Click here to load reader
View
76
Download
0
Embed Size (px)
(With Dagger2)
Dependency Injection
Hi There!
Software Developer for three years Medical Research
eCommerce
Android Developer at heart and profession
Software Developer at Gett
Game Plan*
Whats in it for me?
Dependency Injection Principles
Dagger2
*To the best of our ability :)
Whats in it for me?
Testable Code
If I were to plug this code somewhere else, is it guaranteed to work the same
way?
Maintainable Code
How many what the.. moments am I having while reading this code?
Testable And Maintainable Code?
public class SomeClass {
private SomeOtherClass someOtherClass;
public SomeClass() {
someOtherClass = new SomeOtherClass;
}
}
Testable And Maintainable Code!
public class Customer {
private Breakfast breakfast;
public Customer(Breakfast breakfast) {
this.breakfast = breakfast;
}
}
Game Plan
Whats in it for me?
Dependency Injection Principles
Dagger2
Breakfast!
Breakfast!
Breakfast
Coffee OmeletteBreadJuice Salad
Water SugarMilk VeggiesSaltEggs Olive OilFruit
What is a Dependency?
A state in which an object uses a function of another object
Class A is dependent on class B if and only if A needs B in order to function
Defined by import statements
So how do we use dependencies?
So how do we use dependencies?
new statements
this.breakfast = new Breakfast();
Singleton objects
this.breakfast = Breakfast.getInstance();
Through constructors and methods
this.breakfast = breakfastParameter;
Inversion Of Control
What is Dependency Injection?
A technique whereby one object supplies the dependencies of
another object (wikipedia)
A technique whereby one object supplies the dependencies of
another object (wikipedia)
There are many ways to do it
We just saw four ways!
DI acronym
Ready for some extremely difficult code?
Extremely difficult code ahead!
// Constructor
public Customer(Breakfast breakfast) {
// Save the reference to the dependency as passed in by the creator
this.mBreakfast = breakfast;
}
// Setter Method
public void setBreakfast(Breakfast breakfast) {
// Save the reference to the dependency as passed in by the creator
this.mBreakfast = breakfast;
}
Okay great, can we go now?
Just one questionHow should we create our Breakfast object?
How do we create a breakfast object?
// .. Some code above
Breakfast breakfast = new Breakfast(
new Coffee(
// Dependencies go here..
), new Juice(
// Dependencies go here..
// Some more initializations
);
// Give the client their breakfast
How do we create a breakfast object?
// .. Some code above
Breakfast breakfast = new Breakfast(
new BlackCoffee(Coffee(
// Dependencies go here..
), new Juice(
// Dependencies go here..
// Some more initializations
);
// Give the client their breakfast
How do we create a breakfast object?
// .. Some code above
Breakfast breakfast = new Breakfast(
new BlackCoffee(Coffee(
new Sugarless,
new Skimlesss(new Milk()
// Dependencies go here..
), new Juice(
// Dependencies go here..
// Some more initializations
);
// Give the client their breakfast
Some questions to consider
What if Breakfast is a supertype of other breakfast types?
Factories could work
What if Breakfast is a singleton in the system?
Sure, but singletons are difficult to test
Can we share breakfast instances with different clients?
Kind of, but its difficult to maintain
Dependency Injection - A Technique
A technique whereby one object supplies the dependencies of
another object (wikipedia)
Just like breakfast, I could do it myself
But sometimes I want a restaurant to do it for me
Because Im lazy
Because they make it better
[Insert whatever reason you want here]
Inversion of control
Examples
Game Plan*
Purpose
Dependency Injection Principles
Dagger2
*To the best of our ability :)
Why Dagger2?
Designed for low-end devices
Generates new code in your application
No Reflection
How Do Restaurants Work?
How Does Dagger2 Work?
Modules Component Clients
Module - The Supplier
Goal
Provides dependencies
Providing your dependencies context
Modules At A High Level
A supplier supplies materials
It declares what it supplies as a contract
The restaurant can only get what the supplier supplies
May depend on material it can supply
May depend on material it cannot supply
BreakfastSupplierModule example
@Module
public class BreakfastSupplierModule {
@Provides
Omelette provideOmelette(Eggs eggs) { // The eggs will be supplied from the method below
return new ScrambledOmelette();
}
@Provides
Coffee provideCoffee() { // Method name does not matter
return new BlackCoffee();
}
@Provides
Eggs provideEggs() {
return new Eggs();
}
}
Modules - Some FAQ
Unless stated otherwise
The module recreates each object it provides
Read on @Singleton for single-instance
May depend on other modules dependencies
May depend on its own dependencies
Components - The Restaurants
Goal
Bridges between the suppliers and the customers
Handles the final touches of the basic materials
Components At a High Level
Gathers all of the ingredients from all its suppliers
Serves a defined set of customers
RestaurantComponent example
@Component(modules = {BreakfastSupplierModule.class})
public interface RestaurantComponent {
// injection methods
void inject(Customer aCustomer);
}
Client Classes
Use the @Inject annotation to get what they need
Are supplied through the component
@Inject example
public class Customer {
@Inject Omelette omelette;
@Inject Coffee coffee;
// More code goes here...
}
And Now we Build
Component Usage
The customer depends on the component
The customer asks the component to serve itself
Component Usage - One way
@Inject Omellete omelette;
@Inject Coffee coffee;
public Customer()
DaggerRestaurantComponent.builder()
.build().breakfastSupplierModule(new BreakfastSupplierModule)
.inject(this);
}
Component Usage - Better way
@Inject Omellete omelette;
@Inject Coffee coffee;
public Customer(BreakfastSupplierModule breakfastModule) {
DaggerRestaurantComponent.builder()
.build().breakfastSupplierModule(breakfastModule)
.inject(this);
}
Component Usage - Dagger Master Way
@Inject Omellete omelette;
@Inject Coffee coffee;
public Customer(RestaurantComponent restaurantComponent) {
restaurantComponent.inject(this);
}
Best Practices
Dos and Donts
Dont @Inject constructorYou dont know where youll find yourself
Seriously Just dont use @Inject constructor...
Law of DemeterDont talk to strangers
Dont!
public class MenuManager {
private SharedPreferences sharedPreferences;
public MenuManager(Context context) {
this.sharedPreferences = context.getSharedPreferences(PREFERENCES_NAME,
Context.MODE_PRIVATE);
}
}
Do!
public class MenuManager {
private SharedPreferences sharedPreferences;
public MenuManager(SharedPreferences sharedPreferences) {
this.sharedPreferences = sharedPreferences;
}
}
Verdict
Testing is difficult
Context can do too much for its own good
I can just pass the SharedPreferences, right?
The client should just reflect its API through its dependencies
Constructor InjectionMy dependencies are created before me, and my creation can still be controlled
Dont!
public class Customer {
// Another Way simply initialize
public Customer() {
this.breakfast = new Breakfast();
}
}
Dont!
public class Customer {
// One Way - Inject through component
@Inject Breakfast breakfast;
}
Do!
public class Customer {
private Breakfast breakfast;
public SomeClient(Breakfast breakfast) {
mSomeService = someService;
}
}
Verdict
Difficult to test
Client does not reflect its API
What if Breakfast has dependencies?
If we can create the object on our own, well just pass the dependencies through the
Constructor
Setter Method InjectionMy dependencies are created after me, but my creation can still be controlled
Dont!
public class MenuView extends LinearLayout {
// Another Way
public Breakfast() {
breakfast = new Breakfast()
}
}
Dont!
public class MenuView extends LinearLayout {
// One Way