大话设计模式之装饰模式

最后更新于:2022-04-01 06:32:56

 装饰,字面意思是对生活用品或生活环境进行艺术加工的手法。它必须与所装饰的客体有机地结合,成为统一、和谐的整体,以便丰富艺术形象,扩大艺术表现力,加强审美效果,并提高其功能、经济价值和社会效益。我们编程世界中的装饰又有着怎样与众不同的解释呢?原来装饰模式是在不必改变原类文件和使用继承的情况下,动态地扩展一个对象的功能。它是通过创建一个包装对象,也就是装饰来包裹真实的对象。 我们来看一个具体的例子,经过一个上午的消耗,加上昨天晚上熬夜看《出彩中国人》,早上赖床,没有去吃饭,那上午叫一个饿啊,于是发誓,再也不熬夜了,咳咳,到了晚上,拿起手机什么又都忘了,于是,想着赶紧下课,去吃饭,最好来一碗面条,来点儿辣椒再来点儿醋,那味道,呼呼流口水了,来到卖面条的地方,这个点儿来的人可真多啊,咱是好孩子,得排队是不是,顺便看一下标签上有哪些面条,哇塞面条的种类可真多啊,比如有雪菜肉丝面条,西红柿鸡蛋面条,小鸡蘑菇面条,听,我前面的小姑娘要了一碗西红柿鸡蛋面条,紧接着一个男孩要了一碗小鸡蘑菇面条,每个同学的选择是不同的,也就是需求是各种各样的,那么这种情况在我们的编程世界中如何实现呢,这个时候,排队的我想到了继承,如下图所示:         ![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2015-12-30_56837434b1c56.jpg) 这个时候如果我想要加醋和加辣椒的面条?我要怎么办,可以通过继承来实现扩展,但是这样的设计有点儿笨笨的,于是一种新设计模式--装饰模式就这样横空出世了,我们来看看装饰模式的结构图:         ![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2015-12-30_56837434c0f8e.jpg) 装饰者模式呢,其实可以看做是一种在已有功能上动态添加新的功能的一种方式,在不用装饰者模式的前提下,如果要在已有的功能上添加新功能,一般都是可以使用继承的,但是,继承的缺点呢,在上面的例子中也暴露的很明显,同时,使用继承的话,添加功能不是动态的,因为子类完全继承了父类,而使用装饰者模式的话,您可以在客户端按照需求一个一个的包装对象,通过包装对象来添加新功能,这样便实现了动态添加新功能,比如,我可以对 Component 通过 ConcreteDecoratorA 来包装一个 State 状态,或者是通过 ConcreteDecoratorB 来包装一个新的行为(功能)Behavior ,以我们的面条例子为例,看看我们的程序是怎么实现的呢? 先来看一下Eat类:         ~~~ using System;    namespace Decorator    {        public abstract class  Noodle        {            ///             /// 在抽象类中只定义了一个抽象接口            /// 然后可以通过这个抽象接口来给对象动态的添加功能            ///             public abstract void ShowNoodle();        }    }   ~~~ 然后就是一个Noodle类: ~~~ using System;    namespace Decorator    {        public class Noodle : Eat       {            private string name;            public Noodle(string name)            {                this.name = name;            }            ///             /// 给当前的对象添加一些功能            /// 比如这里就是指定了面条的名称            /// 这里添加的功能是静态添加的            ///             public override void ShowEat()            {                Console.WriteLine("面条名称为:{0}    ", this.name);            }        }    }   ~~~ 下面再来看 DecoratorEat 类: ~~~ namespace Decorator    {        public class DecoratorEat: Noodle       {            ///             /// 在装饰类中必须要保存一个对于对象的引用                   ///             protected Eat eat;            public DecoratorEat(Eat eat)            {                this.eat = eat;            }            public override void ShowEat()            {                if (Eat != null)                {                                      Eat.ShowEat();                }            }        }    }   ~~~ 还有就是装饰类 Tomato: ~~~ using System;    namespace Decorator    {        public class Tomato : DecoratorEat       {                     ///             ///             public Tomato(Eat eat)                : base(eat)            {            }            public override void Showeat()            {               //首先必须要调用父类的 ShowEat                base.ShowEat();                //然后下面就可以添加新功能了                Console.WriteLine("加西红柿   ");            }        }    }   ~~~ 装饰类鸡蛋和豆皮的代码跟上述装饰类西红柿雷同,再此不一一赘述,接下来,我们一起看看客户端的代码: ~~~ 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();            }        }    }   ~~~ 通过装饰模式我们的小菜有着百搭的风格,而我也.......嘻嘻,再回到我们的装饰模式中来,装饰模式与继承关系的目的都是要扩展对象的功能,但是Decorator可以提供比继承更多的灵活性。 通过使用不同的具体装饰类以及这些装饰类的排列组合,设计师可以创造出很多不同行为的组合。设计之旅,未完待续......    
';