大话设计模式之装饰模式

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

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

        大话设计模式之装饰模式_第1张图片

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

        大话设计模式之装饰模式_第2张图片

       装饰者模式呢,其实可以看做是一种在已有功能上动态添加新的功能的一种方式,在不用装饰者模式的前提下,如果要在已有的功能上添加新功能,一般都是可以使用继承的,但是,继承的缺点呢,在上面的例子中也暴露的很明显,同时,使用继承的话,添加功能不是动态的,因为子类完全继承了父类,而使用装饰者模式的话,您可以在客户端按照需求一个一个的包装对象,通过包装对象来添加新功能,这样便实现了动态添加新功能,比如,我可以对 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可以提供比继承更多的灵活性。 通过使用不同的具体装饰类以及这些装饰类的排列组合,设计师可以创造出很多不同行为的组合。设计之旅,未完待续......     

你可能感兴趣的:(设计模式)