Unity【话大】设计模式之装饰器模式

简介: 前言:笔者在最开始写程序的时候经常会遇到一种情况,例如更改一个字段、或者添加一种小功能,就要把原来写过的东西几乎废弃掉,或者更改大量以前写过的代码。又或者自己写的东西时间久了再去回顾,完全找不到到时为什么这么写的头绪,如果遇到了Bug更是无法快速定位在哪里小范围出现的问题。

前言:笔者在最开始写程序的时候经常会遇到一种情况,例如更改一个字段、或者添加一种小功能,就要把原来写过的东西几乎废弃掉,或者更改大量以前写过的代码。又或者自己写的东西时间久了再去回顾,完全找不到到时为什么这么写的头绪,如果遇到了Bug更是无法快速定位在哪里小范围出现的问题。如果你也经常遇到这种问题,就说明你现阶段非常需要学习下设计模式了

在网上经常说的设计模式有23种,也有一些更多的设计模式,无非也是从这些设计模式中变种而来。如果让笔者来形容什么是设计模式,我认为设计模式是:一种思想,一种模式,一种套路,一种解决问题的高效策略



有说的不正确或者不准确的地方欢迎留言指正


有什么有趣的写作技巧或者想法欢迎大家给我留言,大家的帮助是我写下去最有效的动力



圣诞树是圣诞节中必不可少的东西,为什么是圣诞树,而不是弄个什么圣诞花或者圣诞草之类的笔者没有深入研究。下面的两张圣诞树图片是笔者找到认为最漂亮的,本打算只留一张,但确实不好取舍,索性就都用了。我们今天要说的设计模式,就以圣诞树为主题展开

img_3ca7b3d794482dc260a3bb8ee541713d.jpe
img_5d4967de7109acd46a9cc31182953041.jpe

圣诞树一般都是以松树为核心主题,然后在最上面添加圣诞星,树上挂一些彩球、彩灯之类的装饰品,圣诞树下放一些礼物。但是网上有人说挂毛主席头像,笔者表示可能落伍了,这波操作真的看不懂!!!

img_09031f7ec21a1f329c8d54dbfc3b54ac.png

对于这种结构的操作形式,在我们的设计模式中也有一个相近的形式,那就是----【装饰器模式】

首先我们的需求是这样的,先创建一个主题圣诞树,然后调用展示圣诞树函数

public class ChristmasTree
{
    private readonly string core = "圣诞树";
    public virtual void Show()
    {
        Debug.Log($"展示圣诞节的核心{core}");
    }
}

然后我们有了新的需求,在展示里面添加圣诞星对应的信息

public class ChristmasTree
{
    private readonly string core = "圣诞树";
    public virtual void Show()
    {
        Debug.Log($"展示圣诞节的核心{core}");
        /************************/
        Debug.Log("展示圣诞星星");
        /************************/
    }
}

现在策划大佬感觉装饰品不够丰富,要添加圣诞彩灯、圣诞礼物或者一些其他的东西,那我们也在原有的Show函数中添加吗?如果这么做的话显然违反了我们的开闭原则,那么对于这种情况我们应该:把每个要装饰的功能放在单独的类中,并让这个类包装她所要装饰的对象,因此,当需要执行特殊行为时,客户代码就可以在运行时根据需要有选择地、按顺序地使用装饰功能包装对象了。

第一步,为ChristmasTree创建装饰器基类

public class ChristmasTreeDecorator : ChristmasTree
{
    /// <summary>
    /// 上一次圣诞树的状态
    /// </summary>
    protected ChristmasTree christmasTree = null;

    public ChristmasTreeDecorator(ChristmasTree tempChristmasTree)
    {
        this.christmasTree = tempChristmasTree;
    }

    public override void Show()
    {
        //上一次圣诞树的状态
        this.christmasTree.Show();
    }
}

有了装饰器的基类后,我们可以在这个基础上创建圣诞星装饰器、彩灯装饰器、礼物装饰器等等~~~

public class ChristmasTreeDecorator_Start : ChristmasTreeDecorator
{
    public ChristmasTreeDecorator_Start(ChristmasTree tempChristmasTree) : base(tempChristmasTree) { }
    /// <summary>
    /// 在上一次的状态基础上进行装饰
    /// </summary>
    public override void Show()
    {
        Debug.Log("展示在最上面装饰了一个圣诞星");
        //上一次圣诞树的状态
        base.christmasTree.Show();
    }
}
public class ChristmasTreeDecorator_Lights : ChristmasTreeDecorator
{
    public ChristmasTreeDecorator_Lights(ChristmasTree tempChristmasTree) : base(tempChristmasTree) { }
    /// <summary>
    /// 在上一次的状态基础上进行装饰
    /// </summary>
    public override void Show()
    {
        //上一次圣诞树的状态
        base.christmasTree.Show();
        Debug.Log("展示在最下面装饰了一个圣诞彩灯");
    }
}

public class ChristmasTreeDecorator_Gift : ChristmasTreeDecorator
{
    public ChristmasTreeDecorator_Gift(ChristmasTree tempChristmasTree) : base(tempChristmasTree) { }
    /// <summary>
    /// 在上一次的状态基础上进行装饰
    /// </summary>
    public override void Show()
    {
        //上一次圣诞树的状态
        base.christmasTree.Show();
        Debug.Log("展示在最下面放了一些礼物");
    }
}

然后我们的运行代码可以这么用

    public void Function_One()
    {
        ChristmasTree christmasTree = new ChristmasTree();

        ChristmasTreeDecorator_Lights tree_Lights = new ChristmasTreeDecorator_Lights(christmasTree);

        ChristmasTreeDecorator_Gift tree_Gift = new ChristmasTreeDecorator_Gift(tree_Lights);

        ChristmasTreeDecorator_Start tree_Start = new ChristmasTreeDecorator_Start(tree_Gift);

        tree_Start.Show();
    }
img_33d2224de3bfdd9e154503d445240492.png

打印信息

img_42d95cbc148e35fe74e9b99a6e1a2b02.png

这样我们可以有效地把类的核心职责和装饰功能区分开了,而且可以去除相关类中重复的装饰逻辑

还没有完,对于执行代码我们可以继续重构优化

既然所有的装饰器都是继承自装饰器基类,我们可以这么写

    public void Function_Two()
    {
        ChristmasTree christmasTree = new ChristmasTree();

        ChristmasTreeDecorator tree_Lights = new ChristmasTreeDecorator_Lights(christmasTree);

        ChristmasTreeDecorator tree_Gift = new ChristmasTreeDecorator_Gift(tree_Lights);

        ChristmasTreeDecorator tree_Start = new ChristmasTreeDecorator_Start(tree_Gift);

        tree_Start.Show();
    }
img_26ec5b7942ed0bb2fdeb35dec4b57f87.png

装饰器基类又是继承自ChristmasTree,又可以这么写

    public void Function_Three()
    {
        ChristmasTree christmasTree = new ChristmasTree();

        ChristmasTree tree_Lights = new ChristmasTreeDecorator_Lights(christmasTree);

        ChristmasTree tree_Gift = new ChristmasTreeDecorator_Gift(tree_Lights);

        ChristmasTree tree_Start = new ChristmasTreeDecorator_Start(tree_Gift);

        tree_Start.Show();
    }
img_eb0ca9582d7bc6ebc2e01981e00616cd.png

既然所有的声明都是ChristmasTree ,我们最后这样写

    public void Function_Four()
    {
        ChristmasTree christmasTree = new ChristmasTree();

        christmasTree = new ChristmasTreeDecorator_Lights(christmasTree);

        christmasTree = new ChristmasTreeDecorator_Gift(christmasTree);

        christmasTree = new ChristmasTreeDecorator_Start(christmasTree);

        christmasTree.Show();
    }
img_946583df70809f53597e5492ce966c27.png

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

这样我们的装饰器就大功告成了,其实把装饰器模式这种思想发扬光大的另一种编程方式就是面向切面编程(AOP),感兴趣的同学可以去了解一下~

在开发中我们一般在什么地方用到呢?

例如我们已经写好一个相应的战斗模块,但是在进入之前或者进入之后添加一些,输出日志、数据监测、数据收集埋点触发之类的功能,其实这些都可以用这个装饰器模式~既没有更改写好的模块,又添加了一些需要的辅助措施,注意是辅助措施,如果是核心玩法之类的改动,笔者还是建议不要用装饰器模式了。

打完收工~

img_569463b7983f645f063dd7b1bef93e0c.png
相关文章
|
7月前
|
设计模式 存储 缓存
聊聊Java设计模式-装饰器模式
装饰器模式允许向一个现有的对象添加新的功能,同时不改变其结果。比如Java 中的IO框架中,`FileInputStream`(处理文件)、`ByteArrayInputStream`(处理字节数组)、`BufferedInputStream`(带缓存的处理类)等就是对`InputStream`进行的功能扩展,这就是装饰器模式的典型应用。
65 1
聊聊Java设计模式-装饰器模式
|
7月前
|
设计模式 Java
常用设计模式(工厂方法,抽象工厂,责任链,装饰器模式)
有关设计模式的其他常用模式请参考 单例模式的实现 常见的设计模式(模板与方法,观察者模式,策略模式)
73 2
|
7月前
|
设计模式
设计模式之装饰器模式
设计模式之装饰器模式
|
7月前
|
设计模式
设计模式-装饰器模式
设计模式-装饰器模式
|
2月前
|
设计模式 XML Java
【设计模式】装饰器模式(定义 | 特点 | Demo入门讲解)
【设计模式】装饰器模式(定义 | 特点 | Demo入门讲解)
41 0
|
15天前
|
设计模式 前端开发 JavaScript
前端必须掌握的设计模式——装饰器模式
装饰器模式是一种结构型设计模式,通过创建新类来包装原始对象,实现在不修改原有结构的前提下扩展新行为。其核心在于“组合”思想,使新功能可“即插即拔”。该模式具有解耦性、灵活性和动态性等特点,广泛应用于类的面向对象编程语言中,如JavaScript的注解和TypeScript的写法。示例中,通过装饰器模式为游戏角色动态添加装备,展示了其强大的扩展性和灵活性。
|
7月前
|
设计模式 Java
Java一分钟之-设计模式:装饰器模式与代理模式
【5月更文挑战第17天】本文探讨了装饰器模式和代理模式,两者都是在不改变原有对象基础上添加新功能。装饰器模式用于动态扩展对象功能,但过度使用可能导致类数量过多;代理模式用于控制对象访问,可能引入额外性能开销。文中通过 Java 代码示例展示了两种模式的实现。理解并恰当运用这些模式能提升代码的可扩展性和可维护性。
70 1
|
3月前
|
设计模式 Java
Java设计模式-装饰器模式(10)
Java设计模式-装饰器模式(10)
|
6月前
|
设计模式 Java
Java设计模式:深入装饰器模式的三种写法(六)
Java设计模式:深入装饰器模式的三种写法(六)
|
6月前
|
设计模式 架构师 安全
设计模式第五讲-装饰器模式和代理模式详解
远程代理,这种方式通常是为了隐藏目标对象存在于不同地址空间的事实,方便客户端访问。例如,用户申请某些网盘空间时,会在用户的文件系统中建立一个虚拟的硬盘,用户访问虚拟硬盘时实际访问的是网盘空间。
281 0