技术开发 频道

Dot Net设计模式—桥接模式

【IT168技术文档】
1.意图
    “将抽象部分与它的实现部分分离,使它们都可以独立地变化”,这是GOF在《设计模式》一书中的解释。这里的抽象和实现并不一定是同一层次的概念,例如数据库操作可以归结为“增加、删除和修改”。很多业务过程都是通过对数据库的操作实现的,例如“库存管理”中的“入库”,这个业务动作的软件实现可以描述为“在库存表中增加一条记录”,而“入库”和“插入记录”处于不同的业务层次。

2.使用场合
    在如下情况下可以使用桥接模式。
(1)不希望在业务和业务的软件实现之间存在因定的绑定关系。例如,不希望“入库”业务过程和具体的数据库访问技术或数据库管理系统有过于密切的关系。最好是数据库访问技术的升级,或数据库管理系统的改变对业务模块没有影响,甚至在运行期间可以通过动态绑定来选择不同数据库技术或数据库管理系统。
(2)希望类的抽象和实现部分可以扩充,进而实现不同的抽象接口和实现部分的组合。
(3)修改实现部分对用户不产生影响,即代码无须重新编译。
(4)复用实现部分。由于实现部分所处的层次较低,因此可以被多种业务模块复用。例如,数据库访问模块可以用在多种业务单元中。

3.结构
桥接模式的结构如图所示。
                        



(1)Abstraction:定义抽象类的接口并维护指向Implementor类的对象指针。
(2)RefinedAbstraction:扩充Abstraction定义的接口。
(3)Implementor:定义实现类的接口,该接口不一定要与Abstraction的接口完全一致。
事实上这两个接口可以完全不同。一般而言,Implementor接口仅提供基本操作,而Abstraction则定义了基于操作的较高层次的操作。
(4) ConcreteImplementor:实现Implementor接口并定义它的具体实现。
    为了更深入了解这个模式,我们来看一个具体的例子。在应用系统中经常有很多业务单元在很多业务模块中类似,隐含在背后的业务域模型相同。例如,“设备管理”中的“零部件管理”,“物资管理”中的“库房管理”,“实验室管理”中的“试剂管理”等都是“库存管理”。但由于业务场景的不同,导致业务中的细节不同,因此不能简单地复用。另外,“库存管理”软件的实现主要通过操作关系数据库来完成,我们希望保持软件系统与数据库访问技术以及数据库管理系统的独立性。

    为了实现以上要求,我们可以以桥接模式。即将抽象的“库存管理”和“数据库”操作作为具体的“库存管理”应用和具体的“数据库访问技术”的桥梁, 如下图所示。
                    


    从图中可以看出,我们将库存管理的抽象业务域模型封装在“抽象的库存管理”中。具体的库存管理业务如“生产车间库存管理”可以通过继承库存管理获得一般性的业务过程,然后根据具体的业务特点进行相应的扩展。
我们将数据库操作封装在dbOperation类中,具体执行访问数据库的各个指令,针对具体数据库的操作由该类的子类实现。

4.效果
采用桥接模式可以获得以下好处。
(1)将接口与实现分离:一个接口可以有若干实现,一个实现也可以为若干对象服务,表示逻辑的对象可以动态地与实现功能的对象组合。
(2)提高可扩充性:逻辑和实现都可以通过类层次的扩展进行扩充。
需要注意的是,逻辑和实现被封装在不同的对象中,逻辑对实现的引用是动态进行的。在实际中,需要分别用不同的工厂创建逻辑和实现,然后组装。
桥接模式同样可用在多种数据采集方式的场合,在有生产过程实时数据采集时,经常遇到多种数据采集的接口。为适应这种情况,可以采用桥接模式,其结构如图所示。
                  



    针对不同的数据源有不同的数据采集方式,有的采集系统需要直接从文件中读取数据,有的需要从远程Web服务器读取数据,有的需要从实时数据库读取数据,有的需要从关系数据库读取数据等。数据采集系统是低层平台,在上层应用中需要各种方式的显示形式,例如流程图、表格、曲线图和趋势图等。每种显示方式模块都可能从不同的数据源接收数据,即不同类型的数据源和数据显示方式应该可以任意组合。

    以一个来源于实际项目的例子说明。我们需要在Web页面上显示流程图,并且需要生成XML格式的流程图文件。其中采用简单工厂获得数据来源,数据来源标志保存在Web.config文件中。

    下图所示为应用的局部结构,其中采用了桥接模式。
                   



下面是部分代码,限于篇幅,仅列出结构部分。
定义clsAbstractReadData类,其中定义了需要获得数据的结构:
1 Imports System.IO 2 Imports System.Net 3 Imports System.Text 4 Public MustInherit Class clsAbstractReadDataClass clsAbstractReadData 5 Public MustOverride Function ReadData()Function ReadData(ByVal strDate As
strDate As DataSet 6 Protected mySourceDs As DataSet 7 Public Sub New()Sub New( ) 8 MySourceDS = New DataSet 9 Dim dt As DataTable 10 ‘这里定义数据结构,省略 11 End Sub 12 End Class 13
具体的读取类实现ReadData方法。下面是从文本文件中读取数据,其中给出了读取用逗号分隔数据的方法:
1 Public Class clsReadDataFromFileClass clsReadDataFromFile 2 Inherits ClsAbstractReadData 3 Private datafilepath As String 4 5 Public Sub New()Sub New(ByVal strpath As String) 6 MyBase.New( ) 7 Datafilepath = strpath 8 End Sub 9 Public Overrides Function ReadData()Function ReadData(ByVal strDate As String) As 10 System.Date.DataSet 11 ‘调用ReadDataFromFile从具体的文件中读取数据,省略 12 Return mysourceds 13 End Function 14 Private Sub ReadDataFromFile()Sub ReadDataFromFile(ByVal fn As String,,ByVal dt As
DataTable,ByVal 15 cn As Integer ) 16 ‘fn 数据文件名 17 ‘dt DtatTable 18 ‘cn 字段数 19 Dim fileNumber As Integer 20 FileNumber = FreeFile( ) 21 FileOpen(fileNumber, fn, OpenMode.Input) 22 Dim NextLine As String 23 I = 1 24 Do Until EOF(fileNumber) 25 NextLine = LineInput(fileNumber) 26 If I > 1 And Trim(NextLine) <> “ ” Then 27 Dim j As Integer 28 Dim r As DataRow = dt.NewRow 29 Dim s As String = “ ,” 30 Dim sp As Char( ) = s.ToCharArray 31 Dim rs As String( ) = NextLine.Split(sp) 32 For j = 0 To cn – 1 33 Dim v As String 34 Try 35 V = rs ( j ) 36 r.Item( j ) = Trim( v ) 37 Catch ex As Exception 38 r.Item( j ) = “ ” 39 End Try 40 Next 41 Dt.Rows.Add(r) 42 End If 43 I = I + 1 44 Loop 45 FileClose(fileNumber) 46End Sub 47Private Function IsFileExist()Function IsFileExist (ByVal fn As String) As Boolean 48 If FileSystem.Dir (fn) = “ ” Then Return False 49 Return True 50End Function 51End Class 52
下面是产生读取对象的简单工厂:
1 Public Class clsReaDataFactoryClass clsReaDataFactory 2 Pbulic Shared Function getDataReader()Function getDataReader ( ) As clsAbstractReadData 3 Dim datafilepath As String = 4 ConfigurationSettings.AppSettings (“DataFilePath”) 5 Dim strDataType As String = ConfigurationSettings.AppSettings (“DataType”) 6 Dim strHttp As String = ConfigurationSettings.AppSettings (“DataURL”) 7 Select Case strDataType 8 Case “http” 9 Dim mrd As clsReadDataFromRemoteFile 10 Mrd = New clsReadDataFromRemoteFile (strHttp) 11 Return mrd 12 Case Else 13 Dim mrd As clsReadDataFromFile 14 Mrd = New clsReadDataFromFile(datafilepath) 15 Return mrd 16 End Select 17 End Function 18end class
0
相关文章