---
# System prepended metadata

title: “基於接口而非實現編程”的原則

---

# “基於接口而非實現編程”的原則

這條原則能非常有效地提高代碼質量，之所以這麼說，那是因為，應用這條原則，可以將接口和實現相分離，封裝不穩定的實現，暴露穩定的接口。上游系統面向接口而非實現編程，不依賴不穩定的實現細節，這樣當實現發生變化的時候，上游系統的代碼基本上不需要做改動，以此來降低耦合性，提高擴展性。

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

1. 函數的命名不能暴露任何實現細節。比如，前面提到的 uploadToAliyun() 就不符合要求，應該改為去掉 aliyun 這樣的字眼，改為更加抽像的命名方式，比如：upload()。
2. 封裝具體的實現細節。比如，跟阿裡雲相關的特殊上傳（或下載）流程不應該暴露給調用者。我們對上傳（或下載）流程進行封裝，對外提供一個包裹所有上傳（或下載）細節的方法，給調用者使用。
3. 為實現類定義抽像的接口。具體的實現類都依賴統一的接口定義，遵從一致的上傳功能協議。使用者依賴接口，而不是具體的實現類來編程。


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


---

### 是否需要為每個類定義接口？

從這個設計初衷上來看，如果在我們的業務場景中，某個功能只有一種實現方式，未來也不可能被其他實現方式替換，那我們就沒有必要為其設計接口，也沒有必要基於接口編程，直接使用實現類就可以了。除此之外，越是不穩定的系統，我們越是要在代碼的擴展性、維護性上下功夫。相反，如果某個系統特別穩定，在開發完之後，基本上不需要做維護，那我們就沒有必要為其擴展性，投入不必要的開發時間。