Dependency Injection with Flutter

0

 


What is Dependency Injection?

DI is a format sample in which a category requests dependencies from exterior sources as an alternative than growing them. It ability the established objects are injected or furnished to your class. The type doesn’t have to do any initialization by way of itself. It will get what it desires from the injector. 

Loose coupling: When an object receives the object to be used from exterior sources, we name it unfastened coupling. In different words, the unfastened coupling capability that the objects are independent. 

Tight coupling: When a crew of lessons is exceptionally structured on one another, it is referred to as tight coupling.


Dependency injection is one of the most realistic format patterns that enable builders to write loosely coupled code. It additionally helps to maintain our code greater testable. 


Let us take an example,

When some category Jungle wishes type Animal to function its operation, category Jungle is known as Dependent, and category Animal is known as Dependency. 

class Jungle {

Animal _animal = Animal();

void check() {

  _animal.who();

}

}

class Animal {

void who() {

print("I am animal.");

}

}

void main(){

Jungle _jungle=Jungle();

_jungle.check(); //prints "I am animal".

}

In the above example, our class, Jungle, is tightly coupled. It ability the classification Jungle is particularly based on the dependency Animal.

If we desire to add a new animal Tiger, then there is no way to alternate the animal to Tiger as we have hardcoded Jungle and Animal classes.


Now the usage of dependency injection to clear up our problem. 

void main(){

  final Tiger _tiger=Tiger();

Jungle _jungle=Jungle(_tiger);

_jungle.check(); //prints "I am tiger".

}

class Jungle {

  late Animal _animal;

  Jungle(Animal animal) {

    _animal = animal;

  }

  void check() {

    _animal.who();

  }

}


class Animal {

  void who() {

    print('I am animal.');

  }

}

class Tiger implements Animal {

  @override

  void who() {

    print('I am tiger.');

  }

}


As we can see, we are injecting the dependency from the backyard into the implementation of the class.

Now we can create as many animals as feasible and inject them into the Jungle class.

In this way, our class, Jungle, is loosely coupled.

If we desire to recognize about Lion, create a lion object and inject it into the Jungle class.

Dependency injection is really helpful in Unit Testing due to the fact dependencies are injected outdoors in the class. That’s why our category is no longer any greater structured on different dependencies. And we can effortlessly check our category in isolation. 

Constructor as Dependency Injection:


import 'package:flutter/material.dart';


void main() {
  runApp(MyApp());
}

class MyApp extends StatelessWidget {
  final String helloText='Hello world by passing';
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
    
      debugShowCheckedModeBanner: false,
      home: Scaffold(
        body: Center(
          child: Page1(helloText),
        ),
      ),
    );
  }
}

class Page1 extends StatelessWidget {
  final String helloText;
const Page1(this.helloText);
  @override
  Widget build(BuildContext context) {
    return Page2(helloText);
  }
}
class Page2 extends StatelessWidget {
  final String helloText;
const Page2(this.helloText);
  @override
  Widget build(BuildContext context) {
    return Page3(helloText);
  }
}
class Page3 extends StatelessWidget {
  final String helloText;
const Page3(this.helloText);
  @override
  Widget build(BuildContext context) {
    return Page4(helloText);
  }
}
class Page4 extends StatelessWidget {
  final String helloText;
const Page4(this.helloText);
  @override
  Widget build(BuildContext context) {
    return Text(
     helloText,
      style: Theme.of(context).textTheme.headline4,
    );
  }
}


Here when Page4 wishes helloText, we are passing it thru the constructor down to Page4.

It is now not properly exercised as even if Page2 and Page3 don’t require the text, they nevertheless have to declare and bypass the value. And this is now not efficient. 

Inherited Widget as Dependency Injection:

What is an Inherited Widget?

In flutter, the inherited widget is a base type that lets these lessons lengthen statistics below the tree from it. It works with the aid of informing registered construct references when an exchange occurs. 

import 'package:flutter/material.dart';

class InheritedText extends InheritedWidget{

   final String helloText='Hi from inherited widget';

  final Widget child;

  String get getHelloText=>helloText;

 const  InheritedText({required this.child}):super(child:child);

  static InheritedText? of(BuildContext context){

    return context.dependOnInheritedWidgetOfExactType<InheritedText>();

  }

  @override 

  bool updateShouldNotify(InheritedText old){

    return true;

  }

}


void main() {

  runApp(MyApp());

}


class MyApp extends StatelessWidget {

  @override

  Widget build(BuildContext context) {

   

    return InheritedText(

    child: MaterialApp(

    

      debugShowCheckedModeBanner: false,

      home: Scaffold(

        body: Center(

          child: Page1(),

        ),

      ),

    )

    );

  }

}


class Page1 extends StatelessWidget {

 

  @override

  Widget build(BuildContext context) {

    return Page2();

  }

}

class Page2 extends StatelessWidget {

 

  @override

  Widget build(BuildContext context) {

    return Page3();

  }

}

class Page3 extends StatelessWidget {


  @override

  Widget build(BuildContext context) {

    return Page4();

  }

}

class Page4 extends StatelessWidget {

 

  @override

  Widget build(BuildContext context) {

    final helloText= InheritedText.of(context)!.getHelloText;

    return Text(

     helloText,

      style: Theme.of(context).textTheme.headline4,

    );

  }

}


Now, Inherited Widget helps us get admission to any objects, methods, variables, etc., described in the Inherited Widget in the widget tree.


But there nevertheless is a problem, Inherited Widget desires context to get entry to the object. We can’t inject this dependency interior the category which doesn’t have context.


So that’s a trouble now. What if we favor to get admission to dependencies interior the training like DB, Client, etc? There we may not have context, due to the fact they're simply easy everyday classes.


To overcome the hassle of the Inherited widget, there is get_it package. 

https://pub.dev/packages/get_it

Service Locator as a Dependency Injection:


Get it is a Service Locator, which motive is to return the carrier situations on demand.

The Service Locator sample is a way to decouple the interface (abstract base class) from a concrete implementation and at an equal time lets in having access to the concrete implementation from in all places in your App over the interface. 

Now, using get_it as a Service Locator;

// add get_it: any in your pubspec.yaml file
import 'package:get_it/get_it.dart'
final locator= GetIt.instance;
void setupLocator(){
getIt.registerSingleton<Jungle>(Jungle(Lion()));
}
void main(){
setupLocator();
runApp(MyApp());
}
// And use it in Page4 

class Page4 extends StatelessWidget {
 final jungle=locator.<Jungle>();
  @override
  Widget build(BuildContext context) {
   
    return ElevatedButton(
    onPressed:(){
    jungle.check();
    },
    child:Text('Press me'),
    );
  }
}


We don’t want context or ignore the values thru the constructors. 







Post a Comment

0Comments
* Please Don't Spam Here. All the Comments are Reviewed by Admin.
Post a Comment (0)

#buttons=(Accept !) #days=(20)

Our website uses cookies to enhance your experience. Learn More
Accept !