今天继续打卡学习极客时间上的专栏“设计模式之美”, 本篇是专栏第9节的学习笔记,第9节是专栏中介绍"面向对象"这一设计原则和设计思想的一节。

笔记

基于接口编程(Interface-based programing)是一个设计原则,理解这条原则里的接口两字,接口是一组协议约定。 接口这个词在不同场景下有不同的含义,比如后端服务提供给前端服务的"接口”、类库提供的"接口”、而一组自定义的私有通信协议也可以被称作"接口”,而具体编程语言中的接口一般指的是这种编程语言中的"接口或抽象类"的语法特性。我们再来看一下维基百科中“基于接口编程”的定义: 基于接口编程也称基于接口的架构,它是一种在没有模块系统的面向对象程序设计语言中的组件层面实现模块化编程的架构模式。

使用这条设计原则,可以将接口和实现分离,封装不稳定的实现,暴露稳定的接口。上游系统面向接口而非实现编程,不依赖于不稳定的实现细节,以此来降低耦合性、提高扩展性和可维护性。可以看出这条设计原则往更高层抽象可以是系统组件中的"接口”,而落到具体的代码上就是使用"接口或抽象类”

示例代码重写

专栏作者使用Java给出了基于接口编程的例子,这里分别用python和go重写一下:

python版本

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
class Image:
    pass

class AliyunImageStore:
    
    def upload(self, image, bucket_name):
        print('upload image to aliyun image store')

    def download(self, url):
        print('download iamge from aliyun image store')

class PrivateImageStore:
    
    def upload(self, image, bucket_name):
        print('upload image to private image store')

    def download(self, url):
        print('download iamge from private image store')

def main():
    image = Image()
    # image_store = AliyunImageStore()
    image_store = PrivateImageStore()
    image_store.upload(image, 'the-bucket-name')

if __name__ == '__main__':
    main()

python中没有直接提供接口和抽象类的特性,如果想在python中定义一个接口或抽象类,来通过执行类型检查确保子类实现了某些特定的方法话可以使用python的abc模块。 这个在前面设计模式之美学习笔记05: 封装、抽象、继承、多态,面向对象的四大特性中学习抽象特性时有一个示例代码。而本篇的例子并没有使用abc模块,这里不需要静态的类型检查,而是直接使用了python动态语言的特性。

go版本

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
package main

import (
	"fmt"
)

type Image struct {
}

type ImageStore interface {
	upload(image *Image, bucketName string) (string, error)
	download(url string) (*Image, error)
}

type AliyunImageStore struct {
}

func (imageStore *AliyunImageStore) upload(image *Image, bucketName string) (string, error) {
	fmt.Println("upload image to aliyun image store")
	return "", nil
}

func (imageStore *AliyunImageStore) download(url string) (*Image, error) {
	fmt.Println("download iamge from aliyun image store")
	return &Image{}, nil
}

type PrivateImageStore struct {
}

func (imageStore *PrivateImageStore) upload(image *Image, bucketName string) (string, error) {
	fmt.Println("upload image to private image store")
	return "", nil
}

func (imageStore *PrivateImageStore) download(url string) (*Image, error) {
	fmt.Println("download iamge from private image store")
	return &Image{}, nil
}

func main() {
	var imageStore ImageStore
	imageStore = &PrivateImageStore{}
	imageStore.upload(&Image{}, "the-bucket-name")
}

参考