设计模式-适配器模式

Posted by 付辉 on Sunday, April 7, 2019 共973字

当你眼里只有赚钱的时候,你就永远无法把事情本身给做好,收获的也会很有限,最后可能还赚不到钱。- From Myself

下面的代码是github.com/gin-gonic/gin/binding中获取Binding实例的逻辑。我在想:这段代码体现的是什么设计模式呢?写法上肯定是工厂模式,因为它基于不同的contentType创建返回具体的实例。但从宏观上来看,它算不算一个适配器呢?

func Default(method, contentType string) Binding {
	if method == "GET" {
		return Form
	}

	switch contentType {
	case MIMEJSON:
		return JSON
	case MIMEXML, MIMEXML2:
		return XML
	case MIMEPROTOBUF:
		return ProtoBuf
	case MIMEMSGPACK, MIMEMSGPACK2:
		return MsgPack
	default: //case MIMEPOSTForm, MIMEMultipartPOSTForm:
		return Form
	}
}

Adapter Pattern

适配器模式不仅仅局限于代码设计,在现实世界中也经常会看到。比如苹果手机的转接线,将新的、方形的Lighting接口适配到旧的、圆孔的耳机上。

Adapter Pattern主要被用来适配两个不兼容的接口,给两个独立或者不兼容的类提供一个兼容模式,而不需要修改两者内部的具体实现。Adapter Pattern可以是一个独立的新对象或者新方法,在设计中扮演一个桥梁的作用,或者是对不相互兼容的数据格式进行转换。又或者是重用系统老的既存类,来提供新的功能。

Purpose

适配器主要通过转换数据格式,组合、引用不兼容的对象,最终实现我们期盼的功能。

  1. 老系统到新系统的业务迁移。新老系统首先在接收数据的格式上不尽相同,其次新系统可能也需要调用老系统的内部实现。
  2. 重新对对象进行封装,用来提供业务期望的新功能。或者让不兼容的对象可以一起工作。

Design Pattern Diagram

  • TargetClient端调用的新接口。
  • Adapter:将Adaptee适配到Target,实现两者间的转换。
  • Adaptee:需要去适配的既存接口

Implementation

常见的适配实现主要有两种方式:

  1. 通过类的继承来实现
  2. 通过类的组合来实现

很多地方都有提到:组合优于继承。因为组合结构非常灵活,而且没有继承关系中改变既有代码的负面影响。适配器作为一个独立的类,用组合的方式,也更能体现出桥梁的作用。

Verdict

Adapter Pattern 可以用于新老功能的数据结构转换,或者基于既有类来实现额外的功能。如果TargetAdaptee功能相似,那么Adapter可能只需要委托Adaptee去处理。但如果不相似,我们可能就需要转换两者的数据结构,并组合其他功能类来实现具体的处理逻辑了。

Adapter Pattern 的优势在于:通过引入一个适配类,我们无需去改变已经存在的类或者接口,也有效的限制了代码调整的范围,避免对现有业务造成一些未知的负面影响。

参考文章:

  1. Design Patterns in Golang: Adapter