09 | 设计模式之美——王争

越是不稳定的系统,我们越是要在代码的扩展性、维护性上下功夫。

09 | 理论六:为什么基于接口而非实现编程?有必要为每个类都定义接口吗?


1. 如何解读原则中的“接口”二字?

  • 越抽象、越顶层、越脱离具体某一实现的设计,越能提高代码的灵活性,越能应对未来的需求变化。好的代码设计,不仅能应对当下的需求,而且在将来需求发生变化的时候,仍然能够在不破坏原有代码设计的情况下灵活应对。

2. 如何将这条原则应用到实战中?

  • 在编写代码的时候,要遵从“基于接口而非实现编程”的原则(只表明做什么而不是怎么做):
    1. 函数的命名不能暴露任何实现细节。比如,前面提到的 uploadToAliyun() 就不符合要求,应该改为去掉 aliyun 这样的字眼,改为更加抽象的命名方式,比如:upload()。
    2. 封装具体的实现细节。比如,跟阿里云相关的特殊上传(或下载)流程不应该暴露给调用者。我们对上传(或下载)流程进行封装,对外提供一个包裹所有上传(或下载)细节的方法,给调用者使用。
    3. 为实现类定义抽象的接口。具体的实现类都依赖统一的接口定义,遵从一致的上传功能协议。使用者依赖接口,而不是具体的实现类来编程。

3. 是否需要为每个类定义接口?

  • 并不是。设计初衷是将接口和实现相分离,封装不稳定的实现,暴露稳定的接口。以此降低耦合,提高扩展性。
  • 因此,如果在我们的业务场景中,某个功能只有一种实现方式,未来也不
    可能被其他实现方式替换,那我们就没有必要为其设计接口,也没有必要基于接口编程,直接使用实现类就可以了。

4. 课堂讨论

  • 在今天举的代码例子中,尽管我们通过接口来隔离了两个具体的实现。但是,在项目中很多地方,我们都是通过下面第 8 行的方式来使用接口的。这就会产生一个问题,那就是,如果我们要替换图片存储方式,还是需要修改很多类似第 8 行那样的代码。这样的设计还是不够完美,对此,你有更好的实现思路吗?
    // ImageStore 的使用举例
     public class ImageProcessingJob { 
     	 private static final String BUCKET_NAME = "ai_images_bucket"; 
     	 //... 省略其他无关代码... 
     	 public void process() { 
     	 	Image image = ...;// 处理图片,并封装为 Image 对象
    8		ImageStore imageStore = new PrivateImageStore(/* 省略构造函数 */); 
    		imagestore.upload(image, BUCKET_NAME); 
    	}
    }
    
  • 两种方法:
    1. 简单工厂+反射+配置
    2. 通过使用控制反转/依赖注入方式,类似于Spring
  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值