Presentation is loading. Please wait.

Presentation is loading. Please wait.

Dependency Injection Technion – Institute of Technology 236700 1 Author: Gal Lalouche - Technion 2015 ©

Similar presentations


Presentation on theme: "Dependency Injection Technion – Institute of Technology 236700 1 Author: Gal Lalouche - Technion 2015 ©"— Presentation transcript:

1 Dependency Injection Technion – Institute of Technology 236700 1 Author: Gal Lalouche - Technion 2015 ©

2 Class decoupling Consider the following interface: Highly coupled implementation: public interface CreditCardProcessor { void process(PizzaOrder order, CreditCard cc); } class BillingService { private CreditCardProcessor p = new VisaProcessor(); public void chargeOrder(PizzaOrder o, CreditCard cc) { p.process(o, cc); … } 2 Author: Gal Lalouche - Technion 2015 ©

3 Class decoupling (cont.) What’s the problem? new always applies dependency/coupling! Although we use interfaces, the implementation is highly coupled with VisaProcessor It is much harder to test using real dependencies VisaProcessor can be a very slow class It can have unwanted side effects (do we want to be billed for every test?) How can we replace it with mocks? Solution Pass collaborators (dependencies) to the object This is called Dependency Injection 3 Author: Gal Lalouche - Technion 2015 ©

4 Dependency Injection The current supplier can behave differently based on the client configuration Can replace VisaProcessor with PaypalProcessor with little fuss Can inject MockProcessor for testing Dependency objects can be reused elsewhere The default behavior can still exist if we desire it Implementation of default behavior depends on the type of injection used 4 Author: Gal Lalouche - Technion 2015 ©

5 Setters? We can use setters to set the value after object creation We can implement default behavior by calling the setters in the default constructor Is this a good solution? Author: Gal Lalouche - Technion 2015 © 5 public class BillingService { private CreditCardProcessor processor; public void setCreditCardProcessor(CreditCardProcessor p) { processor = p; } public class BillingService { public BillingService { setCreditCardProcessor(new VisaProcessor()) }

6 Setters – problems There’s a window in which an object has been created and is not yet ready for use What happens if we forget to call a setter? Members cannot be final loss of write-safety; what happens if we call set more than once? class becomes mutable, which is something we should always strive to avoid Client is more verbose What happens if we need several setters? Small improvement over setters: use a Fluent API Author: Gal Lalouche - Technion 2015 © 6 public class C { public C setX(X x) { this.x = x; return this; } C c = new C().setX(x).setY(y) …

7 Constructors We can pass the object at the construction of the object Dependencies are injected upon object instantiation Object is always in a correct state Class can be immutable We can implement default behavior using a default constructor We can use constructor injection to provide a default constructor in an inheriting class We saw this when we discussed about using OOP in tests: we injected the actual object under test to the parent constructor Author: Gal Lalouche - Technion 2015 © 7 public class BillingService { private final CreditCardProcessor processor; public BillingService(CreditCardProcessor p) { processor = p; }

8 Builder Objects Combine constructors with setters using the Builder Object Object is always in a valid state Can add validation logic to build() method Class can be immutable Takes quite a bit more code to get running, but is more readble Author: Gal Lalouche - Technion 2015 © 8 public class CBuilder { public CBuilder setX(X x) { this.x = x; return this; } … public C build() { … } } C c = new CBuilder().setX(x).setY(y).build();

9 Factory Method pattern What if we actually want to create more than one object in our class? We could use a createProcessor() method that will be in charge of creating & configuring our Processor This method is called a factory method This method can be overridden to produce a different concrete implementation Author: Gal Lalouche - Technion 2015 © 9

10 Factory Method (cont.) To change the dependencies, simply override the method We can implement default behavior by providing a default method implementation Author: Gal Lalouche - Technion 2015 © 10 public class BillingService { private final CreditCardProcessor processor; protected CreditCardProcessor createProcessor(); } class VisaBillingService extends BillingService { @Override protected CreditCardProcessor createProcessor() { return new VisaProcessor(); }

11 Factory Method – Problems Testing is more verbose than using constructors Have to override the factory method Using the same dependencies in different places is difficult What if we want to use VisaProcessor in all of our objects? We may be forced to create many classes, causing visual clutter What do we do when we have two or more dependencies? Author: Gal Lalouche - Technion 2015 © 11

12 Abstract Factory We would like to separate between an object’s creation and its configuration The point (in the program) of configuration is often different than that of instantiation We will favor composition over inheritance We will delegate the job of object creation to factory objects Author: Gal Lalouche - Technion 2015 © 12

13 Abstract Factory Pattern 13 Processor process(PizzaOrder, CreditCard) ProcessorFactory create(): CreditCardProcessor VisaProcessorFactory create(): CreditCardProcessor VisaProcessor process(PizzaOrder, CreditCard) > Author: Gal Lalouche - Technion 2015 © > implements

14 Abstract Factory – Participants To change the dependencies, simply send a new factory: Author: Gal Lalouche - Technion 2015 © 14 public class VisaProcessorFactory implements ProcessorFactory { public VisaProcessor create() { return new VisaProcessor(); } public class PayPalProcessorFactory implements ProcessorFactory { public PayPalProcessor create() { return new PayPalProcessor(); } public class MockProcessorFactory implements ProcessorFactory { public MockProcessor create() { return new MockProcessor(); }

15 Abstract Factory – Client Client: Author: Gal Lalouche - Technion 2015 © 15 class BillingService { private final ProcessorFactory pf; public BillingService(ProcessorFactory pf) { this.pf = pf; } public void chargeOrder(PizzaOrder o, CreditCard cc) { Processor p = pf.create(); p.process(o, cc); … }

16 Abstract Factory vs. Factory Method – Names are important! Factory Method Creational logic is handled with methods and inheritance Modifications is handled via overriding the factory method Use when you want to couple the creational and business logic Abstract Factory Creational logic is delegated to an external object So more objects are created/passed around But factories can be reused Use when you want to decouple the creational and business logic Author: Gal Lalouche - Technion 2015 © 16

17 Don’t over-design A little coupling is okay You should use injection for service objects, and new for data objects generally speaking, it’s okay to use new ArrayList<>() If we replaced every field with a factory our code would blow up Know when to use constructor dependency injection, and when you need a factory Remember, the creational logic needs to be decided somewhere Be careful of creating FactoryFactory ! Author: Gal Lalouche - Technion 2015 © 17


Download ppt "Dependency Injection Technion – Institute of Technology 236700 1 Author: Gal Lalouche - Technion 2015 ©"

Similar presentations


Ads by Google