Both sides previous revision
Poprzednia wersja
Nowa wersja
|
Poprzednia wersja
|
pl:miw:miw08_ruleruntimeo:mvceditor [2008/05/31 22:35] miw |
pl:miw:miw08_ruleruntimeo:mvceditor [2019/06/27 15:50] (aktualna) |
====== 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 : |
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. | 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: | 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: |
| |
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. | 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. | 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. |
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ę. | |
| |
| ==== 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. | |
| |
| |
==== Docelowe rozwiązanie ==== | |
| |