Różnice

Różnice między wybraną wersją a wersją aktualną.

Odnośnik do tego porównania

Both sides previous revision Poprzednia wersja
pl:miw:miw08_ruleruntimeo:mvceditor [2008/06/01 00:13]
miw
pl:miw:miw08_ruleruntimeo:mvceditor [2019/06/27 15:50] (aktualna)
Linia 1: Linia 1:
 +====== Edytor tekstu oparty o MVC ======
 +
 +===== Cel =====
 +
 +W ramach realizacji tego przykładu konieczne było takie zmodyfikowanie gotowej aplikacji napisanej w J2SE i będącej bardzo prostą, tutorialową demonstracją wykorzystania modelu MVC, aby zastąpić implementacje Modelu z obiektów Javy na Logtalk oraz aby zmodyfikować w jak najmniejszym stopniu pozostałą część aplikacji. ​
 +
 +===== Stan wejściowy =====
 +Wejściowa aplikacja jest prostym edytorem tekstu zawierącym,​ jak widać na poniższym diagramie :
 +
 +{{:​pl:​miw:​miw08_ruleruntimeo:​figure2.gif|:​pl:​miw:​miw08_ruleruntimeo:​figure2.gif}} ​
 +
 +==== Widok (View) ====
 +
 + a dokładnie dwa widoki :   
 +  - Wyświetlający wprowadzony tekst, klasa DisplayViewPanel
 +  - Umożliwiający wprowadzanie tekstu oraz modyfikowanie jego właściwości takich jak czcionka, rozmiar czcionki, przeźroczystość tekstu, obrót tekstu wokół osi itp, zaimplementowany jako klasa PropertiesViewPanel
 +
 +==== Model ====
 +
 +służy do przechowywania wprowadzonego tekstu oraz wartości tych właściwości. Klasy modelu w projekcie to  :
 +  - TextElementModel - przechowuje stan tekstu wyświetlanego w dokumencie, takie jak wartość tekstu, czcionka itp
 +  - DocumentModel - zawiera stan całego dokumentu tekstowego, czyli nazwę, wysokość, szerokość
 +
 +
 +==== Kontroler (Controller) ====
 + 
 +służy do przekazywania do Modelu odpowiednich zmian właściwości na podstawie komunikatów nadsyłanych z Widoku, czyli generalnie odpowiada za mapowanie zmian dokonanych przez użytkownika na odpowiednie zmiany w Modelu. Kontroler został zaimplementowany w klasie DefaultController.
 +
 +Będąc bardziej szczegółowym projekt ten używa lekko zmodyfikowanej wersji wzorca MVC, w której zmiany stanu Modelu nie są bezpośrednio propagowane do Widoku, ale są przekazywane poprzez Kontroler. Czyli projekt używa poniższej architektury :
 +{{:​pl:​miw:​miw08_ruleruntimeo:​figure4.gif|:​pl:​miw:​miw08_ruleruntimeo:​figure4.gif}}
 +
 +Czyli zmiany wykonane przez użytkownika w jednym z widoków, powodują wywołanie odpowiedniej metody w Kontrolerze. Kontroler ma dostęp do odpowiedniego modelu i jest w stanie odpowiednio zmodyfikować stan Modelu. Model wykrywając zmianę jednej z swoich właściwości,​ wywołuje odpowiednie zdarzenie zmiany stanu. Zdarzenie to jest obsługiwane przez Kontrolera, który w właściwy sposób modyfikuje Widok. Jak widać główną różnicą jest fakt pośredniczenia Kontrolera w każdej komunikacji pomiędzy Widokiem a Modelem co okazało się bardzo korzystne w trakcie przechodzenia na implementacje Modelu w Logtalk'​u.
 +
 +
 +Dokładny opis oraz źródła wejściowej aplikacji można znaleźć w [[pl:​miw:​miw08_ruleruntimeo#​materialy|Materiałach]].
 +
 +
 +===== Dokonane modyfikacje =====
 +Jak widać architektura tego projektu sprzyjała procesowi implementacji części klas w Logtalk'​u ze względu na silne odseparowanie modułów, oraz posługiwanie się referencjami do klas abstrakcyjnych takich jak AbstractController,​ AbstractView czy AbstractModel co bardzo ułatwiało podmianę docelowej implementacji tych obiektów.
 +
 +==== Modyfikacje Widoku ====
 +
 +Klasy Widoku, zgodnie z założeniami,​ nie uległy żadnym modyfikacjom.
 +
 +==== Modyfikacje Modelu ====
 +
 +Klasy Modelu tak naprawdę służą tylko do przechowywania wartości kilku właściwości i cała ich implementacja polega na polach klasy oraz getter'​ach i setter'​ach. Jesteśmy zatem w stanie bez większego problemu wymienić klasy modelu napisane w Javie na obiekty Logtalk, na zasadzie 1:1. Czyli tworzymy:
 +  - **documentModel** w pliku documentModel.lgt
 +  - **textElementModel** w pliku textElementModel.lgt
 +
 +
 +Aby powtórzyć tą samą funkcjonalność w Logtalku wystarczy zatem napisać prostą Kategorie, którą potem zaimportujemy do każdego z obiektów Modelu :
 +
 +<code prolog>
 +
 +:- public(set_property/​2).
 +    :- mode(set_property(+nonvar,​ +nonvar), one).
 +
 +    :- public(get_property/​2).
 +    :- mode(get_property(?​nonvar,​ ?nonvar), zero_or_more).
 +
 +    :- private(property_/​2).
 +    :- mode(property_(?​nonvar,​ ?nonvar), zero_or_more).
 +    :- dynamic(property_/​2).
 +
 +    set_property(Property,​ Value):-
 +        write('​Property test : ' + OldValue),​nl,​
 +        ::​retractall(property_(Property,​ OldValue)),
 +
 +        ::​assertz(property_(Property,​ Value)),
 +        ::​firePropertyChange(Property,​ OldValue, ​ Value).
 +
 +    get_property(Property,​ Value):-
 +        ::​property_(Property,​ Value),
 + write(Value).
 +
 +
 +:- end_category.
 +
 +</​code>​
 +
 +Tak dzięki tym predykatom jesteśmy w stanie dokonywać dynamiczego zapisu wartości odpowiednich właściwości Modelu do Bazy wiedzy Prologa. ​ Kod obiektu documentModel wygląda następująco : 
 +
 +<code prolog>
 +:​-object(documentModel,​ imports(properties)).
 +:​-public(firePropertyChange/​3).
 +
 +firePropertyChange(PropertyName,​ OldValue, NewValue):-
 + write('​Document:​ PropertyName ' + PropertyName),​nl,​
 + write('​Document:​ NewValue ' + NewValue),​nl
 + .
 +:​-end_object.
 +</​code>​
 +
 +Tak naprawdę w tym przypadku kod modelu ograniczy się do importowania tej kategorii, jeden predykat służy tylko do wypisania na konsole zmiany stanu modelu.
 +Niestety jako, że problematyczne okazało się wywoływanie zdarzeń Javowych bezpośrednio z kodu Prologa, niestety wymagałoby to przechowania referencji do Obiektu Kontrolera wewnątrz obiektu Logtalk, co niestety okazało się niemożliwe przy użyciu JPL, który dość dobrze radzi sobie z przechowywaniem referencji do obiektów Javy tworzonych przy użyciu JPL, natomiast niekoniecznie takich istniejących już wcześniej.Konieczne było zastosowanie pewnej modyfikacji działania Kontrolera, ale o tym poniżej.
 +
 +
 +==== Modyfikacje Kontrolera ====
 +
 +Drugą modyfikacją konieczną do implementacji Modelu w Logtalk'​u była implementacja Kontrolera w taki sposób, aby wykorzystując JPL będzie tworzył obiekty Logtalk oraz wywoła na nich metodę zapisującą wartość danej właściwości. Jako, że kłopotliwe okazało się przechowywanie referencji do kontrolera wewnątrz obiektu Logtalk'​a,​ co jest konieczne do ustawienia Listnera, nie można było dokładnie skopiować rozwiązania z wejściowego projektu. Zamiast tego kontroler po ustawieniu danej właściwości,​ sprawdza jej wartość i odpowiednio modyfikuje widok. ​
 +
 +Zatem architektura została zachowana, podmieniono obiekty Modelu na zasadzie 1:1 i jedyne co musiało się zmienić to implementacja Kontrolera, która była o tyle ułatwiona, że w pozostałych modułach używana jest referencja do klasy abstrakcyjnej AbstractController,​ zatem podmiana jej implementacji z DefaultController na LogtalkControler była właściwie bezbolesna. Co do implementacji kontrolera to klasa  LogtalkControler zawiera dwa bardziej interesujące fragmenty :
 +
 +**Konstruktor**:​
 +  * nawiązujemy przez JPL komunikacje z SWIProlog i  konfigurujemy runtime Logtalk'​a,​[[pl:​miw:​miw08_ruleruntimeo:​swiconfig|szczegółowy opis]] ​
 +  * Tworzymy obiekty Modelu w następujący sposób : 
 +<code java>
 +
 +Query loadDocumentModel = new Query("​logtalk_load",​
 + new Term[]{new Atom("​src/​com/​sun/​example/​mvc/​model/​documentModel"​)}
 + );
 +
 + if(loadDocumentModel.hasSolution())
 + {
 + System.out.println("​DocumentModel loaded succesfully"​);​
 + }
 + else
 + {
 + throw new RuntimeException("​Unable to load DocumentModel"​);​
 + }
 +
 +</​code>​
 +
 +**Metoda setModelProperty(String propertyName,​ Object newValue) ** - dokonująca właściwej zmiany w modelu a nastepnie update w Widoku.
 +
 +<code java>
 +
 +
 + Query setLogtalkProperty ​ = null;
 + Query getLogtalkProp = null;
 + if (this.isDocumentModel) {
 + setLogtalkProperty ​
 + //= new Query("​documentModel::​set_property('"​
 ++propertyName + "',​ jpl_new('​java.lang.String',​['" ​
 ++ newValue.toString() + "'​],​ _))."​);​
 + = new Query("​documentModel::​set_property('"​
 ++propertyName + "',​ '"​ + newValue.toString() + "'​)."​);​
 +
 + getLogtalkProp = new Query(
 + "​documentModel::​get_property('"​ + propertyName + "',​ X).");
 + }else {
 + setLogtalkProperty = new Query("​textElementModel::​set_property('"​+propertyName + "',​ '"​ + newValue.toString() + "'​)."​);​
 +
 + getLogtalkProp = new Query(
 + "​textElementModel::​get_property('"​ + propertyName + "',​ X).");
 + }
 +
 +
 + if(setLogtalkProperty.hasSolution())
 + {
 + }
 + else
 + {
 + throw new RuntimeException("​Unable to set property named : " + propertyName );
 + }
 +
 + Variable X = new Variable("​X"​);​
 +
 +
 + if(getLogtalkProp.hasMoreElements())
 + {
 + Object elem = getLogtalkProp.nextElement();​
 + if (elem instanceof Hashtable) {
 + Hashtable<​String,​ Atom> solution = (Hashtable<​String,​ Atom>) elem;
 +
 + System.out.println("​Solution is " + solution.get("​X"​));​
 +
 +
 +
 + Atom atomVal = (Atom)solution.get("​X"​);​
 + String strValue = atomVal.name(); ​
 + Object value = strValue;
 + try {
 + value = java.lang.Integer.valueOf( strValue).intValue();​
 + } catch (Exception e) {
 + // TODO: handle exception
 + }
 +
 + DisplayViewPanel displayView = (DisplayViewPanel) this.registeredViews.get(0);​
 + PropertyChangeEvent event = new PropertyChangeEvent(this,​ propertyName,​ newValue, value);
 + displayView.modelPropertyChange(event);​
 +
 + }
 + }
 +
 +</​code>​
 +
 +
 +Dzięki tym modyfikacją da się zachować pełną funkcjonalność aplikacji, jednocześnie implementując obiekty Modelu w Logtalk'​u. ​
 +
 +Źródła projektu znajdują się w dziale [[pl:​miw:​miw08_ruleruntimeo#​projekt|Projekt]].
 +
 +
 +
  
www.chimeric.de Valid CSS Driven by DokuWiki do yourself a favour and use a real browser - get firefox!! Recent changes RSS feed Valid XHTML 1.0