装饰模式【设计模式学习-03】

Definition

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

 

Frequency of use:    Medium
 

修饰模式的UML类图如下:

装饰模式【设计模式学习-03】_第1张图片

 

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

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

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

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

其示例性代码:

using System;

namespace DoFactory.GangOfFour.Decorator.Structural
{
    /// <summary>
    /// MainApp startup class for Structural 
    /// Decorator Design Pattern.
    /// </summary>
    class MainApp
    {
        /// <summary>
        /// Entry point into console application.
        /// </summary>
        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();
        }
    }

    /// <summary>
    /// The 'Component' abstract class
    /// </summary>
    abstract class Component
    {
        public abstract void Operation();
    }

    /// <summary>
    /// The 'ConcreteComponent' class
    /// </summary>
    class ConcreteComponent : Component
    {
        public override void Operation()
        {
            Console.WriteLine("ConcreteComponent.Operation()");
        }
    }

    /// <summary>
    /// The 'Decorator' abstract class
    /// </summary>
    abstract class Decorator : Component
    {
        protected Component component;

        public void SetComponent(Component component)
        {
            this.component = component;
        }

        public override void Operation()
        {
            if (component != null)
            {
                component.Operation();
            }
        }
    }

    /// <summary>
    /// The 'ConcreteDecoratorA' class
    /// </summary>
    class ConcreteDecoratorA : Decorator
    {
        public override void Operation()
        {
            base.Operation();
            Console.WriteLine("ConcreteDecoratorA.Operation()");
        }
    }

    /// <summary>
    /// The 'ConcreteDecoratorB' class
    /// </summary>
    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(装饰)模式的关键在于“动态地实现功能扩展”;

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

 

应用实例:

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

类图:

装饰模式【设计模式学习-03】_第2张图片

代码实现:

using System;

namespace DecoratorPattern
{
    /// <summary>
    /// MainApp startup class for Structural 
    /// Observer Design Pattern.
    /// </summary>
    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();
        }
    }

    /// <summary>
    /// 装备类,相当于Component
    /// </summary>
    public abstract class Equipment
    {

        public abstract void Attack();
    }

    /// <summary>
    /// 士兵类,继承自Equipment
    /// </summary>
    public class Soldier : Equipment
    {
        public Soldier()
        {
            // 构造函数
        }

        /// <summary>
        /// 没有任何武器装备下的核心功能
        /// </summary>
        public override void Attack()
        {
            Console.WriteLine("用拳脚攻击!");
        }
    }

    public abstract class EquipDecorator : Equipment
    {
        protected Equipment equipment;

        /// <summary>
        /// 增加装备,使用该方法来动态地给士兵增加装备
        /// </summary>
        /// <param name="equipment"></param>
        public void SetComponent(Equipment equipment)
        {
            this.equipment = equipment;
        }

        /// <summary>
        /// 攻击
        /// </summary>
        public override void Attack()
        {
            //如果有装备,就用装备进行攻击
            if (equipment != null)
            {
                equipment.Attack();
            }
        }
    }

    /// <summary>
    /// 步枪
    /// </summary>
    public class RifleEquipment : EquipDecorator
    {
        public override void Attack()
        {
            base.Attack();

            Console.WriteLine("步枪射击,啪!");
        }
    }

    /// <summary>
    /// 机枪
    /// </summary>
    public class MachineGunEquipment : EquipDecorator
    {
        public override void Attack()
        {
            base.Attack();

            Console.WriteLine("机枪扫射,突突突!");
        }
    }

    /// <summary>
    /// 火箭筒
    /// </summary>
    public class RocketGunEquipment : EquipDecorator
    {
        public override void Attack()
        {
            base.Attack();

            Console.WriteLine("火箭炮射击,唰......!");
        }
    }
}

输出结果:

 

优点

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

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

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

缺点

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

适用场景

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

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

 

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