用实例解说Dot Net设计模式——装饰模式

本文主要介绍了装饰模式,包括其概念、结构、适用场景、实现注意事项及优缺点。在不改变对象前提下,动态增加其功能可采用该模式,且装饰者和被装饰者需有相同接口。还通过网页组件装饰器和.NET 中 BufferedStream 两个实例,解说了装饰模式的应用。

1.装饰模式的概述
2.1 什么是装饰模式
        在不改变对象的前提下,动态增加其功能,即我们不希望改变原有的类,或采用创建子类的方法增加功能,这种情况下需要采用装饰模式。

2.2结构
        修饰一个对象后,其接口不应该发生变化;否则这个对象不能被原有调用者使用,修饰失去了意义。由此引出了装饰模式结构最重要的一点,即装饰者和被装饰者具有相同的接口。换句话说,动态增加的功能不应该破坏已有的接口。
装饰模式的结构如下图所示。
                                             %E8%A3%85%E9%A5%B0%E6%A8%A1%E5%BC%8F%E7%BB%93%E6%9E%84%E5%9B%BE.jpg
                                                           装饰模式的结构图
(1)Component:定义一个对象接口,可以动态添加这些对象的功能。
(2)ConcreteComponent:定义一个对象,可以为其添加一些功能。
(3)Decorator:维持一个对Component对象的引用,并定义与Component接口一致的接口。
(4)ConcreteDecorator:为组件添加功能。

2.3 什么情况下是用装饰模式
       以下情况使用装饰模式。
   (1)在不影响其他对象的情况下,以动态且透明的方式添加单个对象的功能。
   (2)处理那些可以撤销的功能。
   (3)不能采用生成子类的方法扩充时。

2.4实现时的注意事项
        实现时的注意事项如下。
(1)接口的一致性:装饰模式中被装饰对象对用户而言是透明的,用户仍然可以直接访问被装饰对象,并且装饰后的对象在访问时不就变化。如果接口不一致,尽管也达到了为对象增加功能的目的,但并不是装饰模式。
(2)保持被装饰类的简单性:被装饰类需要功能单一,这样才能使结构更灵活。比如显示最新新闻的组件,由标题和主体组成。

其中的核心组件应该显示若干条最近的新闻,我们可以用一个组件显示新闻,加一个显示标题和样式。解决问题的方法是核心组件保持最小的功能,显示新闻标题,每个装饰器也只完成一项功能。我们可以增加一个显示more按钮的装饰器,使得装饰器可以通过组合完成更多的功能。

 2.5效果
使用装饰模式的优点是比静态继承灵活,并可避免在层次结构高层的类有太多的特征;缺点是产生许多小对象。

2.用一个实例来解说装饰模式
        做BS的朋友们都会遇到网页组件装饰器的实现问题,我们希望为用户自定义组件创建可以通用的装饰器。为此需要定义一个装饰器的基类,代码如下:

 1None.gifPublic Class Decorator
 2None.gif    Inherits System.Web.UI.UserControl
 3None.gif    Private _Control As String
 4None.gif    Private _ContentPane As Web.UI.Control
 5None.gif    Public Property Control() As String
 6None.gif        Get
 7None.gif            Return _Control
 8None.gif        End Get
 9None.gif        Set(ByVal Value As String)
10None.gif            _Control = Value
11None.gif        End Set
12None.gif    End Property
13None.gif    Public Property ContentPane() As Web.UI.Control
14None.gif        Get
15None.gif            Return _ContentPane
16None.gif        End Get
17None.gif        Set(ByVal Value As Web.UI.Control)
18None.gif            _ContentPane = Value
19None.gif        End Set
20None.gif    End Property
21None.gif
22None.gif    Public Sub AddControl(ByVal c As UserControl)
23None.gif        _ContentPane.Controls.Add(c)
24None.gif    End Sub
25None.gifEnd Class
26None.gif
首先需要注意Decorator必须与被装饰者具有相同的接口,因此它是UserControl的子类。在Decorator中定义了装载被装饰者的方法AddControl,和装载被装饰者的容器ContentPane。
在具体的装饰者中,后台的可执行代码很少,主要定义装饰界面,在SubDecorator中定义了带有图形边框的界面:
 1None.gifPublic Class SubDecorator
 2None.gif    Inherits Decorator
 3None.gif    <System.Diagnostics.DebuggerStepThrough()> Private Sub InitializeComponent()
 4None.gif
 5None.gif    End Sub
 6None.gif    Protected WithEvents cp As System.Web.UI.HtmlControls.HtmlTableCell
 7None.gif    Private designerPlaceholderDeclaration As System.Object
 8None.gif    Private Sub Page_Init(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Init
 9None.gif        InitializeComponent()
10None.gif        Me.ContentPane = Me.cp
11None.gif    End Sub
12None.gif    Public Sub Page_load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
13None.gif        If Me.Control <> "" Then
14None.gif            Dim c As UserControl = LoadControl(Me.Control)
15None.gif            Me.AddControl(c)
16None.gif        End If
17None.gif    End Sub
18None.gifEnd Class

在另一个装饰器中如下定义了可以使被装饰者滚动显示的SubDecoratorB.
None.gifPublic Class SubDecoratorB
None.gif    Inherits Decorator
None.gif
None.gif    Protected WithEvents Top As System.Web.UI.WebControls.Literal
None.gif    Protected WithEvents Buttom As System.Web.UI.WebControls.Literal
None.gif    Protected WithEvents cp As System.Web.UI.WebControls.Panel
None.gif
None.gif#Region 
" Web 窗体设计器生成的代码 "
None.gif
None.gif    
'该调用是 Web 窗体设计器所必需的。
None.gif
    <System.Diagnostics.DebuggerStepThrough()> Private Sub InitializeComponent()
None.gif
None.gif    End Sub
None.gif
None.gif    
'注意: 以下占位符声明是 Web 窗体设计器所必需的。
None.gif
    '不要删除或移动它。
None.gif
    Private designerPlaceholderDeclaration As System.Object
None.gif
None.gif    Private Sub Page_Init(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Init
None.gif        
'CODEGEN: 此方法调用是 Web 窗体设计器所必需的
None.gif
        '不要使用代码编辑器修改它。
None.gif
        InitializeComponent()
None.gif        Me.ContentPane 
= Me.cp
None.gif    End Sub
None.gif
None.gif#End Region
None.gif
None.gif    Private Sub Page_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
None.gif        
'在此处放置初始化页的用户代码
None.gif
        If Me.Control <> "" Then
None.gif            Dim c As UserControl 
= LoadControl(Me.Control)
None.gif            Me.AddControl(c)
None.gif            Me.Top.Text 
= ShowRollBegin("100")
None.gif            Me.Buttom.Text 
= ShowRollEnd()
None.gif
None.gif        End If
None.gif    End Sub
None.gif
None.gif    Private Function ShowRollBegin(ByVal strDisplayHeight) As String
None.gif        Return 
"<marquee style='bottom:0px;height:'" & strDisplayHeight & "px;top:0px' id='News' scrollamount=1 scrolldelay=10 behavior='scroll' direction='up' onmouseover='this.stop()' onmouseout='this.start()'>"
None.gif    End Function
None.gif
None.gif    Private Function ShowRollEnd() As String
None.gif        Return 
"</marquee>"
None.gif    End Function
None.gifEnd Class
None.gif

我们定义一个很简单的HelloWorld用户组件用来测试,这个组件没有后台代码,仅仅有一个Lable组件:
<asp:Label Runat="server" id="Label2">HelloWorld</asp:Label>
我们用上面的两个装饰器装饰这个组件:
None.gif    Private Sub Page_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
None.gif        
'在此处放置初始化页的用户代码
None.gif
        Dim c As Decorator = LoadControl("SubDecorator.ascx")
None.gif        Dim d As Decorator 
= LoadControl("SubDecoratorB.ascx")
None.gif        d.Control 
= "HelloWorld.ascx"
None.gif        Me.Controls.Add(c)
None.gif        c.AddControl(d)
None.gif    End Sub


感兴趣的朋友可以做一个例子看看效果,别看上面一大堆代码,其实仔细观察不难看出实际上是几个UserControl的相互套用来实现装饰模式的。

3.我们在看一个.NET中的装饰模式实例
        BufferedStream是经典的装饰模式,GOF在《设计模式》中已有介绍。并且在多种语言平台上都有相同的实现,在.NET中也不例外。
        BufferedStream的作用是为另一流上的读写操作添加一个缓冲层,缓冲区是内存中的字节块,用于缓存数据。从而减少对操作系统的调用次数,缓冲区可提高读取和写入性能。
        Stream是流的基类,抽象了对流的操作。根据流的来源和性质的不同,Stream的子类有System.Data.OracleClient.OracleBFile,System.Data.OracleClient.OracleLob,System.
IO.BufferedStream,System.IO.FileStream,System.IO.MemoryStream,System.Net.Sockets.NetworkStream和System.Security.Cryptography.CryptoStream。
        如FileStream可以打开一个文件并以流的方式读写文件,MemoryStream读写内存中的数据流,而NetworkStream则操作Scokets连接的TCP流。其中,BufferedStream非常特殊,它不直接创建英雄模范种类型的流,而是在已有流上执行附加的操作。由于它继承了Stream,因此使用上与一般的流没有不同,只是为现有的流增加了缓冲功能。
        通过采用装饰模式,BufferedStream使Stream具有了缓存功能而不用改动接口。这就是装饰模式所要达到的效果。这里就不再举具体的例子了,其实很简单,朋友可以自己试着写一下.

 


 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值