博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
装饰模式【设计模式学习-03】
阅读量:5825 次
发布时间:2019-06-18

本文共 11750 字,大约阅读时间需要 39 分钟。

Definition

Attach additional responsibilities to an object dynamically.
Decorators provide a flexible alternative to subclassing for extending functionality.

 

Frequency of use: 
 
Medium
 

装饰模式的UML类图如下:

 

一个生动的例子:Pizza(手抓饼)

 

Component:

namespace DecoratorDemo{    public abstract class Pizza    {        public string Description { get; set; }        public abstract string GetDescription();        public abstract double CalculateCost();    }}

 

ConcreteComponent:

using System;namespace DecoratorDemo{    public class LargePizza : Pizza    {        public LargePizza()        {            Description = "Large Pizza";        }        public override string GetDescription()        {            return Description;        }        public override double CalculateCost()        {            return 9.00;        }    }}using System;namespace DecoratorDemo{    public class MediumPizza : Pizza    {        public MediumPizza()        {            Description = "Medium Pizza";        }        public override string GetDescription()        {            return Description;        }        public override double CalculateCost()        {            return 6.00;        }    }}using System;namespace DecoratorDemo{    public class SmallPizza : Pizza    {        public SmallPizza()        {            Description = "Small Pizza";        }        public override string GetDescription()        {            return Description;        }        public override double CalculateCost()        {            return 3.00;        }    }}

Decorator

using System;namespace DecoratorDemo{    public class PizzaDecorator : Pizza    {        protected Pizza _pizza;        public PizzaDecorator(Pizza pizza)        {            _pizza = pizza;        }        public override string GetDescription()        {            return _pizza.Description;        }        public override double CalculateCost()        {            return _pizza.CalculateCost();        }    }}

ConcreteDecorator:

using System;namespace DecoratorDemo{    public class Cheese : PizzaDecorator    {        public Cheese(Pizza pizza)            : base(pizza)        {            Description = "Cheese";        }        public override string GetDescription()        {            return String.Format("{0}, {1}", _pizza.GetDescription(), Description);        }        public override double CalculateCost()        {            return _pizza.CalculateCost() + 1.25;        }    }}using System;namespace DecoratorDemo{    public class Ham : PizzaDecorator    {        public Ham(Pizza pizza)            : base(pizza)        {            Description = "Ham";        }        public override string GetDescription()        {            return String.Format("{0}, {1}", _pizza.GetDescription(), Description);        }        public override double CalculateCost()        {            return _pizza.CalculateCost() + 1.00;        }    }}using System;namespace DecoratorDemo{    public class Peppers : PizzaDecorator    {        public Peppers(Pizza pizza)            : base(pizza)        {            Description = "Peppers";        }        public override string GetDescription()        {            return String.Format("{0}, {1}", _pizza.GetDescription(), Description);        }        public override double CalculateCost()        {            return _pizza.CalculateCost() + 2.00;        }    }}

 

Program:

using System;namespace DecoratorDemo{    class Program    {        static void Main(string[] args)        {            Pizza largePizza = new LargePizza();            largePizza = new Cheese(largePizza);            largePizza = new Ham(largePizza);            largePizza = new Peppers(largePizza);            Console.WriteLine(largePizza.GetDescription());            Console.WriteLine("{0:C2}", largePizza.CalculateCost());            Console.ReadKey();        }    }}

DebugLZQ:  手抓饼+奶酪+火腿+辣酱

 

通过使用装饰模式,可以在运行时动态地扩充一个类的功能。

原理是:增加一个修饰类包裹原来的类。装饰类实现新的功能,但是,在不需要用到新功能的地方,它可以直接调用原来的类中的方法。修饰类必须和原来的类有相同的接口。

修饰模式是类继承的另外一种选择。类继承在编译时候增加行为,而装饰模式是在运行时增加行为。

当有几个相互独立的功能需要扩充时,这个区别就变得很重要。在有些面向对象的编程语言中,类不能在运行时被创建,通常在设计的时候也不能预测到有哪几种功能组合。这就意味着要为每一种组合创建一个新类。相反,修饰模式是面向运行时候的对象实例的,这样就可以在运行时根据需要进行组合。

其示例性代码:

using System;namespace DoFactory.GangOfFour.Decorator.Structural{    ///     /// MainApp startup class for Structural     /// Decorator Design Pattern.    ///     class MainApp    {        ///         /// Entry point into console application.        ///         static void Main()        {            // Create ConcreteComponent and two Decorators            ConcreteComponent c = new ConcreteComponent();            ConcreteDecoratorA d1 = new ConcreteDecoratorA();            ConcreteDecoratorB d2 = new ConcreteDecoratorB();            // Link decorators            d1.SetComponent(c);            d2.SetComponent(d1);            d2.Operation();            // Wait for user            Console.ReadKey();        }    }    ///     /// The 'Component' abstract class    ///     abstract class Component    {        public abstract void Operation();    }    ///     /// The 'ConcreteComponent' class    ///     class ConcreteComponent : Component    {        public override void Operation()        {            Console.WriteLine("ConcreteComponent.Operation()");        }    }    ///     /// The 'Decorator' abstract class    ///     abstract class Decorator : Component    {        protected Component component;        public void SetComponent(Component component)        {            this.component = component;        }        public override void Operation()        {            if (component != null)            {                component.Operation();            }        }    }    ///     /// The 'ConcreteDecoratorA' class    ///     class ConcreteDecoratorA : Decorator    {        public override void Operation()        {            base.Operation();            Console.WriteLine("ConcreteDecoratorA.Operation()");        }    }    ///     /// The 'ConcreteDecoratorB' class    ///     class ConcreteDecoratorB : Decorator    {        public override void Operation()        {            base.Operation();            AddedBehavior();            Console.WriteLine("ConcreteDecoratorB.Operation()");        }        void AddedBehavior()        {        }    }}
View Code

 

下面再给出一个示例程序,来自程杰的大话设计模式:

View Code
using System; using System.Collections.Generic; using System.Text; namespace 装饰模式 {
class Program {
static void Main(string[] args) {
Person xc = new Person("小菜"); Console.WriteLine("\n第一种装扮:"); Sneakers pqx = new Sneakers(); BigTrouser kk = new BigTrouser(); TShirts dtx = new TShirts(); pqx.Decorate(xc); kk.Decorate(pqx); dtx.Decorate(kk); dtx.Show(); Console.WriteLine("\n第二种装扮:"); LeatherShoes px = new LeatherShoes(); Tie ld = new Tie(); Suit xz = new Suit(); px.Decorate(xc); ld.Decorate(px); xz.Decorate(ld); xz.Show(); Console.WriteLine("\n第三种装扮:"); Sneakers pqx2 = new Sneakers(); LeatherShoes px2 = new LeatherShoes(); BigTrouser kk2 = new BigTrouser(); Tie ld2 = new Tie(); pqx2.Decorate(xc); px2.Decorate(pqx); kk2.Decorate(px2); ld2.Decorate(kk2); ld2.Show(); Console.Read(); } } //Person类 class Person {
public Person() { } private string name; public Person(string name) {
this.name = name; } public virtual void Show() {
Console.WriteLine("装扮的{0}", name); } } //装饰类 class Finery : Person {
protected Person component; //打扮 public void Decorate(Person component) {
this.component = component; } public override void Show() {
if (component != null) {
component.Show(); } } } //具体装饰类 class TShirts : Finery {
public override void Show() {
Console.Write("大T恤 "); base.Show(); } } class BigTrouser : Finery {
public override void Show() {
Console.Write("垮裤 "); base.Show(); } } class Sneakers : Finery {
public override void Show() {
Console.Write("破球鞋 "); base.Show(); } } class Suit : Finery {
public override void Show() {
Console.Write("西装 "); base.Show(); } } class Tie : Finery {
public override void Show() {
Console.Write("领带 "); base.Show(); } } class LeatherShoes : Finery {
public override void Show() {
Console.Write("皮鞋 "); base.Show(); } } }

 

使用装饰模式需要注意的地方:

◇在发生“类爆炸”的情况下,应及时反思工程的设计;

◇在类中,不要过多的将“是否具有某种装饰”用boolean来表示;

◇Decorator(装饰)模式的关键在于“动态地实现功能扩展”;

◇装饰器的安装顺序很重要,应努力做到装饰器的安装顺序不影响最终的装饰效果。

 

应用实例:

装备大兵!无任何装备时(核心功能)可以用拳脚搏击;装备了步枪,可以正常射击;装备了重机枪,可以扫射;装备了火箭筒,可以防空。

类图:

代码实现:

using System;namespace DecoratorPattern{    ///     /// MainApp startup class for Structural     /// Observer Design Pattern.    ///     class MainApp    {        static void Main(string[] args)        {            // 定义新兵            Soldier soldier = new Soldier();            // 三种装备            RifleEquipment rifle = new RifleEquipment();            MachineGunEquipment machineGun = new MachineGunEquipment();            RocketGunEquipment rocketGun = new RocketGunEquipment();            // 将三种装备全部交给新兵            rifle.SetComponent(soldier);            machineGun.SetComponent(rifle);            rocketGun.SetComponent(machineGun);            // 攻击,除了拳脚功夫外,新兵还可以使用步枪,机枪,火箭炮.最终执行的是rocketGun.Attack().            rocketGun.Attack();            Console.Read();        }    }    ///     /// 装备类,相当于Component    ///     public abstract class Equipment    {        public abstract void Attack();    }    ///     /// 士兵类,继承自Equipment    ///     public class Soldier : Equipment    {        public Soldier()        {            // 构造函数        }        ///         /// 没有任何武器装备下的核心功能        ///         public override void Attack()        {            Console.WriteLine("用拳脚攻击!");        }    }    public abstract class EquipDecorator : Equipment    {        protected Equipment equipment;        ///         /// 增加装备,使用该方法来动态地给士兵增加装备        ///         ///         public void SetComponent(Equipment equipment)        {            this.equipment = equipment;        }        ///         /// 攻击        ///         public override void Attack()        {            //如果有装备,就用装备进行攻击            if (equipment != null)            {                equipment.Attack();            }        }    }    ///     /// 步枪    ///     public class RifleEquipment : EquipDecorator    {        public override void Attack()        {            base.Attack();            Console.WriteLine("步枪射击,啪!");        }    }    ///     /// 机枪    ///     public class MachineGunEquipment : EquipDecorator    {        public override void Attack()        {            base.Attack();            Console.WriteLine("机枪扫射,突突突!");        }    }    ///     /// 火箭筒    ///     public class RocketGunEquipment : EquipDecorator    {        public override void Attack()        {            base.Attack();            Console.WriteLine("火箭炮射击,唰......!");        }    }}

输出结果:

 

优点

 1 每个装饰对象只关心自己的功能,不需要关心如何被添加到对象链当中。它是由Decorator的SetComponent方法来实现的,因而它们的职责是单一的。

 2 类的核心职责与动态添加的职责是分离的。如果再向主类中添加新的功能,一是违反了开放封闭原则,二是增加了主类的复杂度。

 3 比静态继承更灵活 与对象的静态继承相比,Decorator模式提供了更加灵活的向对象添加职责的方式,可以使用添加和分离的方法,用装饰在运行时刻增加和删除职责.

缺点

 1 产生许多小对象,采用Decorator模式进行系统设计往往会产生许多看上去类似的小对象,这些对象仅仅在他们相互连接的方式上有所不同。

适用场景

 1 当需要为已有功能动态地添加更多功能时。

 2 类的核心功能无需改变,只是需要添加新的功能时。

 

 

转载地址:http://ausdx.baihongyu.com/

你可能感兴趣的文章
李娜入选国际网球名人堂 成亚洲第一人
查看>>
为找好心人抚养孩子 浙江一离婚父亲将幼童丢弃公园
查看>>
晚婚晚育 近20年巴西35岁以上孕妇增加65%
查看>>
读书:为了那个美妙的咔哒声
查看>>
我从过去八个月的AI公司面试中学到了什么?
查看>>
jQuery实践小结
查看>>
深入探究Immutable.js的实现机制(一)
查看>>
jsp改造之sitemesh注意事项
查看>>
智能硬件的时代,嵌入式是否已经日薄西山
查看>>
单点登录(SSO)看这一篇就够了
查看>>
SpringBoot-Shiro使用
查看>>
分布式理论:CAP是三选二吗?
查看>>
iOS 9.0之后NSString encode方法替换
查看>>
解决 ThinkPHP5 无法接收 客户端 Post 传递的 Json 参数
查看>>
ASMFD (ASM Filter Driver) Support on OS Platforms (Certification Matrix). (文档 ID 2034681.1)
查看>>
gitlab 账号注册及修改资料
查看>>
CRM Transaction处理中的权限控制
查看>>
在PL/SQL中获取操作系统环境变量
查看>>
[转]linux创建链接文件的两种方法
查看>>
python ipaddress模块使用
查看>>