Skip to main content
  1. internet/

设计模式之适配器、装饰器、外观

·980 words·2 mins·

适配器模式 #

适配器,顾名思义,是用来做适配的。比如手机的的电源适配器就是将输入电源的电压适配为手机需要的电压。

适配器模式也分为”主动适配“和”被动适配“。

主动适配 #

仓库模式(Repository Pattery)是适配器模式的一种应用。在我们的代码中,业务逻辑与规则是最复杂和最重要的地方,因此减轻逻辑层/领域层的复杂性至关重要。通过仓库模式,逻辑层/领域层无需关心底层存储的具体实现,由存储层来组装数据达到适配逻辑层/领域层的目的。

主动适配通过接口来定义行为,使用依赖导致来避免下层逻辑污染上层逻辑。

被动适配 #

在开发过程中,我们往往需要被动的去做一些适配,比如:

  • 老的接口并不是很符合我们的需求,因此需要适配老的接口
  • 我们需要重构代码,有些数据结构变了,但是对外的接口不能变,这时候需要适配对外的接口

被动的适配属于是无奈之举,但也是开发中必须的过程。整个团队应该关注这些需要被动适配的地方,然后通过不断重构、迭代消灭它们。

防腐层是这类模式的一种体现。

装饰器模式 #

与适配器的场景不同,装饰器模式是用来扩展功能的

比如说我们有个功能是同步通讯录 这个功能可以简化为同步部门和同步员工两个方法:

type Sync struct {}
func (s Sync) SyncDept() {
  // 同步部门代码
}
func (s Sync) SyncEmp() {
  // 同步员工代码
}

在使用过程中,用户反馈感知不到同步进度,因此需要增加进度条展示功能。于是我们的代码变成了:

type Sync struct {}
func (s Sync) SyncDept() {
  // 同步部门代码
  uploadProgress() // 上传进度
}
func (s Sync) SyncEmp() {
  // 同步员工代码
  uploadProgress() // 上传进度
}

虽然功能实现了,但是:

  1. 违反了开闭原则:同步逻辑并不需要修改但是修改了同步逻辑所在的代码
  2. 代码更复杂,加重了开发人员的认知负担。

我们先将旧版本的同步抽象为接口:

type SyncContact interface{
  SyncDept()
  SyncEmp()
}

然后装饰进度条功能:

type SyncWithProgress struct {
	sync Sync
}

func (s SyncWithProgress) SyncDept() {
  s.sync.SyncDept()
  uploadProgress() // 上传进度
}
func (s SyncWithProgress) SyncEmp() {
	s.sync.SyncEmp()
  uploadProgress() // 上传进度
}

这时候只需要将初始化Sync的地方改为初始化SyncWithProgress即可。

外观模式 #

外观模式的目的在于简化使用,比如go中常用的fmt.Println()的实现为:

func Println(a ...any) (n int, err error) {
	return Fprintln(os.Stdout, a...)
}

在开发过程中,也会经常将一个复杂的流程抽象为一个方法,其目的就是为了减少使用者的负担。

总结 #

  1. 当需要使用一个现有的对象/接口/方法时,如果不符合需求,那么就要使用适配器。
  2. 可以通过主动适配的方式来减少关键代码的复杂性。
  3. 如需简化调用方的使用,可以使用外观模式。
  4. 当需要扩展功能时,可以使用装饰器模式。