缘起

最近复习设计模式
拜读谭勇德的<<设计模式就该这样学>>
本系列笔记拟采用golang练习之

适配器模式

适配器模式(Adapter Pattern)又叫作变压器模式,它的功能是将一个类的接口变成客户端所期望的另一种接口,从而使原本因接口不匹配而导致无法在一起工作的两个类能够一起工作,属于结构型设计模式。
_

场景

  • 某智能家居应用, 可接入并显示温度计信息
  • 系统设计的温度计接口, 采用的是摄氏度单位
  • 现按客户需求, 要接入某进口款温度计, 厂家提供的sdk只提供华氏度的温度信息
  • 根据适配器模式, 在不修改系统原有接口的情况下, 兼容新设备接入
  • 华氏度 = 32+ 摄氏度 × 1.8, 摄氏度 = (华氏度 - 32) ÷ 1.8

设计

  • IThermometer: 现有系统的温度计接口, 温度单位为摄氏度. 本次更新希望保持接口不变, 以免影响现有系统.
  • IThermometerFactory: 现有系统的温度计工厂接口. 本次更新希望保持接口不变, 以免影响现有系统.
  • ISpecialThermometer: 厂家sdk提供的温度计接口, 温度单位为华氏度
  • tMockSpecialThermometer: 厂家sdk提供的温度计实现
  • tMockSpecialAdapter: 根据适配器模式, 实现的温度计适配器, 为新温度计适配现有系统的接口
  • tMockSpecialFactory: 新温度计的工厂类, 实现IThermometerFactory接口

单元测试

adapter_pattern_test.go

  1. package structural_patterns
  2. import (
  3. "learning/gooop/structural_patterns/adapter"
  4. "testing"
  5. )
  6. func Test_AdapterPattern(t *testing.T) {
  7. factory := adapter.SpecialThermometerFactory
  8. thermometer := factory.Create("This is some configuration")
  9. t.Logf("centigrade = %v", thermometer.Centigrade())
  10. }

测试输出

  1. $ go test -v adapter_pattern_test.go
  2. === RUN Test_AdapterPattern
  3. adapter_pattern_test.go:11: centigrade = 26.5
  4. --- PASS: Test_AdapterPattern (0.00s)
  5. PASS
  6. ok command-line-arguments 0.003s

IThermometer.go

现有系统的温度计接口, 温度单位为摄氏度.

  1. package adapter
  2. // 现有系统的温度计接口, 摄氏度
  3. type IThermometer interface {
  4. Centigrade() float64
  5. }

IThermometerFactory.go

现有系统的温度计工厂接口.

  1. package adapter
  2. type IThermometerFactory interface {
  3. Create(config string) IThermometer
  4. }

ISpecialThermometer.go

厂家sdk提供的温度计接口, 温度单位为华氏度

  1. package adapter
  2. // 新接入的温度计, 华氏度
  3. type ISpecialThermometer interface {
  4. Fahrenheit() float64
  5. }

tMockSpecialThermometer.go

厂家sdk提供的温度计实现

  1. package adapter
  2. type tMockSpecialThermometer struct {
  3. mAddress string
  4. }
  5. func newMockSpecialThermometer(address string) ISpecialThermometer {
  6. return &tMockSpecialThermometer{
  7. address,
  8. }
  9. }
  10. func (me *tMockSpecialThermometer) Fahrenheit() float64 {
  11. return 79.7
  12. }

tMockSpecialAdapter.go

根据适配器模式, 实现的温度计适配器, 为新温度计适配现有系统的接口

  1. package adapter
  2. type tMockSpecialAdapter struct {
  3. mOrigin ISpecialThermometer
  4. }
  5. func newSpecialAdapter(origin ISpecialThermometer) IThermometer {
  6. return &tMockSpecialAdapter{
  7. origin,
  8. }
  9. }
  10. func (me *tMockSpecialAdapter) Centigrade() float64 {
  11. return (me.mOrigin.Fahrenheit() - 32) * 5 / 9
  12. }

tMockSpecialFactory.go

新温度计的工厂类, 实现IThermometerFactory接口

  1. package adapter
  2. type tMockSpecialFactory struct {
  3. }
  4. func newMockSpecialFactory() IThermometerFactory {
  5. return &tMockSpecialFactory{}
  6. }
  7. func (me *tMockSpecialFactory) Create(config string) IThermometer {
  8. t := newMockSpecialThermometer(me.parseAddress(config))
  9. return newSpecialAdapter(t)
  10. }
  11. func (me *tMockSpecialFactory) parseAddress(config string) string {
  12. return "http://localhost:8080"
  13. }
  14. var SpecialThermometerFactory IThermometerFactory = newMockSpecialFactory()

适配器模式小结

适配器模式的优点
(1)能提高类的透明性和复用,但现有的类复用不需要改变。
(2)适配器类和原角色类解耦,提高程序的扩展性。
(3)在很多业务场景中符合开闭原则。
适配器模式的缺点
(1)适配器编写过程需要结合业务场景全面考虑,可能会增加系统的复杂性。
(2)增加代码阅读难度,降低代码可读性,过多使用适配器会使系统代码变得凌乱。
_
(end)