Skip to content

Commit

Permalink
polish Use case. Conclusions
Browse files Browse the repository at this point in the history
  • Loading branch information
NickZt committed Nov 26, 2021
1 parent 4fc20f5 commit 2613455
Show file tree
Hide file tree
Showing 4 changed files with 69 additions and 29 deletions.
31 changes: 10 additions & 21 deletions .story.md
@@ -1,30 +1,19 @@
---
focus: lib/presentation/manager/bindings/counter_view_binding.dart:17
focus: lib/presentation/manager/counter_view_model.dart:16
---

### MVI & Clean Code: Rendering Logic of State in Flutter : Riverpod story : The ViewModel has arisen
### MVI & Clean Code: Rendering Logic of State in Flutter : Riverpod story : Polishing to Shine with Clean Code and Conclusions

"our providers become bloated god classes with state and business logic thrown all over the place."
Somewhere in Reddit

#### The problem and why we complicate things.
#### Polishing to Shine with Clean Code.

We need to understand that the provider is a very simple and easy to explain state management tool,
especially for newbies, but I just don't understand how using such singletons in application development can lead to a clean architecture.
Not to mention not being able to use any of the methods in my providers without jumping through hoops.
It makes no sense for me to build clean architecture or die trying. If you have one provider per page (or area) like [ViewModel](lib/presentation/manager/counter_view_model.dart:9),
then it can't really become a big god class. It should only contain the models of this page and some methods.
This way, you can easily call [notifyListerns](lib/presentation/manager/counter_view_model.dart:47), whenever you do something with your models, instead of calling it from inside the model.
In addition to this, you can have service classes that have nothing to do with the provider and only contain logic.

But there is no limit to perfection. To be just like adults, and there was less to explain in the third part, we will transfer the data
(counters) to where they should be - to the data sources ([Data source](lib/presentation/manager/counter_view_model.dart:16)
in the corresponding [Repository](lib/data/repository/Repository.dart:4) and, accordingly, access to them will be through the corresponding
[Use Case](lib/domain/usecase/UseCase.dart:3) interface

Dig deeply into [ViewModel](lib/presentation/manager/counter_view_model.dart:9)
##### Conclusions

In all places of the widget, we call methods from [ViewModel](lib/presentation/manager/counter_view_model.dart:40) e.g. this one is called when the big fab button [is pressed](lib/presentation/pages/home_page.dart:20)
In subwidgets we call direcly counters [EvenCounter](lib/presentation/widgets/counter_widget.dart:23) and [Counter](lib/presentation/pages/home_page.dart:36) in Even State and in Odd state [Counter](lib/presentation/pages/home_page.dart:53)

And yes, you can see that the order of the widgets changes when the state changes.
At the same time, so as not to kill the clock , we added the [logic for switching states](lib/presentation/manager/counter_view_model.dart:45) to our view model.


And after all this code looks simple and easy to understand
I will not repeat the sugar pouring of Clean Architecture, MVI and MVVM.
All together, in my experience, this helps to build systems that are not ashamed to look at after six months, and in the git blame there is no desire to say, "Its not me" )
33 changes: 33 additions & 0 deletions lib/data/repository/Repository.dart
@@ -0,0 +1,33 @@
import 'package:h1_flutter_riverpod/data/models/counter_model.dart';
import 'package:h1_flutter_riverpod/domain/usecase/UseCase.dart';

class Repository implements UseCase {
CounterModel _counter = CounterModel(0);
CounterModel _evenCounter = CounterModel(0);

void iniLoad() {}

void incrementEvenCounter() {
_evenCounter = CounterModel(_evenCounter.count + 1);
}

@override
bool isEven() {
return (_counter.count % 2 == 0);
}

@override
CounterModel getCounter() {
return _counter;
}

@override
void increment() {
_counter = CounterModel(_counter.count + 1);
}

@override
CounterModel getEvenCounter() {
return _evenCounter;
}
}
15 changes: 15 additions & 0 deletions lib/domain/usecase/UseCase.dart
@@ -0,0 +1,15 @@
import 'package:h1_flutter_riverpod/data/models/counter_model.dart';

abstract class UseCase {
void iniLoad();

void incrementEvenCounter();

bool isEven();

CounterModel getCounter();

CounterModel getEvenCounter();

void increment();
}
19 changes: 11 additions & 8 deletions lib/presentation/manager/counter_view_model.dart
@@ -1,24 +1,28 @@
import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:h1_flutter_riverpod/data/models/counter_model.dart';
import 'package:h1_flutter_riverpod/data/repository/Repository.dart';
import 'package:h1_flutter_riverpod/domain/usecase/UseCase.dart';

import 'model/view_state.dart';

final viewModelProvider = ChangeNotifierProvider((ref) => ViewModel());

class ViewModel extends ChangeNotifier {
ViewModel();
ViewModel() {
_useCase.iniLoad();
}

CounterModel _counter = CounterModel(0);
final UseCase _useCase = Repository();

CounterModel get counter => _counter;
CounterModel get counter => _useCase.getCounter();

void increment() {
_counter = CounterModel(_counter.count + 1);
_useCase.increment();
}

bool isEven() {
return (_counter.count % 2 == 0);
return _useCase.isEven();
}

ViewState _state = ViewState.odd();
Expand All @@ -32,12 +36,11 @@ class ViewModel extends ChangeNotifier {

void setState(ViewState viewsState) => _state = viewsState;

CounterModel _evenCounter = CounterModel(0);

CounterModel get evenCounter => _evenCounter;
CounterModel get evenCounter => _useCase.getEvenCounter();

void incrementEvenCounter() {
_evenCounter = CounterModel(_evenCounter.count + 1);
_useCase.incrementEvenCounter();
}

void onFabPressed() {
Expand Down

0 comments on commit 2613455

Please sign in to comment.