大话设计模式之装饰模式

来源:互联网 发布:淘宝商城女装风衣 编辑:程序博客网 时间:2024/05/21 18:47

          装饰,字面意思是对生活用品或生活环境进行艺术加工的手法。它必须与所装饰的客体有机地结合,成为统一、和谐的整体,以便丰富艺术形象,扩大艺术表现力,加强审美效果,并提高其功能、经济价值和社会效益。我们编程世界中的装饰又有着怎样与众不同的解释呢?原来装饰模式是在不必改变原类文件和使用继承的情况下,动态地扩展一个对象的功能。它是通过创建一个包装对象,也就是装饰来包裹真实的对象。

        我们来看一个具体的例子,经过一个上午的消耗,加上昨天晚上熬夜看《出彩中国人》,早上赖床,没有去吃饭,那上午叫一个饿啊,于是发誓,再也不熬夜了,咳咳,到了晚上,拿起手机什么又都忘了,于是,想着赶紧下课,去吃饭,最好来一碗面条,来点儿辣椒再来点儿醋,那味道,呼呼流口水了,来到卖面条的地方,这个点儿来的人可真多啊,咱是好孩子,得排队是不是,顺便看一下标签上有哪些面条,哇塞面条的种类可真多啊,比如有雪菜肉丝面条,西红柿鸡蛋面条,小鸡蘑菇面条,听,我前面的小姑娘要了一碗西红柿鸡蛋面条,紧接着一个男孩要了一碗小鸡蘑菇面条,每个同学的选择是不同的,也就是需求是各种各样的,那么这种情况在我们的编程世界中如何实现呢,这个时候,排队的我想到了继承,如下图所示:

        

       这个时候如果我想要加醋和加辣椒的面条?我要怎么办,可以通过继承来实现扩展,但是这样的设计有点儿笨笨的,于是一种新设计模式--装饰模式就这样横空出世了,我们来看看装饰模式的结构图:

        

       装饰者模式呢,其实可以看做是一种在已有功能上动态添加新的功能的一种方式,在不用装饰者模式的前提下,如果要在已有的功能上添加新功能,一般都是可以使用继承的,但是,继承的缺点呢,在上面的例子中也暴露的很明显,同时,使用继承的话,添加功能不是动态的,因为子类完全继承了父类,而使用装饰者模式的话,您可以在客户端按照需求一个一个的包装对象,通过包装对象来添加新功能,这样便实现了动态添加新功能,比如,我可以对 Component 通过 ConcreteDecoratorA 来包装一个 State 状态,或者是通过 ConcreteDecoratorB 来包装一个新的行为(功能)Behavior ,以我们的面条例子为例,看看我们的程序是怎么实现的呢?

       先来看一下Eat类:

       

<span style="font-size:18px;">using System; namespace Decorator {     public abstract class  Noodle     {         /// <summary>         /// 在抽象类中只定义了一个抽象接口         /// 然后可以通过这个抽象接口来给对象动态的添加功能         /// </summary>         public abstract void ShowNoodle();     } }</span>
       然后就是一个Noodle类:

        

<span style="font-size:18px;">using System; namespace Decorator {     public class Noodle : Eat    {         private string name;         public Noodle(string name)         {             this.name = name;         }         /// <summary>         /// 给当前的对象添加一些功能         /// 比如这里就是指定了面条的名称         /// 这里添加的功能是静态添加的         /// </summary>         public override void ShowEat()         {             Console.WriteLine("面条名称为:{0}    ", this.name);         }     } }</span>
      下面再来看 DecoratorEat 类:

       

<span style="font-size:18px;">namespace Decorator {     public class DecoratorEat: Noodle    {         /// <summary>         /// 在装饰类中必须要保存一个对于对象的引用             /// </summary>         protected Eat eat;         public DecoratorEat(Eat eat)         {             this.eat = eat;         }         public override void ShowEat()         {             if (Eat != null)             {                                Eat.ShowEat();             }         }     } }</span>
           还有就是装饰类 Tomato:

           

<span style="font-size:18px;">using System; namespace Decorator {     public class Tomato : DecoratorEat    {               /// </summary>         /// <param name="Eat"></param>         public Tomato(Eat eat)             : base(eat)         {         }         public override void Showeat()         {            //首先必须要调用父类的 ShowEat             base.ShowEat();             //然后下面就可以添加新功能了             Console.WriteLine("加西红柿   ");         }     } }</span>
        装饰类鸡蛋和豆皮的代码跟上述装饰类西红柿雷同,再此不一一赘述,接下来,我们一起看看客户端的代码:

        

<span style="font-size:18px;">using System; using Decorator; namespace DecoratorTest {     class Program     {         static void Main(string[] args)         {             Noodle noodle = new Noodle("面条");             //给面条加西红柿,也就是使用西红柿来装饰面条             Tomato tomato = new Tomato(noodle);             //给加了西红柿的面条加鸡蛋,也就是使用加鸡蛋来装饰面条             Egg egg = new Egg(Tomato);             //显示出当前面条的状态             Egg.ShowNoodle();             Console.WriteLine();             noodle = new Noodle("面条");             tomato = new Tomato(noodle);             //给加了西红柿的面条加豆皮             Doupi doupi = new Doupi(Tomato);             //给加了西红柿和鸡蛋的面条加个豆皮             Doupi doupi = new Doupi(doupi);             doupi.ShowEat();             Console.ReadLine();         }     } }</span>
       通过装饰模式我们的小菜有着百搭的风格,而我也.......嘻嘻,再回到我们的装饰模式中来,装饰模式与继承关系的目的都是要扩展对象的功能,但是Decorator可以提供比继承更多的灵活性。 通过使用不同的具体装饰类以及这些装饰类的排列组合,设计师可以创造出很多不同行为的组合。设计之旅,未完待续......    

60 1