结构图
动机
在软件系统中,由于应用环境的变化,常常需要将“一些现存的对象”放在新的环境中应用,但是新环境要求的接口是这些现存对象所不满足的。
如何应对这种“迁移的变化”?如何既能利用现有对象的良好实现,同时又能满足新的应用环境所要求的接口?
角色
l 目标(Target)角色:这是客户所期待的接口。因为C#/VB.NET不支持多继承,所以Target必须是接口,不可以是类。
l 源(Adaptee)角色:需要适配的类。
l 适配器(Adapter)角色:把源接口转换成目标接口。这一角色必须是类。
意图
将一个类的接口转换成客房希望的另一个接口。Adapter模式使得原本由于接口不兼容而不能一起工作的那些类可以一起工作。
示意性代码
'Adapter pattern -- Structural example
Namespace DoFactoryNameSpace DoFactory.GangOfFour.Adapter.Structural
'Mainapp test application 
Public Class MainAppClass MainApp
Public Sub Main()Sub Main()
'Create adapter and place a request
Dim target As Target = New Adapter
target.Request()
'Wait for user
Console.ReadLine()
End Sub
'"Target" 
Public Class TargetClass Target
Public Overridable Sub Request()Sub Request()
Console.WriteLine("Called TargetRequest()")
End Sub
End Class
'"Adapter" 
Public Class AdapterClass Adapter
Inherits Target
Private adaptee As New Adaptee()
Public Overrides Sub Request()Sub Request()
'Possibly do some other work
'and then call SpecificRequest
adaptee.SpecificRequest()
End Sub
End Class
'"Adaptee" 
Public Class AdapteeClass Adaptee
Public Sub SpecificRequest()Sub SpecificRequest()
Console.WriteLine("Called SpecificRequest()")
End Sub
End Class
End Class
End Namespace
演变
旧程序
'"Adaptee" 
Public Class AdapteeClass Adaptee
Public Sub SpecificRequest()Sub SpecificRequest()
Console.WriteLine("Called SpecificRequest()")
End Sub
End Class

Public Class MainAppClass MainApp
Public Sub Main()Sub Main()
Dim adaptee As New Adaptee
adaptee.SpecificRequest()
'wait for user
Console.ReadLine()
End Sub
End Class
继承
客户程序期望通过Request方法使用Adaptee类,但是Adaptee类没有Request方法。这时我们提供一个类即Adapter类,它实现Target接口(此接口包含所有客户期望的方法),并继承于Adaptee。 Adapter类的Request方法重新封装了Adaptee的 SpecificRequest方法,实现了适配的目的。
'客户希望的接口
Public Interface ITargetInterface ITarget
Sub Request()Sub Request()
End Interface
'被适配的对象
Public Class AdapteeClass Adaptee
Public Sub SpecificRequest()Sub SpecificRequest()
Console.WriteLine("Called SpecificRequest()")
End Sub
End Class
'适配器
Public Class AdapterClass Adapter
Inherits Adaptee
Implements ITarget

Public Sub Request()Sub Request() Implements ITarget.Request
'Possibly do some other work
'and then call SpecificRequest
Me.SpecificRequest()
End Sub
End Class
'客户程序 
Public Class MainAppClass MainApp
Public Sub Main()Sub Main()
Dim adapter As Adapter = New Adapter
adapter.Request()
'wait for user
Console.Readline()
End Sub
End Class
委派
客户程序期望通过Request方法使用Adaptee类,但是Adaptee类没有Request方法。这时我们提供一个包装(Wrapper)类即Adapter类,它实现Target接口,此接口包含所有客户期望的方法,并包装了一个Adaptee的实例,从而使客户端与Adaptee衔接起来。
'客户希望的接口
Public Interface ITargetInterface ITarget
Sub Request()Sub Request()
End Interface
'被适配的对象
Public Class AdapteeClass Adaptee
Public Sub SpecificRequest()Sub SpecificRequest()
Console.WriteLine("Called SpecificRequest()")
End Sub
End Class
'适配器
Public Class AdapterClass Adapter
Implements ITarget
Private adaptee As New Adaptee()
Public Sub Request()Sub Request() Implements ITarget.Request
'Possibly do some other work
'and then call SpecificRequest
adaptee.SpecificRequest()
End Sub
End Class
'客户程序 
Public Class MainAppClass MainApp
Public Sub Main()Sub Main()
'Create adapter and place a request
Dim adapter As New Adapter
adapter.Request()
'wait for user
Console.readline()
End Sub
End Class
对Adapter模式的改进
旧程序
'"Adaptee" 
Public MustInherit Class AdapteeClass Adaptee
Public MustOverride Sub SpecificRequest()Sub SpecificRequest()
End Class
'"ConcreteAdaptee" 
Public Class ConcreteAdapteeAClass ConcreteAdapteeA
Inherits Adaptee
Public Overrides Sub SpecificRequest()Sub SpecificRequest()
Console.WriteLine("Called SpecificRequestA()")
End Sub
End Class
'"ConcreteAdaptee" 
Public Class ConcreteAdapteeBClass ConcreteAdapteeB
Inherits Adaptee
Public Overrides Sub SpecificRequest()Sub SpecificRequest()
Console.WriteLine("Called SpecificRequestA()")
End Sub
End Class

Public Class MainAppClass MainApp
Public Sub Main()Sub Main()
Dim c1 As adaptee = New ConcreteAdapteeA
c1.SpecificRequest()
Dim c2 As adaptee = New ConcreteAdapteeA
c2.SpecificRequest()
'wait for user
Console.Readline()
End Sub
End Class
配合泛型对“现存对象”进行适配。
'客户希望的新接口
Public Interface ITargetInterface ITarget
Sub Request()Sub Request()
End Interface
'适配器
Public Class AdapterClass Adapter(Of T As {Adaptee, New})
Implements ITarget
Protected _Adaptee As New T
Public Sub Request()Sub Request() Implements ITarget.Request
'Possibly do some other work
'and then call SpecificRequest
_Adaptee.SpecificRequest()
End Sub
End Class
'客户程序 
Public Class MainAppClass MainApp
Public Sub Main()Sub Main()
Dim c1 As New Adapter(Of ConcreteAdapteeA)
c1.Request()
Dim c2 As New Adapter(Of ConcreteAdapteeB)
c2.Request()
'wait for user
Console.Readline()
End Sub
End Class
Adapter模式中的“现存对象”作为新的接口方法参数,来达到适配的目的。
'客户希望的新接口
Public Interface ITargetInterface ITarget
Sub Request()Sub Request()
End Interface
'适配器
Public Class AdapterClass Adapter
Implements ITarget
Private _adaptee As Adaptee
Public Sub New()Sub New(Optional ByVal adaptee As Adaptee = Nothing)
Me.adaptee = adaptee
End Sub

Public Sub Request()Sub Request() Implements ITarget.Request
'Possibly do some other work
'and then call SpecificRequest
If _adaptee IsNot Nothing Then
_adaptee.SpecificRequest()
End If
End Sub
End Class

Public Class MainAppClass MainApp
Public Sub Main()Sub Main()
'Create adapter and place a request
Dim c1 As New Adapter(New ConcreteAdapteeA)
c1.Request()
Dim c2 As New Adapter(New ConcreteAdapteeB)
c2.Request()
'wait for user
Console.Readline()
End Sub
End Class
Adapter模式的几个要点:
1、Adapter模式主要应用于“希望复用一些现存的类,但是接口又与复用的环境要求不一致的情况”,在遗留代码复用、类库迁移等方面非常有用。
2、GoF23定义了两种Adapter模式的实现结构:对象适配器采用“对象组合”的方式,更符合松耦合精神。(
3、Adapter模式可以实现的非常灵活,不必拘泥于GoF23中定义的两种结构。例如,完全可以将Adapter模式中的“现存对象”作为新的接口方法参数,来达到适配的目的。
4、Adapter模式本身要求我们尽可能地使用“面向接口的编程”风格,这样才能在后期很方便地适配。
参考资料
《.NET设计模式(8):适配器模式(Adapter Pattern)》 TerryLee
《我的Design Pattern之旅[7]:使用泛型改進Adapter Pattern (中級)》 真 OO无双
《C#面向对象设计模式纵横谈系列课程(7)》 李建中老师
本文介绍了适配器模式的应用场景及其实现方式,包括对象适配器和类适配器等,展示了如何解决接口不兼容的问题,使现有类能够在新环境中复用。
6万+

被折叠的 条评论
为什么被折叠?



