7.装饰模式

7.结构型模式-装饰模式


7.1 基础知识

学习难度:3

使用频率:3

总分:6

定义

装饰模式(Decorator Pattern)动态地给一个对象添加一些额外的职责,以增加功能。相比生成子类,装饰模式更加灵活。

说人话

不改变原有对象结构,就像给一个人不断穿上不同的外套,而不必改变他的衣服。

结构图

实现步骤

  • 组件接口:定义操作方法
  • 具体组件类:要被装饰的原始对象,实现组件接口
  • 抽象装饰类:实现组件接口,定义组件对象并在构造函数传入初始化,实现操作方法。当组件接口对象不为空时,执行组件接口对象的操作方法。
  • 多个具体装饰类:继承抽象装饰类,继承抽象装饰器类构造函数,重写操作方法添加额外功能。
  • 客户端:实例化具体组件作为要被装饰的原始对象,实例化不同的具体装饰器传入上一装饰对象进行装饰,一系列装饰链后调用最后一个进行装饰的具体装饰器的操作方法。

说明

装饰模式是一种灵活的设计模式,常用于需要动态地增加或修改对象的功能,而又不希望改变其类结构的情况下。


7.2 模版代码

组件接口和具体组件类

// 组件接口
interface IComponent
{
    void Operation();
}

// 具体组件
class ConcreteComponent : IComponent
{
    public void Operation()
    {
        Console.WriteLine("具体组件的操作");
    }
}

抽象装饰接口和具体装饰类

// 装饰抽象类
abstract class Decorator : IComponent
{
    protected IComponent component;

    public Decorator(IComponent component)
    {
        this.component = component;
    }

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

// 具体装饰类,额外的方法
class ConcreteDecoratorA : Decorator
{
    public ConcreteDecoratorA(IComponent component) : base(component)
    {
    }

    public override void Operation()
    {
        base.Operation();
        AddAdditionalOperation();
    }

    public void AddAdditionalOperation()
    {
        Console.WriteLine("具体装饰者A的额外方法");
    }
}

// 具体装饰类,添加额外的字段
class ConcreteDecoratorB : Decorator
{
    private string additionalField;

    public ConcreteDecoratorB(IComponent component) : base(component)
    {
        additionalField = "具体装饰者B的额外字段";
    }

    public override void Operation()
    {
        base.Operation();
        Console.WriteLine(additionalField);
    }
}

客户端

class Program
{
    static void Main()
    {
        // 创建一个具体组件
        IComponent component = new ConcreteComponent();

        // 使用装饰器包装组件
        IComponent decoratorA = new ConcreteDecoratorA(component);
        IComponent decoratorB = new ConcreteDecoratorB(decoratorA);

        // 调用装饰后的操作
        decoratorB.Operation();
        // 具体组件的操作
        // 具体装饰者A的额外方法
        // 具体装饰者B的额外字段

    }
}

7.3 CSharp实践

实践需求

使用装饰模式,给孙悟空穿上凤翅紫金冠和如意金箍棒。

装饰接口和孙悟空类

// 装饰器接口
interface IDecorator
{
    void Decorate();
}

// 孙悟空的默认外观,只穿着兽皮
class MonkeyKing : IDecorator
{
    public void Decorate()
    {
        Console.WriteLine("孙悟空穿着兽皮。");
    }
}

抽象装备类和具体装备类

// 装备基类
abstract class Equipment : IDecorator
{
    private IDecorator monkeyKing;

    public Equipment(IDecorator monkeyKing)
    {
        this.monkeyKing = monkeyKing;
    }

    public virtual void Decorate()
    {
        monkeyKing.Decorate();
    }
}

// 具体的装饰类 - 凤翅紫金冠
class PhoenixCrown : Equipment
{
    public PhoenixCrown(IDecorator monkeyKing) : base(monkeyKing) { }

    public override void Decorate()
    {
        base.Decorate();
        Console.WriteLine("孙悟空戴上凤翅紫金冠。");
    }
}

// 具体的装饰类 - 如意金箍棒
class RuyiJinguBang : Equipment
{
    public RuyiJinguBang(IDecorator monkeyKing) : base(monkeyKing) { }

    public override void Decorate()
    {
        base.Decorate();
        Console.WriteLine("孙悟空持有如意金箍棒。");
    }
}

客户端

class Program
{
    static void Main(string[] args)
    {
        // 创建孙悟空对象
        IDecorator monkeyKing = new MonkeyKing();

        // 使用装饰器装饰孙悟空
        monkeyKing = new PhoenixCrown(monkeyKing); // 装上凤翅紫金冠
        monkeyKing = new RuyiJinguBang(monkeyKing); // 拿上如意金箍棒

        // 打印孙悟空的装饰
        monkeyKing.Decorate();
        // 孙悟空穿着兽皮。
        // 孙悟空戴上凤翅紫金冠。
        // 孙悟空持有如意金箍棒。
    }
}

7.4 Unity实践

实践需求

使用装饰模式,实现生成薇恩时带上两个剑圣和阿狸这两个小伙伴。

英雄组件接口和薇恩英雄类

//英雄组件接口
public interface IHeroComponent
{
    //实例化英雄方法
    void InstantiateHero();
}

//薇恩主英雄
public class VnHeroConcreteComponent : IHeroComponent
{
    public void InstantiateHero()
    {
        GameObject vn = Resources.Load<GameObject>("Lesson16_结构型模式_装饰模式/Vayne");
        GameObject.Instantiate(vn, Vector3.zero, Quaternion.identity);
    }
}

抽象英雄伙伴装饰类和具体英雄伙伴装饰

//英雄伙伴装饰
public abstract class HeroDecorator : IHeroComponent
{
    private IHeroComponent heroComponent;

    public IHeroComponent SetHeroComponent(IHeroComponent heroComponent)
    {
        this.heroComponent = heroComponent;
        return this;
    }

    public virtual void InstantiateHero()
    {
        heroComponent?.InstantiateHero();
    }
}

// 剑圣装饰伙伴
public class YiHeroConcreteDecorator : HeroDecorator
{
    public override void InstantiateHero()
    {
        GameObject yi = Resources.Load<GameObject>("Lesson16_结构型模式_装饰模式/Yi");
        GameObject.Instantiate(yi, Vector3.left, Quaternion.identity);
        base.InstantiateHero();
    }
}

// 阿狸装饰伙伴
public class AhriHeroConcreteDecorator : HeroDecorator
{
    public override void InstantiateHero()
    {
        GameObject ahri = Resources.Load<GameObject>("Lesson16_结构型模式_装饰模式/Ahri");
        GameObject.Instantiate(ahri, Vector3.right, Quaternion.identity);
        base.InstantiateHero();
    }
}

客户端

public class TestDecoratorPattern : MonoBehaviour
{
    private void Start()
    {
        // 创建薇恩主英雄组件
        IHeroComponent vnHeroConcreteComponent = new VnHeroConcreteComponent();
        // 创建剑圣英雄伙伴装饰
        HeroDecorator yiHeroConcreteDecorator = new YiHeroConcreteDecorator();
        // 创建阿狸英雄伙伴装饰
        HeroDecorator ahriHeroConcreteDecorator = new AhriHeroConcreteDecorator();

        // 将剑圣英雄伙伴装饰添加到薇恩主英雄组件
        vnHeroConcreteComponent = yiHeroConcreteDecorator.SetHeroComponent(vnHeroConcreteComponent);
        // 将阿狸英雄伙伴装饰再次添加到组件中
        vnHeroConcreteComponent = ahriHeroConcreteDecorator.SetHeroComponent(vnHeroConcreteComponent);

        // 实例化带有装饰的薇恩主英雄和伙伴
        vnHeroConcreteComponent.InstantiateHero();
    }
}

运行结果



转载请注明来源,欢迎对文章中的引用来源进行考证,欢迎指出任何有错误或不够清晰的表达。可以在下面评论区评论,也可以邮件至 785293209@qq.com

×

喜欢就点赞,疼爱就打赏