史无前例的设计模式-依赖反转原则

一、说明

再说依赖反转之前,首先谈下控制反转和依赖注入。是不是回想起很熟悉的一道面试题:知道spring吗?说说控制反转(IOC)和依赖注入(DI)。

二、控制反转(IOC)

1、概念

控制反转:Inversion Of Control,简称IOC。

2、代码分析

public class UserServiceTest {
  public static boolean doTest() {
    // ... 
  }
  
  public static void main(String[] args) {
	//这部分逻辑可以放到框架中
    if (doTest()) {
      System.out.println("Test succeed.");
    } else {
      System.out.println("Test failed.");
    }
  }
}

上面代码中其实就是硬编码,所有流程都由开发者自己控制,如果采取下面的这样一个框架来改造再看看效果

public abstract class TestCase {
  public void run() {
    if (doTest()) {
      System.out.println("Test succeed.");
    } else {
      System.out.println("Test failed.");
    }
  }
  // 类似于模板模式的模板方法
  public abstract boolean doTest();
}

public class JunitApplication {
  private static final List<TestCase> testCases = new ArrayList<>();
  
  public static void register(TestCase testCase) {
    testCases.add(testCase);
  }
  
  public static final void main(String[] args) {
    for (TestCase case: testCases) {
      case.run();
    }
  }

这个就相当于弄出个抽象模板方法doTest,使用者自己继承这个类去重写doTest方法,不再需要管main方法的执行流程。

public class UserServiceTest extends TestCase {
  @Override
  public boolean doTest() {
    // ... 
  }
}

// 注册操作还可以通过配置的方式来实现,不需要程序员显示调用register()
JunitApplication.register(new UserServiceTest();

这就是对控制反转IOC最好的证明,用框架来驱动整个程序流程的执行,而不是需要每次都需要开发者自己控制主流程。Spring的框架不就是帮我们完成了这部分功能吗?所以,控制反转并不是一种具体的实现技巧,而是一个比较笼统的设计思想,一般用来指导框架层面的设计。

三、依赖注入(DI)

1、概念

依赖注入跟控制反转相反,它不是一种设计思想,而是一种能落地的具体的编码技巧。一句话来概括就是:不通过 new() 的方式在类内部创建依赖类对象,而是将依赖的类对象在外部创建好之后,通过构造函数、函数参数等方式传递(或注入)给类使用。

2、代码分析

2.1、描述

Notification 类负责消息推送,依赖 MessageSender 类实现推送商品促销、验证码等消息给用户。

2.2、非依赖注入的方式

// 非依赖注入实现方式
public class Notification {
  private MessageSender messageSender;
  
  public Notification() {
    this.messageSender = new MessageSender(); //此处有点像hardcode
  }
  
  public void sendMessage(String cellphone, String message) {
    //...省略校验逻辑等...
    this.messageSender.send(cellphone, message);
  }
}

public class MessageSender {
  public void send(String cellphone, String message) {
    //....
  }
}
// 使用Notification
Notification notification = new Notification();

2.3、依赖注入的方式

// 依赖注入的实现方式
public class Notification {
  private MessageSender messageSender;
  
  // 通过构造函数将messageSender传递进来
  public Notification(MessageSender messageSender) {
    this.messageSender = messageSender;
  }
  
  public void sendMessage(String cellphone, String message) {
    //...省略校验逻辑等...
    this.messageSender.send(cellphone, message);
  }
}
//使用Notification
MessageSender messageSender = new MessageSender();
Notification notification = new Notification(messageSender);

其实就是将new的工作提取了出去,通过接收参数的方式去实例化,按照面向接口编程,还可以继续优化下,将MessageSender变成接口,有多种不同的实现。

public class Notification {
  private MessageSender messageSender;
  
  public Notification(MessageSender messageSender) {
    this.messageSender = messageSender;
  }
  
  public void sendMessage(String cellphone, String message) {
    this.messageSender.send(cellphone, message);
  }
}

public interface MessageSender {
  void send(String cellphone, String message);
}

// 短信发送类
public class SmsSender implements MessageSender {
  @Override
  public void send(String cellphone, String message) {
    //....
  }
}

// 站内信发送类
public class InboxSender implements MessageSender {
  @Override
  public void send(String cellphone, String message) {
    //....
  }
}

//使用Notification
MessageSender messageSender = new SmsSender();
Notification notification = new Notification(messageSender);

回想下Spring框架,它就是完美的IOC+DI的一种具体落地方案。

四、依赖反转原则(DIP)

依赖反转:Dependency Inversion Principle,简称DIP。也称依赖倒置原则。简单来说就是高层模块不要依赖低层 模块,这之间通过抽象来实现相互依赖。比如Tomcat,我们写的web应用部署到Tomcat中就能实现web效果。Tomcat就属于高层模块,我们写的Web服务属于低层模块,Tomcat并没有依赖我们的Web模块,那怎么还能运行,这就是两者都共同依赖一个“抽象”模块,也就是Servlet规范。
其实这条原则还是针对框架的。开发过程中服务之间很少可能不产生依赖。

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

【原】编程界的小学生

没有打赏我依然会坚持。

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值