Dot Net设计模式—适配器模式
1.概述
1.1意图
使接口不兼容的类能够协同工作。通常情况下,这些接口不兼容的类在逻辑上的功能是一致或者相似的。例如采用RS232协议和TCP/IP的目的都是为了传输数据,支持这两种协议的API却是截然不同的。
1.2结构
适配器有类适配器和对象适配器两种类型,二者的意图相同,只是实现的方法和适用的情况不同。类适配器采用继承来实现,对象适配器则采用组合的方法来实现。
(1)类适配器:类适配器通过多生继承对一个接口与另一个接口进行匹配,其结构如图所示。
Target定义了Client使用的与特定领域相关的接口,Client通过调用Target实现某一个特定的操作。Adaptee是一个已经存在的类,需要与Target协同工作,这个接口需要适配。Adapter适配器适配Adaptee和Target接口。
在类适配器中,通过继承获得Adaptee中的方法。
类适配器的使用有一这限制,由于.NET不支持多重继承,即一个类只能有一个父类。因此当Target是一个类,而不是一个接口时无法实现类适配器,这时需要使用对象适配器。
(2)对象适配器:对象适配器采用对象组合,通过引用一个类与另一个类接口,其结构如图所示。
在对象适配器中通过组合获得Adaptee对象:
1.3使用场合
适配器模式适用于以下情况。
(1)需要使用一个已经存在的类,但接口与设计要求不符。
(2)希望创建一个可以复用的类,该类可以与其他不相关的类或者是将来不可预见的类协同工作。
在使用适配器时应注意理解适配器的方向性,即注意区分适配器中的Adaptee(适配对象)和Target(目标),在适配器的原理图中很容易看出Target,即被客户操作的是目标。
2.多媒体播放对象
回到上节的问题,我们在开发多媒体播放器时,希望可以采用RealPlay和 MS MediaPlay两种播放器。而二者的接口完全不同,并且我们可能在将来引入其他播放器。
为了使程序兼容两种播放器,我们定义了一个播放器的接口。然后用两个适配器分别实现这个接口,并调用RealPlay和 MS Media Player的API,这是典型的对象适配器。
采用对象适配器的结构如图所示。
代码如下:
采用类适配器的结构如图所示。
以RealPlay为例,代码如下:
3..NET中的适配器——DataAdapter
ADO.NET为统一的数据访问提供了多个接口和基类,其中最重要的接口之一是IdataAdapter。与之相对应的DataAdpter是一个抽象类,它是ADO.NET与具体数据库操作之间的数据适配器的基类。DataAdpter起到了数据库到DataSet桥接器的作用,使应用程序的数据操作统一到DataSet上,而与具体的数据库类型无关。甚至可以针对特殊的数据源编制自己的DataAdpter,从而使我们的应用程序与这些特殊的数据源相兼容。
例如,在多数据源的数据采集系统中,需要从自定义实时数据库中读出并处理数据。我们已经有了数据处理类和数据显示类,这些类是为关系数据库开发的,但同样可以用在实时数据显示中。由于这些类操作的是DataSet,因此我们可以定义一个特殊的适配器实现从实时数据库接口对象中填充DataSe,这样使得针对这些自定义的数据库的操作与一般的关系数据库完全一样。由于针对实时数据库只涉及查询,不涉及更新和删除,所以实现并不复杂,其结构如图所示。
这里省略了实现的代码。采用数据适配器可以使不同格式的数据源都可以被相同的上层应用使用,从而提高了系统的可扩展性和可维护性。
1.1意图
使接口不兼容的类能够协同工作。通常情况下,这些接口不兼容的类在逻辑上的功能是一致或者相似的。例如采用RS232协议和TCP/IP的目的都是为了传输数据,支持这两种协议的API却是截然不同的。
1.2结构
适配器有类适配器和对象适配器两种类型,二者的意图相同,只是实现的方法和适用的情况不同。类适配器采用继承来实现,对象适配器则采用组合的方法来实现。
(1)类适配器:类适配器通过多生继承对一个接口与另一个接口进行匹配,其结构如图所示。
Target定义了Client使用的与特定领域相关的接口,Client通过调用Target实现某一个特定的操作。Adaptee是一个已经存在的类,需要与Target协同工作,这个接口需要适配。Adapter适配器适配Adaptee和Target接口。
在类适配器中,通过继承获得Adaptee中的方法。
Pulic class Adapter:Adaptee,Target
{
#region Target 成员
public void Do( )
{
this.Execute( );
}
#endregion
}
{
#region Target 成员
public void Do( )
{
this.Execute( );
}
#endregion
}
类适配器的使用有一这限制,由于.NET不支持多重继承,即一个类只能有一个父类。因此当Target是一个类,而不是一个接口时无法实现类适配器,这时需要使用对象适配器。
(2)对象适配器:对象适配器采用对象组合,通过引用一个类与另一个类接口,其结构如图所示。
在对象适配器中通过组合获得Adaptee对象:
public class Adapter:Target
{
private Adaptee adaptee;
public Adapter(Adaptee ap)
{
adaptee = ap;
}
#region Target 成员
public void Do( )
{
adaptee.Execute( );
}
#endregion
}
{
private Adaptee adaptee;
public Adapter(Adaptee ap)
{
adaptee = ap;
}
#region Target 成员
public void Do( )
{
adaptee.Execute( );
}
#endregion
}
1.3使用场合
适配器模式适用于以下情况。
(1)需要使用一个已经存在的类,但接口与设计要求不符。
(2)希望创建一个可以复用的类,该类可以与其他不相关的类或者是将来不可预见的类协同工作。
在使用适配器时应注意理解适配器的方向性,即注意区分适配器中的Adaptee(适配对象)和Target(目标),在适配器的原理图中很容易看出Target,即被客户操作的是目标。
2.多媒体播放对象
回到上节的问题,我们在开发多媒体播放器时,希望可以采用RealPlay和 MS MediaPlay两种播放器。而二者的接口完全不同,并且我们可能在将来引入其他播放器。
为了使程序兼容两种播放器,我们定义了一个播放器的接口。然后用两个适配器分别实现这个接口,并调用RealPlay和 MS Media Player的API,这是典型的对象适配器。
采用对象适配器的结构如图所示。
代码如下:
'播放器的接口
Public Interface AudioPlayer
Sub DoPlay()
Sub DoStop()
Sub DoPause()
Property Source() As String
End Interface
'采用Real Player API的播放器
Public Class RealAuidoPlayer
Implements AudioPlayer
Private mAP As AxRealAudioObjects.AxRealAudio
Public Sub New(ByVal c As Control)
mAP = New AxRealAudioObjects.AxRealAudio
c.Controls.Add(mAP)
mAP.Visible = False
End Sub
Public Sub DoPause() Implements AudioPlayer.DoPause
mAP.DoPause()
End Sub
Public Sub DoPlay() Implements AudioPlayer.DoPlay
mAP.DoPlay()
End Sub
Public Sub DoStop() Implements AudioPlayer.DoStop
mAP.DoStop()
End Sub
Public Property Source() As String Implements AudioPlayer.Source
Get
Return mAP.Source
End Get
Set(ByVal Value As String)
mAP.Source = Value
End Set
End Property
End Class
'采用MS Media Player 的播放器类
Public Class MediaPlayer
Implements AudioPlayer
Private mAP As WMPLib.WindowsMediaPlayerClass
Private ms As String
Public Sub New()
mAP = New WMPLib.WindowsMediaPlayerClass
End Sub
Public Sub DoPause() Implements AudioPlayer.DoPause
mAP.pause()
End Sub
Public Sub DoPlay() Implements AudioPlayer.DoPlay
mAP.play()
End Sub
Public Sub DoStop() Implements AudioPlayer.DoStop
mAP.stop()
End Sub
Public Property Source() As String Implements AudioPlayer.Source
Get
Return mAP.URL
End Get
Set(ByVal Value As String)
mAP.URL = Value
mAP.pause()
End Set
End Property
End Class
Public Interface AudioPlayer
Sub DoPlay()
Sub DoStop()
Sub DoPause()
Property Source() As String
End Interface
'采用Real Player API的播放器
Public Class RealAuidoPlayer
Implements AudioPlayer
Private mAP As AxRealAudioObjects.AxRealAudio
Public Sub New(ByVal c As Control)
mAP = New AxRealAudioObjects.AxRealAudio
c.Controls.Add(mAP)
mAP.Visible = False
End Sub
Public Sub DoPause() Implements AudioPlayer.DoPause
mAP.DoPause()
End Sub
Public Sub DoPlay() Implements AudioPlayer.DoPlay
mAP.DoPlay()
End Sub
Public Sub DoStop() Implements AudioPlayer.DoStop
mAP.DoStop()
End Sub
Public Property Source() As String Implements AudioPlayer.Source
Get
Return mAP.Source
End Get
Set(ByVal Value As String)
mAP.Source = Value
End Set
End Property
End Class
'采用MS Media Player 的播放器类
Public Class MediaPlayer
Implements AudioPlayer
Private mAP As WMPLib.WindowsMediaPlayerClass
Private ms As String
Public Sub New()
mAP = New WMPLib.WindowsMediaPlayerClass
End Sub
Public Sub DoPause() Implements AudioPlayer.DoPause
mAP.pause()
End Sub
Public Sub DoPlay() Implements AudioPlayer.DoPlay
mAP.play()
End Sub
Public Sub DoStop() Implements AudioPlayer.DoStop
mAP.stop()
End Sub
Public Property Source() As String Implements AudioPlayer.Source
Get
Return mAP.URL
End Get
Set(ByVal Value As String)
mAP.URL = Value
mAP.pause()
End Set
End Property
End Class
采用类适配器的结构如图所示。
以RealPlay为例,代码如下:
1'采用Real Play API的播放器类,类适配器
2Public Class RealAudioPlayerClass
3 Inherits AxRealAudioObjects.AxRealAudio
4 Implements AudioPlayer
5
6 Public Sub New(ByVal c As Control)
7 c.Controls.Add(Me)
8 Me.Visible = False
9 End Sub
10
11 Public Sub DoPause() Implements AudioPlayer.DoPause
12 MyBase.DoPause()
13 End Sub
14
15 Public Sub DoPlay() Implements AudioPlayer.DoPlay
16 MyBase.DoPlay()
17 End Sub
18
19 Public Sub DoStop() Implements AudioPlayer.DoStop
20 MyBase.DoStop()
21 End Sub
22
23 Public Property Source() As String Implements AudioPlayer.Source
24 Get
25 Return MyBase.Source
26 End Get
27 Set(ByVal Value As String)
28 MyBase.Source = Value
29 End Set
30 End Property
31End Class
32
2Public Class RealAudioPlayerClass
3 Inherits AxRealAudioObjects.AxRealAudio
4 Implements AudioPlayer
5
6 Public Sub New(ByVal c As Control)
7 c.Controls.Add(Me)
8 Me.Visible = False
9 End Sub
10
11 Public Sub DoPause() Implements AudioPlayer.DoPause
12 MyBase.DoPause()
13 End Sub
14
15 Public Sub DoPlay() Implements AudioPlayer.DoPlay
16 MyBase.DoPlay()
17 End Sub
18
19 Public Sub DoStop() Implements AudioPlayer.DoStop
20 MyBase.DoStop()
21 End Sub
22
23 Public Property Source() As String Implements AudioPlayer.Source
24 Get
25 Return MyBase.Source
26 End Get
27 Set(ByVal Value As String)
28 MyBase.Source = Value
29 End Set
30 End Property
31End Class
32
3..NET中的适配器——DataAdapter
ADO.NET为统一的数据访问提供了多个接口和基类,其中最重要的接口之一是IdataAdapter。与之相对应的DataAdpter是一个抽象类,它是ADO.NET与具体数据库操作之间的数据适配器的基类。DataAdpter起到了数据库到DataSet桥接器的作用,使应用程序的数据操作统一到DataSet上,而与具体的数据库类型无关。甚至可以针对特殊的数据源编制自己的DataAdpter,从而使我们的应用程序与这些特殊的数据源相兼容。
例如,在多数据源的数据采集系统中,需要从自定义实时数据库中读出并处理数据。我们已经有了数据处理类和数据显示类,这些类是为关系数据库开发的,但同样可以用在实时数据显示中。由于这些类操作的是DataSet,因此我们可以定义一个特殊的适配器实现从实时数据库接口对象中填充DataSe,这样使得针对这些自定义的数据库的操作与一般的关系数据库完全一样。由于针对实时数据库只涉及查询,不涉及更新和删除,所以实现并不复杂,其结构如图所示。
这里省略了实现的代码。采用数据适配器可以使不同格式的数据源都可以被相同的上层应用使用,从而提高了系统的可扩展性和可维护性。