艾伟_转载:C# Design Patterns (3) - Decorator

Decorator Pattern (装饰模式)

装饰模式可「动态」地给一个对象添加一些额外的职责,提供有别于「继承」的另一种选择。就扩展功能而言,Decorator Pattern 透过 Aggregation (聚合) 的特殊应用,降低了类与类之间的耦合度,会比单独使用「继承」生成子类更为灵活。

一般用「继承」来设计子类的做法,会让程序变得较僵硬,其对象的行为,是在「编译」时期就已经「静态」决定的,而且所有的子类,都会继承到相同的行为;然而,若用「装饰模式」以及 UML 的 Aggregation 的设计,来扩展对象的行为,就能弹性地 (flexible) 将多个「装饰者」混合着搭配使用,而且是在「执行」时期「动态」地进行扩展。

此外,若用一般「继承」的做法,每当对象需要新行为时,必须修改既有的代码、重新编译;但若透过「装饰模式」,则无须修改既有代码。

The Decorator Pattern attaches additional responsibilities to an object dynamically. Decorators provide a flexible alternative to subclassing for extending functionality.
                                 - Design Patterns: Elements of Reusable Object-Oriented Software


图 1 此图为 Decorator 模式的经典 Class Diagram

01_Shell / Program.cs
using System;

namespace _01_Shell
{
    //客户端程序
    class Program
    {
        static void Main(string[] args)
        {
            ConcreteComponent c = new ConcreteComponent();
            ConcreteDecoratorA d1 = new ConcreteDecoratorA();
            ConcreteDecoratorB d2 = new ConcreteDecoratorB();

            //让 ConcreteDecorator 在运行时,动态地给 ConcreteComponent 增加职责
            d1.SetComponent(c);
            d2.SetComponent(d1);
            d2.Operation();

            Console.Read();
        }
    }

    //装饰者、被装饰者的共同基类
    abstract class Component
    {
        public abstract void Operation();
    }

    //被装饰者。具体被装饰对象。
    //此为在「执行」时期,会被 ConcreteDecorator 具体装饰者,「动态」添加新行为(职责)的对象
    class ConcreteComponent : Component
    {
        public override void Operation()
        {
            Console.WriteLine("具体被装饰对象的操作");
        }
    }

    //装饰者。
    //此为所有装饰者,应共同实现的抽象类或接口
    abstract class Decorator : Component
    {
        //以父类声明的字段。
        //实现 UML Class Diagram 的 Aggregation,指向 Component 对象的指针。
        protected Component component;

        public void SetComponent(Component component)
        {
            this.component = component;
        }

        public override void Operation()
        {
            if (component != null)
            {
                component.Operation();
            }
        }
    }

    //具体装饰者 A
    //此为在「执行」时期,替 ConcreteComponent「动态」添加新行为(职责)的对象
    class ConcreteDecoratorA : Decorator
    {
        //装饰者可以添加新的栏位
        private string addedState;

        public override void Operation()
        {
            base.Operation();
            addedState = "New State";
            Console.WriteLine("具体装饰对象 A 的操作");
        }
    }

    //具体装饰者 B
    //此为在「执行」时期,替 ConcreteComponent「动态」添加新行为(职责)的对象
    class ConcreteDecoratorB : Decorator
    {
        public override void Operation()
        {
            base.Operation();
            AddedBehavior();
            Console.WriteLine("具体装饰对象 B 的操作");
        }

        //装饰者可以添加新的方法
        private void AddedBehavior()
        {
        }
    }

} // end of namespace

/*
执行结果:

具体被装饰对象的操作
具体装饰对象 A 的操作
具体装饰对象 B 的操作

*/

上方图 1 的 Class Diagram,以及「Shell (壳)」示例中,ConcreteComponent 即为此一模式中的「被装饰者」,而 Decorator 抽象类及其具体子类 ConcreteDecoratorA、ConcreteDecoratorB 即为「装饰者」。此外,这个模式中最核心的就是 Decorator 这个抽象类,它用一个以父类 Component 声明的变量 component,实现 UML 中的 Aggregation (聚合,有的博文也统称为「组合」或「合成」),亦即为指向 Component 对象的指针,达到我们前述 - 「动态」进行扩展的目的。

至于其设计的原理,以下我引用博客园一位前辈 Justin 两年前所写博文的一段内容 [1],这段是我认为对 Decorator 模式极优的说明。读者亦可搭配参考上方代码里我添加的注释,稍后我会再补充说明。

--------------------------------------------------------

Decorator 是装饰者模式里非常特殊的一个类,它既继承于 Component【IS A关系】,又维护一个指向 Component 实例的引用【HAS A关系】,换个角度来说,Decorator 跟 Component 之间,既有动态组合关系,又有静态继承关系,WHY? 这里为什么要这么来设计?上面我们说过,组合的好处是可以在运行时给对象增加职责,Decorator【HAS A】Component 的目的,是让 ConcreteDecorator 可以在运行时动态地给 ConcreteComponent 增加职责,这一点相对来说还比较好理解;那么 Decorator 继承于 Component 的目的是什么?在这里继承的目的只有一个,那就是可以统一「装饰者」和「被装饰者」的接口,换个角度来说,不管是 ConcretComponent 还是 ConcreteDecorator,它们都是最顶层 Component 基类,用户代码可以把它们统一看作 Component 来处理,这样带来的更深一层好处就是,「装饰者」对象,对「被装饰者」对象的功能职责扩展,对用户代码来说是完全透明的,因为用户代码引用的都是 Component,所以就不会因为「被装饰者」对象在被装饰后,引用它的用户代码发生错误,实际上不会有任何影响,因为装饰前后,用户代码引用的都是 Component 类型的对象,这真是太完美了!「装饰模式」通过继承,实现统一了「装饰者」和「被装饰者」的接口,通过组合获得了在运行时动态扩展「被装饰者」对象的能力。

我们再举个生活中的例子,俗话说“人在衣着马在鞍”,把这用「装饰模式」的语境翻译一下,“人通过漂亮的衣服装饰后,男人变帅了,女人变漂亮了;”。对应上面的类图,这里「人」对应于 ConcreteComponent,而「漂亮衣服」则对应于 ConcreteDecorator;换个角度来说,人和漂亮衣服组合在一起【HAS A】,有了帅哥或美女,但是他们还是人【IS A】,还要做人该做的事情,但是可能会对异性更有吸引力了(扩展功能)!

--------------------------------------------------------

上方 Justin 前辈,其文章的「煮咖啡」示例 [1],是引用自 O'Reilly 出版社的「Head First 设计模式」这本书的第三章 [10]。该文的煮咖啡类图中,HouseBlend (家常咖啡)、DarkRoast (深度烘培咖啡)、Espresso (意大利特浓咖啡)、Decaf (无咖啡因咖啡),这四种咖啡 (饮料),即为「被装饰者」,等同本帖上图 1 中的 ConcreteComponent 类;该文类图中的 CondimentDecorator 抽象类,等同本帖上图 1 中最重要的 Decorator 抽象类,亦即「装饰者」的抽象定义;该文类图中的 Milk、Mocha、Soy、Whip 这四种调料 (调味品),即为具体的「装饰者」,亦即在本帖一开始提到,这四种调料,可弹性地 (flexible) 混合着搭配使用,而且是在「执行」时期「动态」地进行扩展,亦即动态地装饰 HouseBlend、DarkRoas、Espresso、Decaf 这四种咖啡。

接下来,我们用另一个简单的例子来实现 Decorator 模式,并改用 ASP.NET 网页程序来实现。类图及代码如下方图 2 所示,执行结果如下图 3 所示。

此为一个西餐牛排馆的计费程序,这间牛排馆有两种主菜 - 牛排和猪排,此为「被装饰者」;有四种副菜 - 面条、生菜沙拉、饮料 (热饮或冷饮)、甜点,此为「装饰者」。客人点餐时,可点一种主菜,副菜可点一份、可点多份,也可不点 (有弹性地将多个「装饰者」混合着搭配);每样主菜和副菜都有各自的价格,全部相加后,即为一或多位客人的用餐费用。而且我们希望,将来这个计费程序写好后,未来即使要修改价格,或添加新的主菜和副菜时,都不用再修改既有的程序。


图 2 示例 02_Steak.aspx.cs 的 Class Diagram

 

02_Steak.aspx.cs
using System;
using com.cnblogs.WizardWu.sample02;       //客戶端程序调用服务器端的组件和类

//客戶端程序
public partial class _02_Steak : System.Web.UI.Page
{
    protected void Page_Load(object sender, EventArgs e)
    {
        //点一客猪排,不需要副菜。并列出它的描述与价格
        Meal meal1 = new PorkChop();
        //Meal meal1 = new BeefSteak();
        Response.Write(meal1.Description + " = $ " + meal1.cost() + "
");

        //点一客猪排,副菜只要面条。并列出它的描述与价格
        Meal meal2 = new PorkChop();
        meal2 = new Noodle(meal2);          //用 Noodle 装饰它 (运行时动态地增加职责)
        Response.Write(meal2.Description + " = $ " + meal2.cost() + "
");

        //点一客猪排,因为这个人食量大,副菜要两份面条、一杯饮料(热饮)、一盘甜点。并列出它的描述与价格
        Meal meal3 = new PorkChop();
        meal3 = new Noodle(meal3);          //用 Noodle 装饰它
        meal3 = new Noodle(meal3);          //用第二个 Noodle 装饰它
        meal3 = new Drink(meal3, true);    //用 Drink 装饰它
        meal3 = new Dessert(meal3);         //用 Dessert 装饰它
        Response.Write(meal3.Description + " = $ " + meal3.cost() + "
");

        //第四个人不吃猪肉,因此主菜改点一客牛排,副菜要一盘沙拉、一杯饮料(冷饮)。并列出它的描述与价格
        Meal meal4 = new BeefSteak();
        meal4 = new Salad(meal4);            //用 Salad 装饰它 (运行时动态地增加职责)
        meal4 = new Drink(meal4, false);   //用 Drink 装饰它
        Response.Write(meal4.Description + " = $ " + meal4.cost() + "
");
    }
}

//服務器端程序
namespace com.cnblogs.WizardWu.sample02
{
    //装饰者(副菜)、被装饰者(主菜)的共同基类。类似前一例的 Component 抽象类
    abstract class Meal
    {
        protected string description = "西餐";

        public virtual string Description
        {
            get { return description; }
            set { description = value; }
        }

        abstract public int cost();        //必须在子类实作的抽象方法,除非该个子类也是抽象类
    }

    //主菜(被装饰者)。类似前一例的 ConcreteComponent 类
    class PorkChop : Meal                //主菜 - 猪排。以后执行时,才会动态被副菜装饰
    {
        public PorkChop()                  //构造函数
        {
            Description = "猪排";
        }

        public override int cost()         //具体对象的操作
        {
            return 130;                        //猪排的价格。现在不需要管「副菜」的价格,直接返回猪排的价格即可
        }
    }

    //主菜(被装饰者)。类似前一例的 ConcreteComponent 类
    class BeefSteak : Meal               //主菜 - 牛排。以后执行时,才会动态被副菜装饰
    {
        public BeefSteak()                 //构造函数
        {
            Description = "牛排";
        }

        public override int cost()         //具体对象的操作
        {
            return 150;                        //牛排的价格。现在不需要管「副菜」的价格,直接返回牛排的价格即可
        }
    }

    //装饰者。类似前一例的 Decorator 抽象类。此为所有「副菜(装饰者)」的父类。
    //功能一、未来所有可能添加的副菜,其共同的属性、行为,都可放在这个类里。
    //功能二、用来「分类」哪些是主菜,哪些是副菜。
    abstract class CondimentDecorator : Meal      //副菜,用来「动态」装饰主菜和 Meal 基类,亦即在运行时动态地替他们增加职责
    {
        //以父类声明的字段。
        //实现 UML Class Diagram 的 Aggregation,指向 Meal 对象的指针。
        protected Meal meal;

        public override string Description
        {
            get { return meal.Description + " + " + description; }
            set { description = value; }
        }
    }

    //副菜(装饰者)。具体装饰类 - 面条,用来动态装饰主菜 - 牛排或猪排
    class Noodle : CondimentDecorator            //类似前一例的 ConcreteDecoratorA
    {
        public Noodle(Meal meal)        //构造函数
        {
            Description = "面条";
            this.meal = meal;
        }

        public override int cost()         //具体装饰对象 A 的操作
        {
            return 50 + meal.cost();
        }
    }

    //副菜(装饰者)。具体装饰类 - 沙拉,用来动态装饰主菜 - 牛排或猪排
    class Salad : CondimentDecorator             //类似前一例的 ConcreteDecoratorB
    {
        public Salad(Meal meal)          //构造函数
        {
            Description = "生菜沙拉";
            this.meal = meal;
        }

        public override int cost()         //具体装饰对象 B 的操作
        {
            return 60 + meal.cost();
        }
    }

    //副菜(装饰者)。具体装饰类 - 饮料,用来动态装饰主菜 - 牛排或猪排
    class Drink : CondimentDecorator             //类似前一例的 ConcreteDecoratorC
    {
        private bool isHot;

        public bool IsHot
        {
            get { return isHot; }
        }

        public Drink(Meal meal, bool isHot)          //构造函数
        {
            Description = (isHot) ? "热饮" : "冷饮";
            this.meal = meal;
            this.isHot = isHot;
        }

        public override int cost()         //具体装饰对象 C 的操作。冷饮比热饮多收 20 块钱
        {
            return (isHot) ? (30 + meal.cost()) : (50 + meal.cost());
        }
    }

    //副菜(装饰者)。具体装饰类 - 甜点,用来动态装饰主菜 - 牛排或猪排
    class Dessert : CondimentDecorator          //类似前一例的 ConcreteDecoratorD
    {
        public Dessert(Meal meal)       //构造函数
        {
            Description = "甜点";
            this.meal = meal;
        }

        public override int cost()         //具体装饰对象 D 的操作
        {
            return 40 + meal.cost();
        }
    }

} // end of namespace

 


图 3 示例 02_Steak.aspx.cs 的执行结果。扩展功能时,主菜和副菜可任意混合搭配使用

原理与本帖之前提过的相同,将来店里若要推出 羊排、鱼排、…等新的主菜 (被装饰者) 时,只要增加一个类,去继承 Meal 这个抽象的基类即可;若要推出新的副菜 (装饰者) 也一样,只要增加一个类,去继承 CondimentDecorator 抽象类即可。我们透过这个重要的 CondimentDecorator 抽象类,实现 UML 的 Aggregation (聚合) 观念,以「装饰模式」取代传统「继承」的做法,也同时降低了「主菜」、「副菜」这两种类之间的耦合度。

这个 CondimentDecorator 抽象类的作用,还可将未来所有种类的副菜,一些「共同的」行为或职责写在里面。而且,它还可用来区分哪些类是主菜,哪些类是副菜,因为主菜、副菜都是继承自 Meal 这个最顶层的基类,若没有这个 CondimentDecorator 抽象类,将来 Class Diagram 变得很复杂时,会不易分辨某个类是主菜或副菜。

此外,也因为主菜 (被装饰者)、副菜 (装饰者) 都是继承自 Meal 这个最顶层的基类,所以客户端程序 (Page_Load) 在引用他们的对象时,把 new 出来的主菜实例、new 出来的副菜实例,再抛入其他副菜实例的构造函数中,也会相容、不会发生错误,在相互引用和「运行」时期的「动态」扩展上,变得很有弹性。

最后补充一点,Decorator 模式中,装饰者类对象,在组合时的「顺序」亦很重要。本帖图 1 中,ConcreteDecoratorA、ConcreteDecoratorB、ConcreteDecoratorC、... 等具体装饰者,在动态添加和组合时,在某些实际应用中必须依照一定的顺序,若顺序相反可能会导致程序执行结果不合理,但本帖所提供的几个例子中并不需要考虑到这点。

--------------------------------------------------------

Decorator Pattern 适用的情景: 

  • 你拥有一个已存在的组件类,却无法继承它 (subclassing)。
  • 能够动态地为对象添加职责 (添加状态和行为)。
  • 改变类中的成员和行为,但不影响其他对象。
  • 希望能便于职责的撤消。
  • 不想用「继承」来扩展行为。其中一种原因是避免当一些功能要交叉搭配引用时,单独用「继承」来设计会产生太多的子类、太复杂的类图结构 [1], [10];另一种考量可能是因为类的定义被隐藏,或类的定义不能用于生成子类。

Decorator Pattern 的优点:

 

  • 可避免单独使用「继承」时,在扩展时不够弹性,且可能衍生过多的子类。
  • 扩展时不需要修改既有的代码。
  • 可在执行时期,动态地添加新行为 (职责)。

Decorator Pattern 的缺点:

 

  • 可能会在程序中出现许多的小型类,亦即需要编写很多 ConcreteDecorator 类 (具体装饰者)。
  • 若过度使用 Decorator 模式,会让程序逻辑变得很复杂。
  • 别人较不易理解设计方式及代码,排查故障、追踪和调试也比较困难。

Decorator Pattern 的其他特性:

 

  • 每个要装饰的功能,都放在单独的类中。
  • 我们可以用无数个装饰者,去包装一个组件。
  • 「装饰者」可以在「被装饰者」前面或后面,添加自己的行为,甚至将「被装饰者」的行为整个取代掉,以达到特定的目的。
  • 「被装饰者」并不需要知道它已经被「装饰」过了,亦即 Component 类 (对象) 并不需要知道 Decorator 类 (对象) 的存在,且 Decorator 也仅仅认识 Component。

--------------------------------------------------------

最后再补充,在 Java I/O、.NET I/O、.NET System.Windows.Controls 命名空间中,很多地方都有用到 Decorator 模式来设计 [2], [5], [12]。例如我们查询 MSDN Library,会发现 .NET 3.x 版本的 Windows Forms 其 API 里,甚至还有增加一个新的 Decorator 类,如下:

System.Object
 System.Windows.Threading.DispatcherObject
  System.Windows.DependencyObject
   System.Windows.Media.Visual
    System.Windows.UIElement
     System.Windows.FrameworkElement
      System.Windows.Controls.Decorator
       System.Windows.Controls.Viewbox

 

System.Windows.Controls.Decorator 类:
提供在单个子元素(如 Border 或 Viewbox)上或周围应用效果的元素的基类。

http://msdn.microsoft.com/zh-cn/library/system.windows.controls.decorator.aspx
http://msdn.microsoft.com/zh-cn/library/system.windows.controls.decorator(VS.85).aspx

以下列出 Decorator Pattern,用于实际程序的四种方式 [12]:

  • 装饰模式非常适合于「图形程序」,亦适合于「视频和声音」,比如:视频流可用不同的比率进行压缩,而声音可以输入给同声传译服务。
  • 装饰模式如此有用,以致于 .NET 3.0 中,已经有实际的 Decorator 类了。如刚才提到的,在 System.Windows.Controls 命名空间中,提供了一些基类,可用于给其他的图形元素添加特殊效果,如:Border 类和 Viewbox 类。
  • 在如今的移动设备上,Web 浏览器及其他应用中,也大量运用 Decorator Pattern。比如这些设备上可以创建适合小屏幕显示的对象,跟标准桌面机上的浏览器相比,这些屏幕可能也含有滚动条,但不含有标题栏 [6]。
  • 从更一般的层次上,.NET 的 I/O API 中,到处都是装饰模式 [6],如下方的体系:
    System.Object
     System.MarshalByRefObject
      System.IO.Stream
       System.IO.BufferedStream
       System.IO.FileStream
       System.IO.MemoryStream
       System.Net.Sockets.NetworkStream
       System.Security.Cryptography.CryptoStream

上方体系的最后五个子类,有的就装饰了 Steram 这个父类 (如:BufferedStream 类),因为它们从它继承,同时又含有 Stream 类的实例,而且这个实例是子类被构造时传递进去的 (如同本帖第二个西餐店的示例中,副菜的构造函数的写法)。如下方 MSDN Library 代码的 BufferedStream 类,其构造函数的第一个参数,即为其父类 System.IO.Stream 的变量 stream。

BufferedStream 构造函数:

public BufferedStream(
 Stream stream
)

http://msdn.microsoft.com/zh-cn/library/system.io.bufferedstream.bufferedstream(VS.80).aspx 

 

--------------------------------------------------------

本帖的最后,提供一位 Java 大师 - 结城浩,所绘制的 Decorator Pattern 趣味四格漫画 [9],原地址如下:

Giko 猫谈 DP 四格漫画:
http://www.hyuki.com/dp/cat_Decorator.html
http://www.javaworld.com.tw/jute/post/view?bid=44&id=40923&sty=3

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

∧_∧  敲敲敲  ╱
(    )  ∧ ∧ < System.IO.Stream 是个典型的例子..恩....。
(    )  (,,゚Д゚)  ╲____________
______ (つ_つ____
|   日∇ ╲|ThinkPad|╲
|      =========  ╲

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
____________

| 喔~、是 Decorator Pattern 吗?
╲ __ __________
  |╱
  ∧_∧       ╱
  ( ・∀・)  ∧ ∧ < 你你是谁? ...有..有什么事嬷你?・・・
  (  ⊃ )  (゚Д゚;)  ╲____________
________(つ_つ____
|    日∇ ╲|ThinkPad|╲
|       =========  ╲

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
__________

| 将 Concrete Decorator 重迭起来达到想要的目的..恩
╲ __ ________
  |╱
  ∧_∧       ╱
  ( ・∀・)  ∧ ∧ < 恩...恩恩..没错....
 (     )  (;゚Д゚)  ╲____________
_____ (つ_つ____
|     日∇╲|ThinkPad|╲
|       =========  ╲

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
__________

| 乱做一堆细微的类的人就是你.恩.
╲ __ ________
  |╱
 ∧_∧       ╱
 ( ・∀・)  ∧ ∧ < 不..不是我..!!
 (  ⊃ )  (゚Д゚;) ╲____________
_____(つ_つ____
|   日∇ ╲|ThinkPad|╲
|      =========  ╲
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

时间: 2024-10-24 07:20:19

艾伟_转载:C# Design Patterns (3) - Decorator的相关文章

艾伟_转载:C# Design Patterns (4) - Proxy

本帖介绍 Proxy Pattern (代理模式). Proxy Pattern (代理模式) The Proxy Pattern provides a surrogate or placeholder for another object to control access to it...                                  - Design Patterns: Elements of Reusable Object-Oriented Software 在 Go

艾伟_转载:C# Design Patterns (5) - Prototype

本帖介绍 Prototype Pattern (原型模式),并以一个「人事招聘程序」作为示例来说明. --------------------------------------------------------本帖的示例下载点:http://files.cnblogs.com/WizardWu/090713.zip第一个示例为 Console Mode (控制台应用程序) 项目,第二个示例为 ASP.NET 网站项目.执行示例需要 Visual Studio 2008 或 IIS + .NE

艾伟_转载:C# Design Patterns (2) - Strategy

Strategy Pattern (策略模式) 所谓 Strategy Pattern 的精神,就是将策略 (算法) 封装为一个对象,易于相互替换,如同 USB 设备一样可即插即用:而不是将策略.具体的算法和行为,硬编码在某个类或客户程序中,导至事后的修改和扩展不易. 若有多种「策略」,就将这些个策略,和这些策略的算法.行为,封装在各个类中,并让这些类,去继承某个公用的抽象类或接口.接着在客户程序中,就可动态引用,且易于更换这些不同的「策略」,不会因为日后添加.修改了某一个「策略」,就得重新修改

艾伟_转载:C# Design Patterns (1) - Factory Method

Simple Factory Pattern (简单工厂模式) 特性: 把类的实例化工作,集中到一个「工厂类」去处理,亦即将 new instance 的工作,都交给一个「工厂」去处理,而不要分散写在各个类中. 客户端程序,与创建实例 (对象) 的工作必须隔离,亦即「解耦」,客户端程序只要专注于自己的业务逻辑.适用于客户端程序在开发过程中,尚无法预知要创建的具体类型. 产品具体的实现能和客户端隔离,便于事后抽换. Simple Factory Pattern (简单工厂模式).Factory M

艾伟:C# Design Patterns (3) - Decorator

Decorator Pattern (装饰模式) 装饰模式可「动态」地给一个对象添加一些额外的职责,提供有别于「继承」的另一种选择.就扩展功能而言,Decorator Pattern 透过 Aggregation (聚合) 的特殊应用,降低了类与类之间的耦合度,会比单独使用「继承」生成子类更为灵活. 一般用「继承」来设计子类的做法,会让程序变得较僵硬,其对象的行为,是在「编译」时期就已经「静态」决定的,而且所有的子类,都会继承到相同的行为:然而,若用「装饰模式」以及 UML 的 Aggregat

艾伟_转载:虚方法的使用

<编程絮语>之一 C#的语法脱胎于C++,因而保留了virtual关键字,可以定义一个虚方法(或虚属性).一个类的成员被定义为virtual,就意味着它在告诉自己的子类:我准备了一笔遗产,你可以全盘接受,也可以完全拒绝或者修改我的遗嘱.显然,虚方法授予子类的权利甚至大于抽象方法.子类面对抽象方法只有重写(override)的权利,而对于虚方法,它还可以选择完全继承. 毫无疑问,虚方法破坏了对象的封装性.如果不加约束的使用,会对调用方造成破坏,至少它有可能破坏子类与父类之间在外在行为上的一致性.

C# Design Patterns (3) - Decorator

Decorator Pattern (装饰模式) 装饰模式可「动态」地给一个对象添加一些额外的职责,提供有别于「继承」的另一种选择.就扩展功能而言,Decorator Pattern 透过 Aggregation (聚合) 的特殊应用,降低了类与类之间的耦合度,会比单独使用「继承」生成子类更为灵活. 一般用「继承」来设计子类的做法,会让程序变得较僵硬,其对象的行为,是在「编译」时期就已经「静态」决定的,而且所有的子类,都会继承到相同的行为:然而,若用「装饰模式」以及 UML 的 Aggregat

艾伟_转载:.NET设计模式:单件模式(Singleton Pattern)

概述 Singleton模式要求一个类有且仅有一个实例,并且提供了一个全局的访问点.这就提出了一个问题:如何绕过常规的构造器,提供一种机制来保证一个类只有一个实例?客户程序在调用某一个类时,它是不会考虑这个类是否只能有一个实例等问题的,所以,这应该是类设计者的责任,而不是类使用者的责任. 从另一个角度来说,Singleton模式其实也是一种职责型模式.因为我们创建了一个对象,这个对象扮演了独一无二的角色,在这个单独的对象实例中,它集中了它所属类的所有权力,同时它也肩负了行使这种权力的职责! 意图

艾伟_转载:数组排序方法的性能比较(上):注意事项及试验

昨天有朋友写了一篇文章,其中比较了List的Sort方法与LINQ中排序方法的性能,而最终得到的结果是"LINQ排序方法性能高于List.Sort方法".这个结果不禁让我很疑惑.因为List.Sort方法是改变容器内部元素的顺序,而LINQ排序后得到的是一个新的序列.假如两个排序方法的算法完全一致,LINQ排序也比对方多出元素复制的开销,为什么性能反而会高?如果LINQ排序的算法/实现更为优秀,那为什么.NET Fx不将List.Sort也一并优化一下呢?于是今天我也对这个问题进行了简