public class PersonService {public void addManager( Person employee, Person newManager ) { ... }public void removeManager( Person employee, Person oldManager ) { ... }public Group getGroupByManager( Person manager ) { ... }}
public class GroupMembershipService() {public void addPersonToGroup( Person person, Group group ) { ... }public void removePersonFromGroup( Person person, Group group ) { ... }}
class Car{private Wheel wh; // Inject an Instance of Wheel (dependency of car) at runtimeprivate Battery bt; // Inject an Instance of Battery (dependency of car) at runtimeCar(Wheel wh,Battery bt) {this.wh = wh;this.bt = bt;}//Or we can have settersvoid setWheel(Wheel wh) {this.wh = wh;}}
其优点是:
解耦对象的创建(换句话说,从对象的创建中分离使用)
能够替换依赖项(例如:Wheel,Battery)而无需更改使用它的类(Car)
提倡“代码到接口而不是实现”原则
能够在测试期间创建和使用模拟依赖(如果我们想在测试期间使用Mock of Wheel而不是真实实例…我们可以创建Mock Wheel对象并让DI框架注入Car)
public class Example {private DatabaseThingie myDatabase;
public Example() {myDatabase = new DatabaseThingie();}
public void doStuff() {...myDatabase.getData();...}}
具有依赖注入的构造函数:
public class Example {private DatabaseThingie myDatabase;
public Example(DatabaseThingie useThisDatabaseInstead) {myDatabase = useThisDatabaseInstead;}
public void doStuff() {...myDatabase.getData();...}}
public class Person {public Person() {}
public IDAO Address {set { addressdao = value; }get {if (addressdao == null)throw new MemberAccessException("addressdao" +" has not been initialized");return addressdao;}}
public Address GetAddress() {// ... code that uses the addressdao object// to fetch address details from the datasource ...}
// Should not be called directly;// use the public property insteadprivate IDAO addressdao;
public class MyDao {
protected DataSource dataSource = new DataSourceImpl("driver", "url", "user", "password");
//data access methods...public Person readPerson(int primaryKey) {...}}
依赖关系:
public class MyDao {
protected DataSource dataSource = null;
public MyDao(String driver, String url, String user, String password) {this.dataSource = new DataSourceImpl(driver, url, user, password);}
//data access methods...public Person readPerson(int primaryKey) {...}}
public class MyLogger : ILogger // Others will depend on our logger.{private readonly TextWriter _output;private readonly IClock _clock;
// Dependencies are injected through the constructorpublic MyLogger(TextWriter stream, IClock clock){_output = stream;_clock = clock;}
public void LogRecord(string somethingToLog){// We can now use our dependencies through the abstraction// and without knowledge of the lifespans of the dependencies_output.Write("{0:yyyy-MM-dd HH:mm:ss} - {1}", _clock.Now, somethingToLog);}}
package com.deepam.hidden;
public interface BookInterface {
public BookInterface setHeight(int height);public BookInterface setPages(int pages);public int getHeight();public int getPages();
public String toString();}
接下来我们可以有很多种书;其中一种类型是小说:
package com.deepam.hidden;
public class FictionBook implements BookInterface {int height = 0; // height in cmint pages = 0; // number of pages
/** constructor */public FictionBook() {// TODO Auto-generated constructor stub}
@Overridepublic FictionBook setHeight(int height) {this.height = height;return this;}
@Overridepublic FictionBook setPages(int pages) {this.pages = pages;return this;}
@Overridepublic int getHeight() {// TODO Auto-generated method stubreturn height;}
@Overridepublic int getPages() {// TODO Auto-generated method stubreturn pages;}
@Overridepublic String toString(){return ("height: " + height + ", " + "pages: " + pages);}}
现在订阅者可以与本书建立关联:
package com.deepam.hidden;
import java.lang.reflect.Constructor;import java.lang.reflect.InvocationTargetException;
public class Subscriber {BookInterface book;
/** constructor*/public Subscriber() {// TODO Auto-generated constructor stub}
// injection Ipublic void setBook(BookInterface book) {this.book = book;}
// injection IIpublic BookInterface setBook(String bookName) {try {Class<?> cl = Class.forName(bookName);Constructor<?> constructor = cl.getConstructor(); // use it for parameters in constructorBookInterface book = (BookInterface) constructor.newInstance();//book = (BookInterface) Class.forName(bookName).newInstance();} catch (InstantiationException e) {e.printStackTrace();} catch (IllegalAccessException e) {e.printStackTrace();} catch (ClassNotFoundException e) {e.printStackTrace();} catch (NoSuchMethodException e) {e.printStackTrace();} catch (SecurityException e) {e.printStackTrace();} catch (IllegalArgumentException e) {e.printStackTrace();} catch (InvocationTargetException e) {e.printStackTrace();}return book;}
public BookInterface getBook() {return book;}
public static void main(String[] args) {
}
}
所有三个类都可以为它自己的实现隐藏。现在我们可以将此代码用于DI:
package com.deepam.implement;
import com.deepam.hidden.Subscriber;import com.deepam.hidden.FictionBook;
public class CallHiddenImplBook {
public CallHiddenImplBook() {// TODO Auto-generated constructor stub}
public void doIt() {Subscriber ab = new Subscriber();
// injection IFictionBook bookI = new FictionBook();bookI.setHeight(30); // cmbookI.setPages(250);ab.setBook(bookI); // injectSystem.out.println("injection I " + ab.getBook().toString());
// injection IIFictionBook bookII = ((FictionBook) ab.setBook("com.deepam.hidden.FictionBook")).setHeight(5).setPages(108); // inject and setSystem.out.println("injection II " + ab.getBook().toString());}
public static void main(String[] args) {CallHiddenImplBook kh = new CallHiddenImplBook();kh.doIt();}}
public class Triangle {
private String type;
public String getType(){return type;}
public Triangle(String type){ //constructor injectionthis.type=type;}}<bean id=triangle" class ="com.test.dependencyInjection.Triangle"><constructor-arg value="20"/></bean>
public class SwitchTest {TestToggleBulb() {MockBulb mockbulb = new MockBulb();
// MockBulb is a subclass of Bulb, so we can// "inject" it here:Switch switch = new Switch(mockBulb);
switch.ToggleBulb();mockBulb.AssertToggleWasCalled();}}
public class Switch {private Bulb myBulb;
public Switch() {myBulb = new Bulb();}
public Switch(Bulb useThisBulbInstead) {myBulb = useThisBulbInstead;}
public void ToggleBulb() {...myBulb.Toggle();...}}`
public class Car{public Car(){GasEngine engine = new GasEngine();engine.Start();}}
public class GasEngine{public void Start(){Console.WriteLine("I use gas as my fuel!");}}
public interface IEngine{void Start();}
public class GasEngine : IEngine{public void Start(){Console.WriteLine("I use gas as my fuel!");}}
public class ElectricityEngine : IEngine{public void Start(){Console.WriteLine("I am electrocar");}}
public class Car{private readonly IEngine _engine;public Car(IEngine engine){_engine = engine;}
public void Run(){_engine.Start();}}
Public MyClass{DependentClass dependentObject/*At somewhere in our code we need to instantiatethe object with new operator inorder to use it or perform some method.*/dependentObject= new DependentClass();dependentObject.someMethod();}
使用依赖注入,依赖注入器将为我们取消实例化
Public MyClass{/* Dependency injector will instantiate object*/DependentClass dependentObject
/*At somewhere in our code we perform some method.The process of instantiation will be handled by the dependency injector*/
dependentObject.someMethod();}
public class Service {public void doSomeThingInService() {// ...}}
没有依赖注入
方式1)
public class Client {public void doSomeThingInClient() {Service service = new Service();service.doSomeThingInService();}}
方式2)
public class Client {Service service = new Service();public void doSomeThingInClient() {service.doSomeThingInService();}}
方式3)
public class Client {Service service;public Client() {service = new Service();}public void doSomeThingInClient() {service.doSomeThingInService();}}
1)2)3)使用
Client client = new Client();client.doSomeThingInService();
优势
简单
缺点
很难测试Client类
当我们更改Service构造函数时,我们需要在所有地方更改代码,创建Service对象
使用依赖注入
方式1)构造函数注入
public class Client {Service service;
Client(Service service) {this.service = service;}
// Example Client has 2 dependency// Client(Service service, IDatabas database) {// this.service = service;// this.database = database;// }
public void doSomeThingInClient() {service.doSomeThingInService();}}
使用
Client client = new Client(new Service());// Client client = new Client(new Service(), new SqliteDatabase());client.doSomeThingInClient();
方式2) Setter注入
public class Client {Service service;
public void setService(Service service) {this.service = service;}
public void doSomeThingInClient() {service.doSomeThingInService();}}
使用
Client client = new Client();client.setService(new Service());client.doSomeThingInClient();
public class Injector {public static Service provideService(){return new Service();}
public static IDatabase provideDatatBase(){return new SqliteDatabase();}public static ObjectA provideObjectA(){return new ObjectA(provideService(...));}}