zoukankan      html  css  js  c++  java
  • 基于接口而非实现编程 和 依赖注入

    基于接口而非实现编程

    1.要遵从“基于接口而非实现编程”的原则,具体来讲,我们需要做到下面这 3 点: 函数的命名不能暴露任何实现细节。比如,uploadToAliyun() 就不符合要求,应该改为去掉 aliyun 这样的字眼,改为更加抽象的命名方式,比如:upload()。

    封装具体的实现细节。比如,跟阿里云相关的特殊上传(或下载)流程不应该暴露给调用者。我们对上传(或下载)流程进行封装,对外提供一个包裹所有上传(或下载)细节的方法,给调用者使用。 为实现类定义抽象的接口。具体的实现类都依赖统一的接口定义,遵从一致的上传功能协议。使用者依赖接口,而不是具体的实现类来编程。

    2.是否需要为每个类定义接口? 从这个设计初衷上来看,如果在我们的业务场景中,某个功能只有一种实现方式,未来也不可能被其他实现方式替换,那我们就没有必要为其设计接口,也没有必要基于接口编程,直接使用实现类就可以了。

     

    依赖注入

    用一句话来概括就是:不通过 new() 的方式在类内部创建依赖类对象,而是将依赖的类对象在外部创建好之后,通过构造函数、函数参数等方式传递(或注入)给类使用。

     

    场景

    例子1:

    我们代码中通过 Kafka 来发送异步消息。对于这样一个功能的开发,我们要学会将其抽象成一组跟具体消息队列(Kafka)无关的异步消息接口。

    所有上层系统都依赖这组抽象的接口编程,并且通过依赖注入的方式来调用。当我们要替换新的消息队列的时候,比如将 Kafka 替换成 RocketMQ,可以很方便地拔掉老的消息队列实现,插入新的消息队列实现。具体代码如下所示:

    // 这一部分体现了抽象意识
    public interface MessageQueue { //... }
    public class KafkaMessageQueue implements MessageQueue { //... }
    public class RocketMQMessageQueue implements MessageQueue {//...}
    public interface MessageFromatter { //... }
    public class JsonMessageFromatter implements MessageFromatter {//...}
    public class ProtoBufMessageFromatter implements MessageFromatter {//...}
    public class Demo {
      private MessageQueue msgQueue; // 基于接口而非实现编程
      public Demo(MessageQueue msgQueue) { // 依赖注入
        this.msgQueue = msgQueue;
      }
      
      // msgFormatter:多态、依赖注入
      public void sendNotification(Notification notification, MessageFormatter msgFormatter) {
        //...    
      }
    }
     

    例子2:

    在这个例子中,Notification 类负责消息推送,依赖 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);
    ​
    
    

    总结

    1.“基于接口而非实现编程”,这条原则的另一个表述方式,是“基于抽象而非实现编程”。后者的表述方式其实更能体现这条原则的设计初衷。我们在做软件开发的时候,一定要有抽象意识、封装意识、接口意识。越抽象、越顶层、越脱离具体某一实现的设计,越能提高代码的灵活性、扩展性、可维护性。

    2.我们在定义接口的时候,一方面,命名要足够通用,不能包含跟具体实现相关的字眼;另一方面,与特定实现有关的方法不要定义在接口中。

    3.“基于接口而非实现编程”这条原则,不仅仅可以指导非常细节的编程开发,还能指导更加上层的架构设计、系统设计等。比如,服务端与客户端之间的“接口”设计、类库的“接口”设计。

     

    参考来源: 极客时间 王争 老师的 《设计模式之美》 

     

     

  • 相关阅读:
    iOS 列表三级展开
    iOS 聊天界面
    iOS 地图(添加大头针)
    iOS 地图
    swift 快速创建一些基本控件
    swift
    swift
    swift4.2 打印所有系统字体
    Xcode 去掉控制台无用打印信息
    swift
  • 原文地址:https://www.cnblogs.com/Deaseyy/p/13943925.html
Copyright © 2011-2022 走看看