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/05/31 23:25]
miw
pl:miw:miw08_ruleruntimeo:mvceditor [2008/06/01 00:13]
miw
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. 
- 
-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. 
- 
-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]]. 
- 
- 
- 
  
pl/miw/miw08_ruleruntimeo/mvceditor.txt · ostatnio zmienione: 2019/06/27 15:50 (edycja zewnętrzna)
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