首页 > 程序开发 > Web开发 > ASP.Net >

步步为营 .NET 设计模式学习笔记 十四、Decorator(装饰模式)

2011-04-23

概述 在软件系统中,有时候我们会使用继承来扩展对象的功能,但是由于继承为类型引入的静态特质,使得这种扩展方式缺乏灵活性;并且随着子类的增多(扩展功能的增多),各种子类的组合(扩展功能的组合)会导致更多子类的膨胀。如何使

概述

在软件系统中,有时候我们会使用继承来扩展对象的功能,但是由于继承为类型引入的静态特质,使得这种扩展方式缺乏灵活性;并且随着子类的增多(扩展功能的增多),各种子类的组合(扩展功能的组合)会导致更多子类的膨胀。如何使“对象功能的扩展”能够根据需要来动态地实现?同时避免“扩展功能的增多”带来的子类膨胀问题?从而使得任何“功能扩展变化”所导致的影响将为最低?这就是本文要讲的Decorator模式。

一个场景是我们要为一个对象动态添加新的职责,这个职责并不修改原有的行为,而是在原有行为基础上添加新的功能,就好比装饰工人为一座新居的墙上涂抹上色彩缤纷的颜料一般。

意图

动态地给一个对象添加一些额外的职责。就增加功能来说,Decorator模式相比生成子类更为灵活。[GOF 《设计模式》]

<Design Pattern>结构图

图1 Decorator模式结构图

在装饰模式中的各个角色有:

  • 抽象构件(Component)角色:给出一个抽象接口,以规范准备接收附加责任的对象。
  • 具体构件(Concrete Component)角色:定义一个将要接收附加责任的类。
  • 装饰(Decorator)角色:持有一个构件(Component)对象的实例,并定义一个与抽象构件接口一致的接口。
  • 具体装饰(Concrete Decorator)角色:负责给构件对象"贴上"附加的责任。

生活中的例子

装饰模式动态地给一个对象添加额外的职责。不论一幅画有没有画框都可以挂在墙上,但是通常都是有画框的,并且实际上是画框被挂在墙上。在挂在墙上之前,画可以被蒙上玻璃,装到框子里;这时画、玻璃和画框形成了一个物体。

图2 使用有画框的画作为例子的装饰模式对象图

示例用例图

在超市里,平常节日都有优惠活动,不同节日有不同优惠活动,我们用装饰模式写一个超市节日打折的例子,用例图如下:

image

代码设计

先创建SuperMarket.cs:

 public abstract class SuperMarket
    {
        private int _CategoryNumber;

        public int CategoryNumber
        {
            get { return _CategoryNumber; }
            set { _CategoryNumber = value; }
        }

        private string _Name;

        public string Name
        {
            get { return _Name; }
            set { _Name = value; }
        }

        private double _Discount;

        public double Discount
        {
            get { return _Discount; }
            set { _Discount = value; }
        }

        private string _Festival;

        public string Festival
        {
            get { return _Festival; }
            set { _Festival = value; }
        }

        public abstract string ShowInfo();
    }

再创建Decorator.cs:

    public abstract class Decorator : SuperMarket
    {
        protected SuperMarket superMarker;

        public Decorator(SuperMarket superMarker)
        {
            this.superMarker = superMarker;
        }

        public override string ShowInfo()
        {
            return superMarker.ShowInfo();
        }
    }

再创建WalMart .cs:

   public  class WalMart:SuperMarket
    {
       public WalMart()
       {
           this.CategoryNumber = 1000;
           this.Discount = 0.95;
           this.Name = "沃尔玛";
           this.Festival = "平常";
       
       }
        public override string ShowInfo()
        {
            StringBuilder strBuilder = new StringBuilder();
            strBuilder.AppendFormat("在{0}超市,{1}节日期间,折扣为{2}的商品种类有{3}类
.
", this.Name,this.Festival, this.Discount, this.CategoryNumber);
            return strBuilder.ToString();
        }
    }
 
再创建MidAutumnFestival.cs:
    public class MidAutumnFestival : Decorator
    {
        public MidAutumnFestival(SuperMarket superMarket)
            : base(superMarket)
        {

        }
        public void Preferential()
        {
            superMarker.Discount = 0.95;
            superMarker.CategoryNumber = 1500;
            superMarker.Festival = "中秋节";
        }

        public string MoonCake()
        {
            return "期间所有月饼8折优惠";
        }
    }

再创建SpringFestival.cs:

    public class SpringFestival : Decorator
    {
        public SpringFestival(SuperMarket supermarket)
            : base(supermarket)
        {

        }

        public void Preferential()
        {

            superMarker.Discount = 0.9;
            superMarker.CategoryNumber = 2100;
            superMarker.Festival = "春节";
        }

        public string GiftPreferential()
        {
            return "期间有100种礼品类商品8折优惠.";
        }
    }

最后再调用:

   public partial class Run : Form
    {
        public Run()
        {
            InitializeComponent();
        }

        private void btnRun_Click(object sender, EventArgs e)
        {
       
            //-------------------------------------

            SuperMarket superMarket = new WalMart();
            rtbResult.AppendText(superMarket.ShowInfo()+"
");
            SpringFestival springFestival = new SpringFestival(superMarket);
            springFestival.Preferential();
            rtbResult.AppendText(springFestival.ShowInfo());
            rtbResult.AppendText(springFestival.GiftPreferential()+"

");
 MidAutumnFestival midAutumnFestival = new MidAutumnFestival(superMarket);
            midAutumnFestival.Preferential();
            rtbResult.AppendText(midAutumnFestival.ShowInfo());
            rtbResult.AppendText(midAutumnFestival.MoonCake() + "

");

        }
    }

结果如下图:

热点推荐