对装饰模式(Decorator)的解读

看过好多对装饰模式的讲解,他们几乎都有一句相同的话:对现有类功能的扩展。不知道大家怎么理解这句话的,之前我把”对功能的扩展“理解成”加功能=加方法“,比如Person类本来有两个功能:Eat 和 Run ,使用装饰模式后,可以再加一个功能:Sleep,这显然是不能的。增加Sleep意味着修改接口,装饰模式的功能并不是这样,那是怎样的呢?

还拿Person类来说明,比如现在有个需求:在吃饭前要洗手。 ”洗手“这个功能就是对Eat功能的扩展,添加“洗手”这个功能可以通过装饰模式添加,又比如吃完后,“男人要刷锅刷碗”, “刷锅刷碗”这个功能要添加给男人身上,也可以通过装饰模式动态给男人扩展这个功能,这个功能何时调用呢,当然是在吃饭的时候了,也就是调用Eat的时候,所以这些代码要写到Eat方法里。

再举个汽车的例子:

IMachine 接口是机器的接口,包含:Start()和Stop()两个功能。Car是IMachine的一个实现,SUVCar是Car的一个实现;

类:

1     /// <summary>
2     /// 机器
3     /// </summary>
4     interface IMachine
5     {
6         void Start();
7         void Stop();
8     }

IMachine

 1     /// <summary>
 2     /// 汽车
 3     /// </summary>
 4     abstract class Car : IMachine
 5     {
 6
 7         public abstract void Start();
 8
 9         public abstract void Stop();
10     }
11
12     /// <summary>
13     /// suv汽车
14     /// </summary>
15     class SUVCar : Car
16     {
17         public override void Start()
18         {
19             Console.WriteLine("我是SUV,发动机启动");
20         }
21
22         public override void Stop()
23         {
24             Console.WriteLine("我是SUV,发动机熄火");
25         }
26     }

Car 和 SUVCar

这样的话,在Program里直接调用:

 1     class Program
 2     {
 3         static void Main(string[] args)
 4         {
 5             Console.WriteLine("****汽车的功能****");
 6             IMachine car = new SUVCar();   //SUV汽车的功能
 7             ControlMachine(car);
 8
 9             Console.WriteLine("");
10             Console.ReadLine();
11         }
12
13         static void ControlMachine(IMachine m)
14         {
15             m.Start();
16             Console.WriteLine("机器在运转.....");
17             m.Stop();
18         }
19     }

没问题,但是如果有新的需求时,比如:当汽车发动机启动时自动打开大灯,发动机熄火时关闭大灯,这如何实现呢?

可以用一下两种方式:1、继承的方式,添加一个能自动管理大灯的SUVCar,继承自Car,重写Start和Stop方法,然后Main中的IMachine car = new SUVCar(); 改成IMachine car = new LightSUVCar();即可。

2、装饰模式实现,原理就是 添加 控制灯光功能类,这个控制灯光的功能对汽车而言是个装饰,汽车装饰上了这个功能,就具有了这个功能。如何装饰呢?这个灯光控制的功能就像个带灯光控制功能的汽车盒子,它能容纳一个汽车,也具有汽车的所有功能,只是这些功能室通过调用汽车的功能来实现的,同时添加自己的功能。

好,那我们先定义一个可以容纳汽车的盒子(装饰类):

    class LightCarDecotar
    {
        private IMachine mac = null;

        public LightCarDecotar(IMachine c)
        {
            mac = c;
        }
    }

这个类可以通过构造函数来容纳一个机器(IMachine),当然也就可以容纳汽车了。构造函数的参数IMachine可以修改成Car,这要看你调用地方的接口是如何使用的。好,能够容纳后,还需要让这个盒子拥有汽车的功能,如何拥有呢,那就是让它继承接口:IMachine。由于汽车继承了IMachine,所以它继承了这个接口就拥有了相关功能:

    /// <summary>
    /// 汽车启动时自动开启远光灯,熄火后自动关闭远光灯
    /// </summary>
    class LightCarDecotar : IMachine
    {
        private IMachine mac = null;
        public LightCarDecotar(IMachine c)
        {
            mac = c;
        }

        public void Start()
        {
            Console.WriteLine("车灯打开");
            mac.Start();
        }

        public void Stop()
        {
            mac.Stop();
            Console.WriteLine("车灯关闭");
        }
    }

到这里,这个汽车车灯控制的装饰类搞定了,在Main中调用:

    class Program
    {
        static void Main(string[] args)
        {
            Console.WriteLine("****汽车的功能****");
            IMachine car = new SUVCar();   //SUV汽车的功能
            ControlMachine(car);

            Console.WriteLine("");

            Console.WriteLine("****为汽车添加灯光功能****");
            IMachine lightCar = new LightCarDecotar(car);  //为汽车添加灯光功能
            ControlMachine(lightCar); 

            Console.WriteLine("");  

            Console.ReadLine();
        }

        static void ControlMachine(IMachine m)
        {
            m.Start();
            Console.WriteLine("机器在运转.....");
            m.Stop();
        }
    }

由于装饰类:LightCarDecotar需要容纳一个汽车,所以要通过构造函数把汽车传递进去,由因为它继承自IMachine接口,故可以直接传递给ControlMachine方法的参数。运行结果:

同样的,给汽车再加一个”鸣笛“功能,鸣笛装饰类:

    /// <summary>
    /// 汽车启动时自动鸣笛,关闭时也自动鸣笛
    /// </summary>
    class VoiceCarDecorator : IMachine
    {
        private IMachine mac = null;
        public VoiceCarDecorator(IMachine c) { mac = c; }

        public void Start()
        {
            Console.WriteLine("喇叭鸣笛");
            mac.Start();
        }

        public void Stop()
        {
            mac.Stop();
            Console.WriteLine("喇叭鸣笛");
        }
    }

调用的方式同上。

这是汽车就用了两个功能的装饰类了,再想一下,可能还会有这样的需求:汽车启动时即”开灯“又”鸣笛“,这怎么办呢?两种:1,再加一个装饰类,类中同时写”鸣笛“和”开灯“的代码。不过第一种方法貌似会出现重复的代码(鸣笛和开灯),这时就体现出装饰模式的强大之处和构思巧妙了。由于它能容纳一个汽车,而它自己就是汽车(因为继承了IMachine),所以它能容纳同类(装饰类)。

对于即“开灯”又“鸣笛”的汽车,可以这样写:

    IMachine voiceCar = new VoiceCarDecorator(car); //为汽车添加鸣笛功能
    IMachine lightVoiceCar = new LightCarDecotar(voiceCar); //为汽车添加鸣笛和灯光功能
    ControlMachine(lightVoiceCar);

先创建一个能鸣笛的车,然后创建一个能开灯的车,并把能鸣笛的车传递进去,装饰完的车就既可以鸣笛又可以开灯了。运行结果:

综上所述,您看出装饰模式的优势没?

例子中的类比较少,假设Car的子类有10种,其中的5种要加鸣笛,2种加开灯,3种加“既鸣笛又开灯”,如果用继承方式来实现,则要至少要加10个类通过重写方法来实现。但是如果通过装饰模式实现,则只需要加两个类(两个功能装饰类),然后在调用的时候按需装饰,装饰出来的对象就具有了装饰的功能。

以上例子是自己构想的,解释若有不确之处还请指出。谢谢

时间: 2024-10-29 19:06:04

对装饰模式(Decorator)的解读的相关文章

装饰模式Decorator

第三章 装饰模式Decorator  1.1 什么是装饰模式? 装饰模式Decorator,动态的给一些对象添加一些额外的职责,就增加功能来说,装饰模式比生成子类更加灵活 1.2装饰模式Decorator的结构图 Component是定义一个对象接口,可以给这些对象动态的添加职责. ConcreteComponent是定义了一个具体的对象,也可以给这个对象添加一些职责. Decorator装饰抽象类,继承了Component,从外类来扩展Component类的功能,但对于Component来说,

设计模式--装饰模式(Decorator)

装饰模式(Decorator) : 动态的给一个对象加入一些额外的职能,就添加功能来说,装饰模式比生成子类更为灵活. 实例: ConcreteComponent:让Decorator对象为自己加入功能.有时候使用ConcreteComponent的派生类提供核心功能.在这样的情况就是用ConcreteComponent替代了Component的功能,并且装饰者是继承于ConcreteComponent的子类. Component:定义ConcreteComponent和Decorator类要实现

[工作中的设计模式]装饰模式decorator

一.模式解析 装饰模式又名包装(Wrapper)模式.装饰模式以对客户端透明的方式扩展对象的功能,是继承关系的一个替代方案. 装饰模式的要点主要是: 1.需要对已有对象扩展新的功能,又不希望改变原有对象接口: 2.装饰者对象与原有对象需要继承相同接口,初始化装饰对象时将原有对象传入装饰对象: 3.可以对一个对象定义多个装饰着对象,进行分别装饰或者组合装饰 二.模式代码 1.抽象接口 package decorator.patten; public interface Component { pu

设计模式之三:装饰模式(Decorator)

装饰模式: 动态地给对象添加一些相关的职责.装饰模式相比与添加子类提供了一种更加灵活的方式. UML图如下所示: 感觉上图中关键的有这几点: Decorator与Component的聚合关系(即Decorator中存在一个Component类型的引用),由于这个聚合关系的存在,Decorator可以通过一个Component的引用调用Component的接口 Decorator与Component的继承关系,这个关系不是很容易理解.但是在这里联想到继承的里氏代换原则(父类出现的地方都可以替换成子

装饰模式(Decorator pattern)

装饰模式又名包装(Wrapper)模式.装饰模式以对客户端透明的方式扩展对象的功能,是继承关系的一个替代方案. 装饰模式的结构 装饰模式以对客户透明的方式动态地给一个对象附加上更多的责任.换言之,客户端并不会觉得对象在装饰前和装饰后有什么不同.装饰模式可以在不使用创造更多子类的情况下,将对象的功能加以扩展.装饰模式的类图如下: 在装饰模式中的角色有: 抽象构件(Component)角色:给出一个抽象组件接口,以规范准备接收附加责任的对象,即可以给这些对象动态地添加职责. 具体构件(Concret

装饰模式(decorator)

意图: 动态地给一个对象添加一些额外的职责,就增加功能而言,Decorator模式相比生成子类模式更为灵活 动机: 有时我们希望给某个对象而不是整个类添加一些功能.例如,一个图形用户界面工具箱允许你对任意一个用户界面组件添加一些特性,例如边框,或是一些行为,例如窗口滚动.一种较为灵活的方式是将组件嵌入另一个对象中,由这个对象添加边框.我们称这个嵌入的对象为装饰 .这个装饰与它所装饰的组件接口一致,因此它对使用该组件的客户透明.         例如,假定有一个对象 Te x t Vi e w,它

大话锦集(三)装饰模式(Decorator)

装饰模式(Decorator)就是动态地给一个对象添加一些额外的职责,就增加功能来说,装饰模式比生成子类更为灵活. 其结构图如下: Component是定义一个对象接口,可以给这些对象动态地添加责任.ConcreteComponent是定义了一个具体的对象,也可以给这个对象添加一些职责.Decorator装饰抽象类,继承了Component,从外类来扩展Component类的功能,但对于Component来说,是无需知道Decorator的存在.ConcreteDecorator就是具体的装饰对

设计模式 笔记 装饰模式 Decorator

//---------------------------15/04/17---------------------------- //Decorator 装饰模式----对象结构型模式 /* 1:意图: 动态地给一个对象添加额外的职业,就增加功能来说,Decorator模式相比生成子类更为灵活. 2:别名: 包装器(Wrapper) 3:动机: 4:适用性: 1>在不影响其他对象的情况下,以动态.透明的方式给单个对象添加职责. 2>处理那些可以撤销的职责. 3>当不能采用生成子类的方法

设计模式-装饰模式(Decorator Pattern)

Attach additional responsibilities to an object dynamically keeping the same interface.Decorators provide a flexible alternative to subclassing for extending functionality.(动态地给一个对象添加一些额外的职责.就增加功能来说,装饰模式相比生成子类更为灵活.) 装饰模式有四个角色:1.Component抽象构件Component