Administrator
发布于 2023-07-21 / 18 阅读 / 0 评论 / 0 点赞

设计模式

设计模式之美笔记

为什么要基于接口而非实现编程,有必要为每个类都定义接口吗?

什么接口,语法是什么。怎么做到封装不稳定的实现,暴露稳定的接口。以此降低耦合性,和提高扩展性

学习目标:在软件开发中,最大的挑战就是需求不断变化,这也是考验系统设计的一个好坏。越抽象、越顶层、越脱离具体某一实现的设计,越能提高代码的灵活性,越能应对未来的需求变化。好的代码设计,不仅能应对当下的需求,而且在将来需求发生变化的时候,仍然能够在不破坏原有代码设计的情况下灵活应对。

实例:

public class AliyunImageStore {
  //...省略属性、构造函数等...
  
  public void createBucketIfNotExisting(String bucketName) {
    // ...创建bucket代码逻辑...
    // ...失败会抛出异常..
  }
  
  public String generateAccessToken() {
    // ...根据accesskey/secrectkey等生成access token
  }
  
  public String uploadToAliyun(Image image, String bucketName, String accessToken) {
    //...上传图片到阿里云...
    //...返回图片存储在阿里云上的地址(url)...
  }
  
  public Image downloadFromAliyun(String url, String accessToken) {
    //...从阿里云下载图片...
  }
}
// AliyunImageStore类的使用举例
public class ImageProcessingJob {
  private static final String BUCKET_NAME = "ai_images_bucket";
  //...省略其他无关代码...
  
  public void process() {
    Image image = ...; //处理图片,并封装为Image对象
    AliyunImageStore imageStore = new AliyunImageStore(/*省略参数*/);
    imageStore.createBucketIfNotExisting(BUCKET_NAME);
    String accessToken = imageStore.generateAccessToken();
    imagestore.uploadToAliyun(image, BUCKET_NAME, accessToken);
  }
}

这块代码是没有任何问题的,问题在于如果我们后期要换成自己私有云来充当OSS服务器,这个类,类的实例化对象均需要更换,这是一个很大的工程量,这个时候就可以说这个设计是失败的。有一下原因

  • 重点是命名中都存在Aliyun

  • 如果私有云使用方法和aliyun不一致,比如accessID,这就导致接下来的代码大量冗余但是不可复用

如何重构这块代码呢?

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);
  }
}

那么问题就又来了,怎么能做到在最开始的时候就做到这种设计,哈哈哈哈其实我也不会,感觉是写的多了,思考的多了,定时总结,然后类似于肌肉记忆就记住了。


评论