Skip to content

Commit 505520e

Browse files
committed
mvp, mvvm, mvi updated
1 parent d6d78ca commit 505520e

File tree

4 files changed

+269
-15
lines changed

4 files changed

+269
-15
lines changed

_drafts/2019-08-26-mvi.md

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -22,9 +22,9 @@ Podobnie jak w przypadku innych wzorców architektonicznych zastosowanie `MVI` m
2222
## Implementacja
2323
Realizacja wzorca `MVI` może przypominać tą znaną z `MVP`, różnica polega jednak na implementacji i interakcji komponentów. Na podstawie klasy `Model` będącej kontenerem danych opisujących stan, definiowane są finalne klasy stanów o wspólnym rodzicu `PartialState`. Warstwa widoku `ViewImpl` implementuje interfejs `View` dostarczając zachowania obsługi otrzymanych stanów w metodzie `render` oraz emisji intencji w odpowiedzi na akcje użytkownika. Klasa `Presenter` odpowiada za odbieranie i przetwarzanie intencji z widoku oraz delegowanie ich do logiki biznesowej. W odpowiedzi na otrzymany stan tworzy nowy niezmienny obiekt modelu w metodzie `reduce`, który trafia do widoku.
2424

25-
![MVI diagram](/assets/img/diagrams/patterns/mvvi.svg){: .center-image }
25+
![MVI diagram](/assets/img/diagrams/patterns/mvi.svg){: .center-image }
2626

27-
Poniższy listing przedstawia realizację wzorca `MVI` z pominięciem zależności `Androidowych` oraz zastosowaniem `RxJava` w celu realizacji programowania reaktywnego.
27+
Poniższy listing przedstawia realizację wzorca `MVI` z pominięciem zależności `Android` oraz zastosowaniem `RxJava` w celu realizacji programowania reaktywnego.
2828

2929
{% highlight kotlin %}
3030
//define Model where fields values describe the states of the screen
@@ -57,14 +57,14 @@ interface View {
5757
class ViewImpl : View {
5858

5959
private val presenter = Presenter(Interactor())
60-
61-
public ViewImpl() {
60+
61+
public ViewImpl() {
6262
presenter.bindIntents(this)
63-
63+
6464
//init views
6565

6666
emitActionIntent() //emit action on start
67-
}
67+
}
6868

6969
override fun emitActionIntent() : Observable<Boolean> {
7070
return Observable.just(true)

_posts/design_patterns/2018-10-29-mvp.md

Lines changed: 29 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -180,6 +180,17 @@ public class ViewActivity extends AppCompatActivity implements View {
180180
presenter.initView();
181181
}
182182

183+
@Override
184+
public void setLastLogin(String login) {
185+
loginEdit.setText(login);
186+
}
187+
188+
@Override
189+
public void navigateToHome() {
190+
//go to another activity (like home screen)
191+
//instead of doing logic operations it can be delegate to Router helper class
192+
}
193+
183194
@Override
184195
public void showError() {
185196
Toast.makeText(this, "Incorrect login or password", Toast.LENGTH_LONG).show();
@@ -205,12 +216,6 @@ public class ViewActivity extends AppCompatActivity implements View {
205216
}
206217
}
207218

208-
@Override
209-
public void navigateToHome() {
210-
//go to another activity (like home screen)
211-
//instead of doing logic operations it can be delegate to Router helper class
212-
}
213-
214219
private void loginAction() {
215220
//controller get inputs from view
216221
String login = loginEdit.getText().toString();
@@ -251,6 +256,21 @@ public class PresenterImpl implements Presenter, OnResult {
251256
interactor.getSavedLogin();
252257
}
253258

259+
@Override
260+
public void onLoginSuccess() {
261+
view.navigateToHome();
262+
}
263+
264+
@Override
265+
public void onLoginFail() {
266+
view.showError();
267+
}
268+
269+
@Override
270+
public void onSavedLoginExists(String savedLogin) {
271+
view.setLastLogin(savedLogin);
272+
}
273+
254274
private boolean isLoginValid(String login) {
255275
//check rules e.g. no special characters
256276
return true; //mock
@@ -277,6 +297,7 @@ public class InteractorImpl implements Interactor {
277297
sharedPref = context.getPreferences(Context.MODE_PRIVATE);
278298
}
279299

300+
@Override
280301
public void login(String login, String password) {
281302
//use some network library to login
282303
int code = Response.OK; //mock code response from network
@@ -290,6 +311,7 @@ public class InteractorImpl implements Interactor {
290311
}
291312
}
292313

314+
@Override
293315
public void getSavedLogin() {
294316
String savedLogin = sharedPref.getString("login", "");
295317
if(!savedLogin.equals(""))
@@ -307,6 +329,7 @@ interface Contract {
307329

308330
interface View {
309331

332+
void setLastLogin(String login);
310333
void navigateToHome();
311334
void showError();
312335
void showInvalidLogin(boolean valid);

_posts/design_patterns/2018-11-05-mvvm.md

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ keywords: "mvvm, model, view, viewmodel, wzorzec, wzorce projektowe, wzorzec arc
1111
---
1212

1313
## Zastosowanie
14-
`MVVM` (ang. `Model-View-ViewModel`) (wzorzec architektoniczny) ma za zadanie ułatwić tworzenie ekranów aplikacji poprzez zastosowanie podziału odpowiedzialności na trzy różne warstwy: `widoku` (View), `widoku modelu` (ViewModel) oraz `modelu` (Model). `Warstwa widoku` odpowiedzialna jest za prezentacje danych, stanu systemu i bieżących operacji w interfejsie graficznym, a także za inicjalizację i wiązanie `ViewModel` z elementami widoku. `Warstwa widoku modelu` zajmuje się dostarczaniem danych modelu dla warstwy widoku oraz podejmowaniem akcji na rzecz wywołanego zdarzenia z widoku. Natomiast `warstwa modelu` odpowiada za logikę biznesową, czyli przetwarzanie, przechowywanie, modyfikacje oraz dostarczanie oczekiwanych danych do widoku modelu. Dzięki zastosowaniu strategii `wiązania danych` (data binding) w warstwie widoku minimalizowana jest jego logika, kod staje się bardziej uporządkowany i otwarty na modyfikacje, a przeprowadzenie testów łatwiejsze. Idea wzorca `MVVM` opiera się przede wszystkim na obserwowaniu przez warstwę widoku (`wzorzec Obserwator`) zmieniających się danych w warstwie widoku modelu i reagowanie na zmiany poprzez mechanizm wiązania danych. Ze względu na różnorodność środowisk i technologii realizacja wzorca `MVVM` może zostać uzyskana na wiele sposobów.
14+
`MVVM` (ang. `Model-View-ViewModel`) (wzorzec architektoniczny) ma za zadanie ułatwić tworzenie ekranów aplikacji poprzez zastosowanie podziału odpowiedzialności na trzy różne warstwy: widoku (`View`), widoku modelu (`ViewModel`) oraz modelu (`Model`). `Warstwa widoku` odpowiedzialna jest za prezentacje danych, stanu systemu i bieżących operacji w interfejsie graficznym, a także za inicjalizację i wiązanie `ViewModel` z elementami widoku. `Warstwa widoku modelu` zajmuje się dostarczaniem danych modelu dla warstwy widoku oraz podejmowaniem akcji na rzecz wywołanego zdarzenia z widoku. Natomiast `warstwa modelu` odpowiada za logikę biznesową, czyli przetwarzanie, przechowywanie, modyfikacje oraz dostarczanie oczekiwanych danych do widoku modelu. Dzięki zastosowaniu strategii wiązania danych (`data binding`) w warstwie widoku minimalizowana jest jego logika, kod staje się bardziej uporządkowany i otwarty na modyfikacje, a przeprowadzenie testów łatwiejsze. Idea wzorca `MVVM` opiera się przede wszystkim na obserwowaniu przez warstwę widoku (`wzorzec Obserwator`) zmieniających się danych w warstwie widoku modelu i reagowanie na zmiany poprzez mechanizm wiązania danych. Ze względu na różnorodność środowisk i technologii realizacja wzorca `MVVM` może zostać uzyskana na wiele sposobów.
1515

1616
## Ograniczenia
1717
Każdy ekran widoku posiada dedykowany widok modelu co przekłada się na większą ilość klas (w porównaniu do wzorca `MVP` nadal jest ich mniej). Ponadto warstwa widoku musi zadbać o właściwe wiązanie zmiennych i metod dla każdego wymaganego elementu widoku, a także o obserwowanie stanu widoku modelu. Ze względu na wybór dostępnych technik, bibliotek i komponentów służących realizacji wiązania danych oraz obserwowania ich stanu implementacja wzorca `MVVM` nie należy do łatwych. Co więcej mnogość strategii implementacji `MVVM` sprawia, że dane rozwiązanie może być niezrozumiałe dla innych programistów. Stworzenie poprawnego i kompletnego widoku modelu wymaga przeprowadzenia analizy warstwy widoku pod kątem wymaganych danych i możliwych stanów. Zawarty kod logiki kontrolek widoku w plikach `layout` może być nieczytelny i trudny do testowania, dlatego warto rozważyc umieszczanie pewnych fragmentów logiki w klasie widoku.
@@ -24,7 +24,7 @@ Warstwa widoku `View` tworzy instancje widoku modelu `ViewModel` oraz wiąże go
2424

2525
![MVVM diagram](/assets/img/diagrams/patterns/mvvm.svg){: .center-image }
2626

27-
Poniższy listing przedstawia realizację wzorca `MVVM` z pominięciem zależności `Androidowych` oraz implementacji wzorca `Obserwator`.
27+
Poniższy listing przedstawia realizację wzorca `MVVM` z pominięciem zależności `Android` oraz implementacji wzorca `Obserwator`.
2828

2929
{% highlight java %}
3030
public class View {
@@ -127,7 +127,7 @@ public class Model {
127127
}
128128
{% endhighlight %}
129129

130-
Implementacja wzorca `MVVM` może zostać zrealizowana na wiele różnych sposobów i wariantów. Warstwa widoku `View` może wykorzystywać mechanizm `data binding` w plikach `layout` lub w kodzie klasy widoku. Jest również możliwe uzyskanie implementacji wzorca bez użycia wiązania danych, a wszelkie zmiany odnotowane są poprzez śledzenie zmian w `ViewModel` z wykorzystaniem wzorca `Obserwator`. Istnieje także wiele podejść do informowania warstwy widoku o wystąpieniu błędu lub postępu operacji. Jedną ze strategii jest traktowanie takich zdarzeń jako pola w klasie widoku modelu i nasłuchiwanie przez widok zmiany stanu i podejmowaniu właściwej akcji. Komunikacja między warstwą modelu `Model`, a widoku modelu `ViewModel` może przebiegać przy wykorzystaniu natywnych rozwiązań, funkcji zwrotu (`callback`), mechanizmu `Interactor` (znanego z `MVP`), szyny zdarzeń (`event bus`), wzorca `Obserwator` czy też użycia biblioteki do programowania reaktywnego jak np. `RxJava`. Niezależnie od wyboru strategii implementacji należy przede wszystkim pamiętać, aby widok modelu nie posiadał `zależności Androidowych` oraz `referencji do Aktywności`, a warstwa widoku obserwowała stan `ViewModel`.
130+
Implementacja wzorca `MVVM` może zostać zrealizowana na wiele różnych sposobów i wariantów. Warstwa widoku `View` może wykorzystywać mechanizm `data binding` w plikach `layout` lub w kodzie klasy widoku. Jest również możliwe uzyskanie implementacji wzorca bez użycia wiązania danych, a wszelkie zmiany odnotowane są poprzez śledzenie zmian w `ViewModel` z wykorzystaniem wzorca `Obserwator`. Istnieje także wiele podejść do informowania warstwy widoku o wystąpieniu błędu lub postępu operacji. Jedną ze strategii jest traktowanie takich zdarzeń jako pola w klasie widoku modelu i nasłuchiwanie przez widok zmiany stanu i podejmowaniu właściwej akcji. Komunikacja między warstwą modelu `Model`, a widoku modelu `ViewModel` może przebiegać przy wykorzystaniu natywnych rozwiązań, funkcji zwrotu (`callback`), mechanizmu `Interactor` (znanego z `MVP`), szyny zdarzeń (`event bus`), wzorca `Obserwator` czy też użycia biblioteki do programowania reaktywnego jak np. `RxJava`. Niezależnie od wyboru strategii implementacji należy przede wszystkim pamiętać, aby widok modelu nie posiadał zależności `Android` oraz referencji do `Aktywności`, a warstwa widoku obserwowała stan `ViewModel`.
131131

132132
## Przykład
133133
Aplikacja Scorer ułatwia rejestrowanie i śledzenie zdarzeń z rozgrywek meczu piłkarskiego (zdobyte bramki, żółte i czerwone kartki, kontuzje itp). Obsługujący ją sędzia techniczny wybiera typ wydarzenia oraz wskazuje zawodnika. Dodane wydarzenie automatycznie pojawia się w interfejsie graficznym. Do realizacji tego zadania wykorzystano wzorzec `MVVM` w wariancie z użyciem komponentów architektury `Android`.

0 commit comments

Comments
 (0)