适配器模式

98 阅读2分钟

适用场景

一般来说,适配器模式可以看作一种“补偿模式”,用来补救设计上的缺陷。应用这种模式算是“无奈之举”。如果在设计初期,我们就能协调规避接口不兼容的问题,那这种模式就没有应用的机会了。

type ITarget interface {
   f1()
   f2()
   f3()
}

type Adaptee struct {
}

func (a *Adaptee) fa() {
   fmt.Println("fa")
}
func (a *Adaptee) fb() {
   fmt.Println("fb")
}
func (a *Adaptee) fc() {
   fmt.Println("fc")
}

type Adapter struct {
   Adaptee
}

func (a *Adapter) f1() {
   a.fa()
}
func (a *Adapter) f2() {
   a.fb()
}
func (a *Adapter) f3() {
   a.fc()
}

func target(t ITarget) {
   t.f1()
   t.f2()
   t.f3()
}
func TestAdapter() {
   a := &Adapter{
      Adaptee{},
   }
   target(a)
}

可以看到Adaptee不满足接口的方法,就用Adapter类作为适配器封装一层,内部调用Adaptee方法


还有一种场景统一多个类的接口设计

某个功能的实现依赖多个外部系统(或者说类)。通过适配器模式,将它们的接口适配为统一的接口定义。假设我们的系统要对用户输入的文本内容做敏感词过滤,为了提高过滤的召回率,我们引入了多款第三方敏感词过滤系统,依次对用户输入的内容进行过滤,过滤掉尽可能多的敏感词。但是,每个系统提供的过滤接口都是不同的。这就意味着我们没法复用一套逻辑来调用各个系统。这个时候,我们就可以使用适配器模式,将所有系统的接口适配为统一的接口定义,这样我们可以复用调用敏感词过滤的代码

比如原来有3个过滤系统,每个定义的方法都不一样

type ASensitiveWordFilter struct{}

func (a *ASensitiveWordFilter) FilterSexyWord(string) string {
   fmt.Println("FilterSexyWord")
   return ""
}
func (a *ASensitiveWordFilter) FilterPolicyWord(string) string {
   fmt.Println("FilterPolicyWord")
   return ""
}

type BSensitiveWordFilter struct{}

func (b *BSensitiveWordFilter) ViolenceWordFilter(string) string {
   fmt.Println("ViolenceWordFilter")
   return ""
}
func (b *BSensitiveWordFilter) BloodyWordFilter(string) string {
   fmt.Println("BloodyWordFilter")
   return ""
}

type CSensitiveWordFilter struct{}

func (c *CSensitiveWordFilter) FilterReligion(string) string {
   fmt.Println("FilterReligion")
   return ""
}

func TestUnAdapter() {
   var str string = "i didnt say anything,i just walk away"
   a := &ASensitiveWordFilter{}
   b := &BSensitiveWordFilter{}
   c := &CSensitiveWordFilter{}
   filteredStr := a.FilterSexyWord(str)
   filteredStr = a.FilterPolicyWord(filteredStr)
   filteredStr = b.BloodyWordFilter(filteredStr)
   filteredStr = b.ViolenceWordFilter(filteredStr)
   filteredStr = c.FilterReligion(filteredStr)
}

可以看到上面方法TestUnAdapter可测试性差,扩展性不好,为了解决问题, 用适配器为每一个过滤系统新建一个类,适配器类实现接口的统一Filter方法,内部调用各个系统的方法,如下所示

type ISensitiveWordFilter interface {
   Filter(s string) string
}

type ASensitiveWordFilterAdaptor struct {
   base *ASensitiveWordFilter
}

func (a *ASensitiveWordFilterAdaptor) Filter(s string) string {
   filtered := a.base.FilterSexyWord(s)
   filtered = a.base.FilterPolicyWord(filtered)
   return filtered
}

type BSensitiveWordFilterAdaptor struct {
   base *BSensitiveWordFilter
}

func (b *BSensitiveWordFilterAdaptor) Filter(s string) string {
   filtered := b.base.BloodyWordFilter(s)
   filtered = b.base.ViolenceWordFilter(filtered)
   return filtered
}

type CSensitiveWordFilterAdaptor struct {
   base *CSensitiveWordFilter
}

func (c *CSensitiveWordFilterAdaptor) Filter(s string) string {
   filtered := c.base.FilterReligion(s)
   return filtered
}

func TestAdapted() {
   var str string = "how do you do"
   a := &ASensitiveWordFilterAdaptor{
      base: &ASensitiveWordFilter{},
   }
   b := &BSensitiveWordFilterAdaptor{
      base: &BSensitiveWordFilter{},
   }
   c := &CSensitiveWordFilterAdaptor{
      base: &CSensitiveWordFilter{},
   }
   iFilters := make([]ISensitiveWordFilter, 0)
   iFilters = append(iFilters, a, b, c)
   for _, filter := range iFilters {
      str = filter.Filter(str)
   }
}

如上面代码所示,分别为3个系统类新建三个对应的XAdaptor类,这些类实现接口ISensitiveWordFilter的Filter方法,每一个XAdaptor类的Filter方法内部调用对应类的过滤方法,这样对外按照接口形式给出,如TestAdapted方法中所示,比较统一