Intro to Dependency Injection - Or bar

46
Intro To Dependency Injection Or Bar

Transcript of Intro to Dependency Injection - Or bar

Page 1: Intro to Dependency Injection - Or bar

Intro To Dependency Injection

Or Bar

Page 2: Intro to Dependency Injection - Or bar

- What is a Dependency?

- Dependency Injection

- Dependency Inversion Principle

- Dependency Injection Frameworks

Agenda

Page 3: Intro to Dependency Injection - Or bar

A depends on B

Page 4: Intro to Dependency Injection - Or bar

public class Example { DatabaseHelper mDatabaseHelper; public Example() { mDatabaseHelper = new DatabaseHelper(); } public void doStuff() { ... mDatabaseHelper.loadUsers(); ... } }

Page 5: Intro to Dependency Injection - Or bar

- Dependency injection is a software design pattern that implements inversion of control for resolving dependencies

- An injection is the passing of a dependency to a dependent object to use

Page 6: Intro to Dependency Injection - Or bar

public class Example { DatabaseHelper mDatabaseHelper; public Example() { mDatabaseHelper = new DatabaseHelper(); } }

Page 7: Intro to Dependency Injection - Or bar

public class Example { DatabaseHelper mDatabaseHelper; public Example() { mDatabaseHelper = new DatabaseHelper(); } }

public class Example { DatabaseHelper mDatabaseHelper; public Example(DatabaseHelper databaseHelper) { mDatabaseHelper = databaseHelper; }}

Page 8: Intro to Dependency Injection - Or bar

public class Example { DatabaseHelper mDatabaseHelper; public Example() { mDatabaseHelper = new DatabaseHelper(); } }

public class Example { DatabaseHelper mDatabaseHelper;

public Example() { mDatabaseHelper = new DatabaseHelper(); } }

public class Example { DatabaseHelper mDatabaseHelper; public Example(DatabaseHelper databaseHelper) { mDatabaseHelper = databaseHelper; }}

public class Example { DatabaseHelper mDatabaseHelper; public Example(DatabaseHelper databaseHelper) { mDatabaseHelper = databaseHelper; } }

Page 9: Intro to Dependency Injection - Or bar

public class Example { DatabaseHelper mDatabaseHelper; public Example() { } public void setDatabaseHelper(DatabaseHelper databaseHelper) { mDatabaseHelper = databaseHelper; }}

Page 10: Intro to Dependency Injection - Or bar

- Shared dependencies

- Configure dependencies externally

- Separation of modules

- Inherent testability

Why?

Page 11: Intro to Dependency Injection - Or bar

public class ExampleTest { @Mock DatabaseHelper mockDatabaseHelper; @Test public void testExample_doStuff() { Example example = new Example(mockDatabaseHelper); example.doStuff(); mockDatabaseHelper.AssertGetDataWasCalled(); }}

public class Example { DatabaseHelper mDatabaseHelper; public Example(DatabaseHelper databaseHelper) { mDatabaseHelper = databaseHelper; } public void doStuff() { ... mDatabaseHelper.loadUsers(); ... }

}

Page 12: Intro to Dependency Injection - Or bar

- High-level modules should not depend on low-level modules. Both should depend on abstractions.

- Abstractions should not depend on details. Details should depend on abstractions.

Dependency Inversion Principle

Page 13: Intro to Dependency Injection - Or bar

A depends on B

Page 14: Intro to Dependency Injection - Or bar

A is coupled to B

Page 15: Intro to Dependency Injection - Or bar

- Bare bones ebook reader

- Supports PDF files

- Prints book contents to screen

Ebook Reader

Page 16: Intro to Dependency Injection - Or bar

CoolEBookReader

PDFReader DisplayPrinter

Page 17: Intro to Dependency Injection - Or bar

public class CoolEBookReader { public void loadPage(String bookUri, int PageNumber) { String pdfContent = getPdfContent(bookUri, PageNumber); displayPage(pdfContent); } }

Page 18: Intro to Dependency Injection - Or bar

public class CoolEBookReader { enum BookType { PDF, EPUB } public void loadPage(BookType bookType, String bookUri, int PageNumber) { String pageContent; if (bookType == BookType.PDF) { pageContent = getPdfContent(bookUri, PageNumber); } else if (bookType == BookType.EPUB) { pageContent = getEpubContent(bookUri, PageNumber); } else { throw new IllegalArgumentException("Unknown book type"); } displayPage(pageContent); } }

Page 19: Intro to Dependency Injection - Or bar

public class CoolEBookReader { enum BookType { PDF, EPUB } enum PrinterType { SCREEN, VOICE } public void loadPage(BookType bookType, PrinterType printerType, String bookUri, int PageNumber) { String pageContent; if (bookType == BookType.PDF) { pageContent = getPdfContent(bookUri, PageNumber); } else if (bookType == BookType.EPUB) { pageContent = getEpubContent(bookUri, PageNumber); } else { throw new IllegalArgumentException("Unknown book type"); } if (printerType == PrinterType.SCREEN) { displayPage(pageContent); } else if (printerType == PrinterType.VOICE) { readAloudPage(pageContent); } else { throw new IllegalArgumentException("Unknown printer type"); } } }

Page 20: Intro to Dependency Injection - Or bar

- High-level modules should not depend on low-level modules. Both should depend on abstractions.

- Abstractions should not depend on details. Details should depend on abstractions.

Dependency Inversion

Page 21: Intro to Dependency Injection - Or bar

CoolEBookReader

PDFReader DisplayPrinter

<<Interface>> Reader

<<Interface>> Printer

Page 22: Intro to Dependency Injection - Or bar

interface Reader { String read(String bookUri, int pagNumber); } interface Printer { void print(String pageContent);}

public class CoolEBookReader { public void loadPage(Reader reader, Printer printer, String bookUri, int pageNumber) { String pageContent = reader.read(bookUri, pageNumber); printer.print(pageContent); } }

Page 23: Intro to Dependency Injection - Or bar

interface Reader { String read(String bookUri, int pagNumber); } interface Printer { void print(String pageContent);}

public class CoolEBookReader { public void loadPage(Reader reader, Printer printer, String bookUri, int pageNumber) { String pageContent = reader.read(bookUri, pageNumber); printer.print(pageContent); } }

public class CoolEBookReader { public void loadPage(String bookUri, int PageNumber) { String pdfContent = getPdfContent(bookUri, PageNumber); displayPage(pdfContent); } }

Page 24: Intro to Dependency Injection - Or bar

public class CoolEBookReaderTest { @Mock Reader mockReader; @Mock CoolEBookReader.Printer mockPrinter; @Test public void TestExample_loadPage() { CoolEBookReader coolEBookReader = new CoolEBookReader(); coolEBookReader.loadPage(mockReader, mockPrinter, "", 1); // Assert Reader.read() is called // Assert Printer.print() is called } }

Page 25: Intro to Dependency Injection - Or bar

- Dependency Injection

- Dependency Inversion

- Where are these dependencies come from

What’s next?

Page 26: Intro to Dependency Injection - Or bar

- Handles object creation

- Reduces boilerplate code

- A central location for organizing dependencies

- Implement common patterns natively (singleton, lazy loading, etc)

Why use a framework?

Page 27: Intro to Dependency Injection - Or bar

- Dagger 1

- Dagger 2

- Guice and RoboGuice

- PicoContainer

- Spring

- Many, many, many, many more options

Common Frameworks

Page 28: Intro to Dependency Injection - Or bar

History lesson of DI on Android- RoboGuice - 2009

- Spring for Android - 2012

- Dagger 1 - 2013

- Dagger 2 - 2015

- Tiger - 2016

Page 29: Intro to Dependency Injection - Or bar

- @javax.inject.Inject

- @Module

- @Provides

- @Component

Dagger uses annotations

Page 30: Intro to Dependency Injection - Or bar

public class ConnectionHelper { private Context mContext; public ConnectionHelper(Context context) { mContext = context; } public boolean isConnected() { ConnectivityManager connectivityManager = (ConnectivityManager) mContext.getSystemService(Context.CONNECTIVITY_SERVICE); return connectivityManager.getActiveNetworkInfo().isConnected(); } }

ConnectionHelper connectionHelper = new ConnectionHelper(context);boolean isConnected = connectionHelper.isConnected();

Page 31: Intro to Dependency Injection - Or bar

public class ConnectionHelper { private Context mContext; @Inject public ConnectionHelper(Context context) { mContext = context; } public boolean isConnected() { ConnectivityManager connectivityManager = (ConnectivityManager) mContext.getSystemService(Context.CONNECTIVITY_SERVICE); return connectivityManager.getActiveNetworkInfo().isConnected(); }}

@Inject

Page 32: Intro to Dependency Injection - Or bar

@Modulepublic class AppModule { }

@Module

Page 33: Intro to Dependency Injection - Or bar

@Provides@Modulepublic class AppModule { private final Context mContext; public AppModule(Context context) { mContext = context; }

@Provides public Context providesContext() { return mContext; }

@Provides public ConnectionHelper providesConnectionHelper(Context context) { return new ConnectionHelper(context); }}

Page 34: Intro to Dependency Injection - Or bar

@Component(modules = {AppModule.class})public interface AppComponent { void inject(MainActivity activity);}

@Component

Page 35: Intro to Dependency Injection - Or bar

public class App extends Application { private AppComponent component; @Override public void onCreate() { super.onCreate(); AppComponent component = DaggerAppComponent.builder() .appModule(new AppModule(this)) .build(); } public AppComponent getComponent() { return component; }}

public class App extends Application { private AppComponent component; @Override public void onCreate() { super.onCreate(); AppComponent component = DaggerAppComponent.builder() .appModule(new AppModule(this)) .build(); } public AppComponent getComponent() { return component; }}

Page 36: Intro to Dependency Injection - Or bar

public class MainActivity extends AppCompatActivity { @Inject ConnectionHelper mConnectionHelper; @Override protected void onCreate(Bundle savedInstanceState) { ((App) getApplication()).getComponent().inject(this); boolean isConnected = mConnectionHelper.isConnected(); textView.setText(isConnected ? "Connected" : "Not Connected"); }}

public class MainActivity extends AppCompatActivity { @Inject ConnectionHelper mConnectionHelper; @Override protected void onCreate(Bundle savedInstanceState) { ((App) getApplication()).getComponent().inject(this); boolean isConnected = mConnectionHelper.isConnected(); textView.setText(isConnected ? "Connected" : "Not Connected"); }}

@Inject - again

Page 37: Intro to Dependency Injection - Or bar

- More annotations

- Scopes

- Lazy injections

- others

Fun stuff

Page 38: Intro to Dependency Injection - Or bar

@Provides@Singletonpublic Context providesContext() { return context; }

@Singleton

@Singleton@Component(modules = {AppModule.class})public interface AppComponent { void inject(MainActivity activity); }

Page 39: Intro to Dependency Injection - Or bar

@Provides@Reusablepublic ConnectionHelper providesConnectionHelper(Context context) { return new ConnectionHelper(context);}

@Reusable

@Singleton @Reusable@Component(modules = {AppModule.class})public interface AppComponent {}

Page 40: Intro to Dependency Injection - Or bar

@InjectLazy<ConnectionHelper> mConnectionHelper; ... mConnectionHelper.get().isConnected();

Lazy and Provider Injections

@InjectProvider<ConnectionHelper> mConnectionHelper; ... mConnectionHelper.get().isConnected();

Page 41: Intro to Dependency Injection - Or bar

@Target(ANNOTATION_TYPE) @Retention(RUNTIME) @Documentedpublic @interface Qualifier {}

@Qualifier

@Qualifier@Documented@Retention(RUNTIME) public @interface Named {}

Page 42: Intro to Dependency Injection - Or bar

@Provides @Singleton @Named(“Adapter 1”) public RestAdapter providesRestAdapter1() { return …; }

@Qualifier

@Provides @Singleton @Named(“Adapter 2”) public RestAdapter providesRestAdapter2() { return …; }

Page 43: Intro to Dependency Injection - Or bar

@Qualifier@Inject @Named(“Adapter 1”) RestAdapter mRestAdapter;

Page 44: Intro to Dependency Injection - Or bar

Subcomponents and Scopes

- Subcomponents allow you to combine different modules at runtime

- Scopes let you define the lifetime of a dependency

Page 45: Intro to Dependency Injection - Or bar

Testing and dagger

- Constructors used for injections can be used for testing

- Test Modules for espresso

Page 46: Intro to Dependency Injection - Or bar

Questions

- @or_bar

- [email protected]

- orbar1.tumblr.com