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

2.2结构
        修饰一个对象后,其接口不应该发生变化;否则这个对象不能被原有调用者使用,修饰失去了意义。由此引出了装饰模式结构最重要的一点,即装饰者和被装饰者具有相同的接口。换句话说,动态增加的功能不应该破坏已有的接口。
装饰模式的结构如下图所示。
                                             用实例解说Dot Net设计模式——装饰模式
                                                           装饰模式的结构图
(1)Component:定义一个对象接口,可以动态添加这些对象的功能。
(2)ConcreteComponent:定义一个对象,可以为其添加一些功能。
(3)Decorator:维持一个对Component对象的引用,并定义与Component接口一致的接口。
(4)ConcreteDecorator:为组件添加功能。

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

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

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

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

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

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

在另一个装饰器中如下定义了可以使被装饰者滚动显示的SubDecoratorB.
用实例解说Dot Net设计模式——装饰模式Public Class SubDecoratorB
用实例解说Dot Net设计模式——装饰模式    Inherits Decorator
用实例解说Dot Net设计模式——装饰模式
用实例解说Dot Net设计模式——装饰模式    Protected WithEvents Top As System.Web.UI.WebControls.Literal
用实例解说Dot Net设计模式——装饰模式    Protected WithEvents Buttom As System.Web.UI.WebControls.Literal
用实例解说Dot Net设计模式——装饰模式    Protected WithEvents cp As System.Web.UI.WebControls.Panel
用实例解说Dot Net设计模式——装饰模式
用实例解说Dot Net设计模式——装饰模式#Region 
" Web 窗体设计器生成的代码 "
用实例解说Dot Net设计模式——装饰模式
用实例解说Dot Net设计模式——装饰模式    
'该调用是 Web 窗体设计器所必需的。
用实例解说Dot Net设计模式——装饰模式
    <System.Diagnostics.DebuggerStepThrough()> Private Sub InitializeComponent()
用实例解说Dot Net设计模式——装饰模式
用实例解说Dot Net设计模式——装饰模式    End Sub
用实例解说Dot Net设计模式——装饰模式
用实例解说Dot Net设计模式——装饰模式    
'注意: 以下占位符声明是 Web 窗体设计器所必需的。
用实例解说Dot Net设计模式——装饰模式
    '不要删除或移动它。
用实例解说Dot Net设计模式——装饰模式
    Private designerPlaceholderDeclaration As System.Object
用实例解说Dot Net设计模式——装饰模式
用实例解说Dot Net设计模式——装饰模式    Private Sub Page_Init(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Init
用实例解说Dot Net设计模式——装饰模式        
'CODEGEN: 此方法调用是 Web 窗体设计器所必需的
用实例解说Dot Net设计模式——装饰模式
        '不要使用代码编辑器修改它。
用实例解说Dot Net设计模式——装饰模式
        InitializeComponent()
用实例解说Dot Net设计模式——装饰模式        Me.ContentPane 
= Me.cp
用实例解说Dot Net设计模式——装饰模式    End Sub
用实例解说Dot Net设计模式——装饰模式
用实例解说Dot Net设计模式——装饰模式#End Region
用实例解说Dot Net设计模式——装饰模式
用实例解说Dot Net设计模式——装饰模式    Private Sub Page_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
用实例解说Dot Net设计模式——装饰模式        
'在此处放置初始化页的用户代码
用实例解说Dot Net设计模式——装饰模式
        If Me.Control <> "" Then
用实例解说Dot Net设计模式——装饰模式            Dim c As UserControl 
= LoadControl(Me.Control)
用实例解说Dot Net设计模式——装饰模式            Me.AddControl(c)
用实例解说Dot Net设计模式——装饰模式            Me.Top.Text 
= ShowRollBegin("100")
用实例解说Dot Net设计模式——装饰模式            Me.Buttom.Text 
= ShowRollEnd()
用实例解说Dot Net设计模式——装饰模式
用实例解说Dot Net设计模式——装饰模式        End If
用实例解说Dot Net设计模式——装饰模式    End Sub
用实例解说Dot Net设计模式——装饰模式
用实例解说Dot Net设计模式——装饰模式    Private Function ShowRollBegin(ByVal strDisplayHeight) As String
用实例解说Dot Net设计模式——装饰模式        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()'>"
用实例解说Dot Net设计模式——装饰模式    End Function
用实例解说Dot Net设计模式——装饰模式
用实例解说Dot Net设计模式——装饰模式    Private Function ShowRollEnd() As String
用实例解说Dot Net设计模式——装饰模式        Return 
"</marquee>"
用实例解说Dot Net设计模式——装饰模式    End Function
用实例解说Dot Net设计模式——装饰模式End Class
用实例解说Dot Net设计模式——装饰模式

我们定义一个很简单的HelloWorld用户组件用来测试,这个组件没有后台代码,仅仅有一个Lable组件:
<asp:Label Runat="server" > 用实例解说Dot Net设计模式——装饰模式    Private Sub Page_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
用实例解说Dot Net设计模式——装饰模式        
'在此处放置初始化页的用户代码
用实例解说Dot Net设计模式——装饰模式
        Dim c As Decorator = LoadControl("SubDecorator.ascx")
用实例解说Dot Net设计模式——装饰模式        Dim d As Decorator 
= LoadControl("SubDecoratorB.ascx")
用实例解说Dot Net设计模式——装饰模式        d.Control 
= "HelloWorld.ascx"
用实例解说Dot Net设计模式——装饰模式        Me.Controls.Add(c)
用实例解说Dot Net设计模式——装饰模式        c.AddControl(d)
用实例解说Dot Net设计模式——装饰模式    End Sub

相关文章: