Różnice

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

Odnośnik do tego porównania

Both sides previous revision Poprzednia wersja
Nowa wersja
Poprzednia wersja
pl:miw:miw08_ruleruntimeo:mvceditor [2008/05/31 22:12]
miw
pl:miw:miw08_ruleruntimeo:mvceditor [2019/06/27 15:50] (aktualna)
Linia 1: Linia 1:
 ====== Edytor tekstu oparty o MVC ====== ====== Edytor tekstu oparty o MVC ======
  
-==== Cel ====+===== 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. ​ 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 ====+===== Stan wejściowy ​=====
 Wejściowa aplikacja jest prostym edytorem tekstu zawierącym,​ jak widać na poniższym diagramie : 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}} ​ {{:​pl:​miw:​miw08_ruleruntimeo:​figure2.gif|:​pl:​miw:​miw08_ruleruntimeo:​figure2.gif}} ​
  
-**Widok (View)** - a dokładnie dwa widoki :   +==== Widok (View) ​==== 
 + 
 + a dokładnie dwa widoki :   
   - Wyświetlający wprowadzony tekst, klasa DisplayViewPanel   - 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   - 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  :+==== 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   - 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ść   - 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.+==== 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 : 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}} {{:​pl:​miw:​miw08_ruleruntimeo:​figure4.gif|:​pl:​miw:​miw08_ruleruntimeo:​figure4.gif}}
  
-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.+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]]. Dokładny opis oraz źródła wejściowej aplikacji można znaleźć w [[pl:​miw:​miw08_ruleruntimeo#​materialy|Materiałach]].
  
-==== Dokonane modyfikacje ====+ 
 +===== 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]].
  
  
-Widać, że podmiana klas modelu na obiekty Logtalku może się odbyć tylko poprzez modyfikacje Kontrolera (Controller) na taki, który wykorzystując JPL będzie komunikował się z Logtalk'​iem ​ i przekazywał komunikaty do Widoku (View). Zatem klasy modelu napisane w Javie de facto mogą zostać podmienione przez obiekty Logtalk na zasadzie 1:1. 
-Niestety jako, że problematyczne okazało się wywoływanie zdarzeń bezpośrednio z kodu Prologa, konieczne było zastosowanie pewnych obejść żeby zachować istniejącą architekturę aplikacji, ale generlanie rzecz biorąc próba realizacji takiej podmiany udała się. 
  
-==== Docelowe rozwiązanie ==== 
  
pl/miw/miw08_ruleruntimeo/mvceditor.1212264737.txt.gz · ostatnio zmienione: 2019/06/27 15:59 (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