美文网首页
基于接口而非实现编程

基于接口而非实现编程

作者: 疯狂的小强_94ee | 来源:发表于2019-11-26 22:25 被阅读0次

    “基于接口而非实现编程”这条原则的另一个表述方式,是“基于抽象而非实现编程”。后者的表述方式其实更能体现这条原则的设计初衷。在软件开发中,最大的挑战之一就是需求的不断变化,这也是考验代码设计好坏的一个标准。越抽象、越顶层、越脱离具体某一实现的设计,越能提高代码的灵活性,越能应对未来的需求变化。好的代码设计,不仅能应对当下的需求,而且在将来需求发生变化的时候,仍然能够在不破坏原有代码设计的情况下灵活应对。而抽象就是提高代码扩展性、灵活性、可维护性最有效的手段之一。


    public interface ImageStore {

      String upload(Image image, String bucketName);

      Image download(String url);

    }

    public class AliyunImageStore implements ImageStore {

      //...省略属性、构造函数等...

      public String upload(Image image, String bucketName) {

        createBucketIfNotExisting(bucketName);

        String accessToken = generateAccessToken();

        //...上传图片到阿里云...

        //...返回图片在阿里云上的地址(url)...

      }

      public Image download(String url) {

        String accessToken = generateAccessToken();

        //...从阿里云下载图片...

      }

      private void createBucketIfNotExisting(String bucketName) {

        // ...创建bucket...

        // ...失败会抛出异常..

      }

      private String generateAccessToken() {

        // ...根据accesskey/secrectkey等生成access token

      }

    }

    // 上传下载流程改变:私有云不需要支持access token

    public class PrivateImageStore implements ImageStore  {

      public String upload(Image image, String bucketName) {

        createBucketIfNotExisting(bucketName);

        //...上传图片到私有云...

        //...返回图片的url...

      }

      public Image download(String url) {

        //...从私有云下载图片...

      }

      private void createBucketIfNotExisting(String bucketName) {

        // ...创建bucket...

        // ...失败会抛出异常..

      }

    }

    // ImageStore的使用举例

    public class ImageProcessingJob {

      private static final String BUCKET_NAME = "ai_images_bucket";

      //...省略其他无关代码...

      public void process() {

        Image image = ...;//处理图片,并封装为Image对象

        ImageStore imageStore = new PrivateImageStore(...);

        imagestore.upload(image, BUCKET_NAME);

      }

    }

    尽管我们通过接口来隔离了两个具体的实现。但是,在项目中很多地方,我们都是通过下面第 8 行的方式来使用接口的。这就会产生一个问题,那就是,如果我们要替换图片存储方式,还是需要修改很多类似第 8 行那样的代码。这样的设计还是不够完美,对此,你有更好的实现思路吗?

    // ImageStore的使用举例

    public class ImageProcessingJob {

      private static final String BUCKET_NAME = "ai_images_bucket";

      //...省略其他无关代码...

      public void process() {

        Image image = ...;//处理图片,并封装为Image对象

        ImageStore imageStore = new PrivateImageStore(/*省略构造函数*/);

        imagestore.upload(image, BUCKET_NAME);

      }

    两种方法改进:简单工厂方法和使用反射。

    1、简单工厂方法

    ImageStore imageStore = ImageStoreFactory.newInstance(SOTRE_TYPE_CONFIG);

    config文件可以写类似properties的文件,使用key-value存储。

    缺点:再新增另一种存储手段时,需要修改工厂类和添加新的类。修改工厂类,违反了开放-封闭原则。

    那有没有更好一点的方法呢?

    2、使用反射。

    在配置文件中定义需要的image store类型。

    在ProcessJob中

    ImageStore store = (ImageStore) Class.forName(STORE_CLASS)

        .newInstance();

    缺点:使用反射,在大量创建对象时会有性能损失。

    相关文章

      网友评论

          本文标题:基于接口而非实现编程

          本文链接:https://www.haomeiwen.com/subject/fofuwctx.html