共计 2543 个字符,预计需要花费 7 分钟才能阅读完成。
原文首发于我的博客:https://kaolengmian7.com/post…
示例代码曾经上传到我的 Github:https://github.com/kaolengmian7/golang-demo/tree/master/design_pattern/adapter, 能够把代码拉下来跑一跑~
核心思想
适配器是两个不兼容的接口之间的桥梁,使接口不兼容的对象可能相互合作。
应用场景
有动机地批改一个失常运行的零碎的接口,这时应该思考应用适配器模式。
1. 封装有缺点的接口
2. 封装多个接口
3. 替换依赖
4. 兼容老版本接口
5. 适配不同格局数据
肯定要留神:适配器为的是解决正在退役的我的项目的问题,而不是在设计阶段增加的。如果在设计阶段就思考应用适配器模式,那这个设计肯定不合格。
实战
如果你正在开发一款股票市场监测程序,它会从不同起源下载 XML 格局的股票数据,而后向用户呈现出好看的图表。
type XmlHandler interface {ProcessXml(xml string)}
type xmlHandler struct{}
func (x *xmlHandler) ProcessXml(xml string) {log.Printf("xml:%s processing", xml)}
在开发过程中,你决定在程序中整合一个第三方智能剖析函数库。然而遇到了一个问题,那就是剖析函数库只兼容 JSON 格局的数据。
// 剖析库接口
type JsonHandler interface {ProcessJson(json []byte)}
type jsonHandler struct {
}
func (j *jsonHandler) ProcessJson(json []byte) {log.Printf("json processing")}
你能够批改函数库来反对 XML。然而,这可能须要大量代码。或者,咱们能够将 XML 转换成 JSON?
xml 与 json 代表了事实中不兼容的两个接口。
为了演示不便,我用string 类型
示意xml 文件
,用[]byte
示意json 文件
适配器就是为两个兼容两个接口而生,在此例中:xmlAdapter
继承了XmlHandler 接口
,其中封装了对接口的解决。后果就是,客户端的 JSON 解决被“适配”成 XML 解决。
type xmlAdapter struct {JsonHandler}
func (x *xmlAdapter) ProcessXml(xml string) {
// 模仿对象转换:xml -> json
json := []byte(xml) // 解决 json 文件
x.ProcessJson(json)}
func TestAdapter(t *testing.T) {inputJson := []byte("json_file") // 原客户端
handler := &jsonHandler{} handler.ProcessJson(inputJson)
// 客户端接入适配器,利用 原有的 JsonHandler 解决 xml 文件。inputXml := "xml_file" adapter := &xmlAdapter{&jsonHandler{}} adapter.ProcessXml(inputXml)}
长处
灵活性强,上线新性能不须要改变大量源代码,仅须要在接口层做一层类型转换。
毛病
过多地应用适配器,会让零碎十分零乱。比方,表明上看到调用的是 A 接口,其实外部被适配成了 B 接口的实现。
一个零碎如果太多呈现这种状况,无异于一场劫难。因而如果不是很有必要,尽量不应用适配器,而是间接对系统进行重构。
更进一步:加强版适配器
对于 Golang 这种能够实现多继承的语言来讲,适配器有更优雅的解决方案:让适配器实现所有接口。
type adapter struct {jsonHandler JsonHandler xmlHandler XmlHandler}
这样的适配器弱小的多,想用谁的实现就用谁的实现,与此同时齐全躲避了下面提到的毛病,不容易产生误解。
func TestAdapterInGolang(t *testing.T) {inputJson := []byte("json_file") inputXml := "xml_file" // 原客户端
handler := &jsonHandler{} handler.ProcessJson(inputJson)
// 客户端接入适配器
adapter := &adapter{&jsonHandler{}, &xmlHandler{}} adapter.jsonHandler.ProcessJson(inputJson) // 想用 json 用 json adapter.xmlHandler.ProcessXml(inputXml) // 想用 xml 用 xml}
也能够重写函数:
type adapter struct {}
func (x *adapter) ProcessJson(json []byte) {// 自定义解决逻辑}
func (x *adapter) ProcessXml(xml string) {// 自定义解决逻辑}
func TestAdapterInGolang(t *testing.T) {inputJson := []byte("json_file") inputXml := "xml_file" // 原客户端
handler := &jsonHandler{} handler.ProcessJson(inputJson)
// 客户端接入适配器
adapter := &adapter{&jsonHandler{}, &xmlHandler{}} adapter.ProcessJson(inputJson) // 想用 json 用 json adapter.ProcessXml(inputXml) // 想用 xml 用 xml}
参考:
- https://refactoringguru.cn/design-patterns/adapter
- http://shusheng007.top/2021/09/08/018/
- https://www.runoob.com/design-pattern/adapter-pattern.html
- https://lailin.xyz/post/adapter.html#comments