I want my project to follow the SOLID principles, and for that I want to know if the coupling that is always seen between the UI and the providers in various tutorials is something that violates the principle of dependency inversion or not.
I remember the definition at the beginning:
A. High level classes should not depend on low level classes. Both should depend on abstractions.
B. Abstractions should not depend on details. The details should depend on the abstractions.
By this I mean this application that you see a lot in tutorials:
class MyProvider extends ChangeNotifier{
//...
}
class UIClass extends StatelessWidget{
@override
Widget build(BuildContext context) {
MyProvider myProvider = Provider.of<MyProvider>(context);
//...
}
}
As can be seen, the UI class directly instantiates the provider class and not an interface, generating coupling between these two classes.
I understand that the "high level class" would be the provider and the "low level class" would be the UI. And that "details" in this case would be the UI class.
Would it be better to use abstractions and pass the provider through the constructor?
Clarification: I'm not asking for personal opinions (otherwise the question would be closed), I'm asking about applying SOLID principles to Flutter.
CodePudding user response:
As you mention before your application should be based on abstraction
instead of real implementations. Your current approach describes how to make it wrong in terms of this principle.
To make it right your UIClass
should depend on the abstraction class
(because dart
doesn't have interfaces
) instead of the real class.
First, create an abstraction
class MyProvider implements ChangeNotifier {
void method();
}
Than implementations
class MyNetworkProvider extends ChangeNotifier implements MyProvider {
@override
void method() {...}
}
class MyDatabaseProvider extends ChangeNotifier implements MyProvider {
@override
void method() {...}
}
Initialise your provider with one of implementation
runApp(ChangeNotifierProvider<MyProvider>(
create: (_) => MyNetworkProvider(),
child: ...
));
And make dependency on the abstraction
class UIClass extends StatelessWidget {
@override
Widget build(BuildContext context) {
MyProvider myProvider = Provider.of<MyProvider>(context);
//...
}
}