什么是依赖注入?
依赖注入(Dependency Injection)是一种通过外部引入的方式来完成对象依赖性的处理的技术。它用于解决对象之间相互依赖的问题,按照依赖倒置原则,依赖应该从高层次的管理对象向低层次的被管理对象传递,而不应该反过来。依赖注入可以让开发者更加专注于业务实现,降低了组件之间的耦合度,提高代码的可测试性和可维护性。
依赖注入的实现方式
依赖注入有以下三种实现方式:
- 构造函数注入(Constructor Injection)
- 通过将依赖项作为构造函数的参数传递来注入依赖项。
class Car {
private IEngine _engine;
public Car(IEngine engine)
{
this._engine = engine;
}
public void Run()
{
_engine.Start();
}
}
class GasolineEngine implements IEngine {
public void Start()
{
System.out.println("Gasoline Engine start.");
}
}
IEngine engine = new GasolineEngine();
Car car = new Car(engine);
car.Run(); // Output: Gasoline Engine start.
- 属性注入(Property Injection)
- 通过在组件中定义一个可写的属性,然后再将依赖项设置到该属性中来注入依赖项。
class Car {
private IEngine _engine;
public IEngine Engine {
set {
this._engine = value;
}
}
public void Run()
{
_engine.Start();
}
}
IEngine engine = new GasolineEngine();
Car car = new Car();
car.Engine = engine;
car.Run(); // Output: Gasoline Engine start.
- 方法注入(Method Injection)
- 通过在类中定义一个方法,然后该方法接受依赖项作为形参来注入依赖项。
class Car {
public void Run(IEngine engine)
{
engine.Start();
}
}
IEngine engine = new GasolineEngine();
Car car = new Car();
car.Run(engine); // Output: Gasoline Engine start.
依赖注入的主要优点
- 降低耦合性
-
依赖注入技术可以将各个组件之间的依赖关系解耦,减少了各个组件之间的相互依赖,从而提高了系统的可维护性和可扩展性。
-
提高代码的可测试性
-
依赖注入可以让我们更加方便地对系统进行单元测试。
-
提供了更加灵活的配置方式
- 依赖注入可以从外部配置文件、注解等多个方式来进行配置,提供了更加灵活的配置方式。
示例说明
以下是一个使用Spring框架实现依赖注入的示例:
//定义一个接口
public interface MessageService {
String getMessage();
}
//实现接口
public class HelloWorldMessageService implements MessageService{
@Override
public String getMessage() {
return "Hello, Spring!";
}
}
//注入实现类
@Service
public class MessagePrinter {
private final MessageService service;
@Autowired
public MessagePrinter(MessageService service) {
this.service = service;
}
public void printMessage(){
System.out.println(this.service.getMessage());
}
}
上面的示例中,我们定义了一个 MessageService 接口,有两个实现类,一个实现类是 HelloWorldMessageService,实现 getMessage 方法并返回 “Hello, Spring!”。另一个是 MessagePrinter,它通过构造函数正常例来依赖注入实现类。
另一个示例是 Dagger 框架的依赖注入实现:
定义一个接口:
public interface Pump {
void pump();
}
定义其实现类:
public class Thermosiphon implements Pump {
private final Heater heater;
@Inject
public Thermosiphon(Heater heater) {
this.heater = heater;
}
@Override public void pump() {
if (heater.isHot()) {
System.out.println("=> => pumping => =>");
}
}
}
定义另一个接口和其实现类:
public interface Heater {
void on();
void off();
boolean isHot();
}
public class ElectricHeater implements Heater {
boolean heating;
@Override public void on() {
System.out.println("~ ~ ~ heating ~ ~ ~");
this.heating = true;
}
@Override public void off() {
this.heating = false;
}
@Override public boolean isHot() {
return heating;
}
}
然后在主函数中注入:
public class CoffeeMaker {
@Inject Heater heater;
@Inject Pump pump;
public CoffeeMaker() { }
public void brew() {
heater.on();
pump.pump();
System.out.println(" [_]P coffee! [_]P ");
heater.off();
}
}
CoffeeMaker coffeeMaker = DaggerCoffeeComponent.create().maker();
coffeeMaker.brew();
总之,依赖注入是一种非常重要的技术,它可以帮助我们降低耦合性、提高代码灵活性和可测试性。