1:主题拆解

①基本介绍

②王者荣耀英雄甄姬皮肤场景

③装饰器模式的优缺点

④适用场景

⑤相关扩展

2:基本介绍

装饰模式可以在不改变一个对象本身功能的基础上给对象增加额外的新行为。若要扩展功能,装饰者提供了比继承更有弹性的替代方案。

装饰模式是一种用于替代继承的技术,无须定义子类即可给对象动态增加职责,使用对象之间的关联关系来代替继承关系,在装饰模式中引入了装饰类,在装饰类中既可以调用待装饰的原有类方法,还可以增加新的方法,以扩充原有的类功能。

3:王者荣耀英雄甄姬皮肤场景

下面以当前热门游戏王者荣耀英雄甄姬选择皮肤,然后开始对战来模拟

1:基础版

①英雄抽象类基类

public abstract class AbstractBaseCharacter
{public AbstractBaseCharacter() {//构造函数}public int Id { get; set; }public string Name { get; set; }/// <summary>/// 开始游戏/// </summary>public void Play(){Console.WriteLine("  当前玩家,mylove:{0}", this.Name);}//秀皮肤public abstract void Show();
}

②玩家类继承并且实现

public class ZhenjiPlay : AbstractBaseCharacter
{ //选择甄宓自动获得经典皮肤public override void Show(){            Console.WriteLine("  真的,会有人选择阿宓吗?");Console.WriteLine("  沦陷在爱情的泡影中。");Console.WriteLine("  明明说好的,要永远在一起。");Console.WriteLine("  果然,先爱上的那个人,是输家。");            Console.WriteLine("  获得皮肤-经典");}
}

③上端调用

AbstractBaseCharacter zhenji = new ZhenjiPlay()
{Id = 1,Name = "颖宝"
};
zhenji.Show();
zhenji.Play();

分析:该版本为最基本的抽象工厂模式,对英雄的方法与属性由抽象类进行约束,子类再进行重写实现。

如果另外一个玩家,其除了经典皮肤之外又喜欢幽恒这一款皮肤,该如何处理呢。直接改玩家类势必就违反了对修改封闭的原则。

现在提供两种方式。

2:组合方式版

①添加一个组合类

public class ZhenjiPlayCombination
{private AbstractBaseCharacter _AbstractBaseCharacter = null;public ZhenjiPlayCombination(AbstractBaseCharacter abstractBaseCharacter){this._AbstractBaseCharacter = abstractBaseCharacter;this._AbstractBaseCharacter.Id = abstractBaseCharacter.Id;this._AbstractBaseCharacter.Name = abstractBaseCharacter.Name;}public void Show(){this._AbstractBaseCharacter.Show();Console.WriteLine("  获得皮肤-幽恒");}public void Play(){this._AbstractBaseCharacter.Play();}
}

②上端调用

AbstractBaseCharacter zhenji = new ZhenjiPlay()
{Id = 1,Name = "颖宝"
};
ZhenjiPlayCombination zhenjiPlayCombination = new ZhenjiPlayCombination(zhenji);
zhenjiPlayCombination.Show();
zhenjiPlayCombination.Play();

分析:采用组合的方式,实现了功能的扩展,并且没有对原有的类做更改,遵循了对修改封闭对扩展开放。

3:继承方式版

①添加一个继承类

public class ZhenjiPlay幽恒 : ZhenjiPlay
{public override void Show(){base.Show();Console.WriteLine("  获得皮肤-幽恒");}
}

②上端调用

ZhenjiPlay幽恒 zhenjiPlay幽恒 = new ZhenjiPlay幽恒()
{Id = 1,Name = "颖宝"
};
zhenjiPlay幽恒.Show();
zhenjiPlay幽恒.Play();

分析:采用继承的方式,同样是在未更改原有封装的前提下实现了业务功能的扩展

4:装饰器模式版本

需求:随着玩家的增加,特别是土豪玩家或者犯有皮肤收藏强迫症的小菇凉加入,基于上面的继承与组合的方式,不可能每获得一个皮肤就增加一种组合或者继承。特别是不同的玩家对皮肤的喜爱程度不一样,购买顺序也不一样,这样无论是组合还是继承的方式来实现,对应的类都会成爆炸式增长。

①抽象类基类

public abstract class AbstractBaseCharacter
{public AbstractBaseCharacter() {//构造函数}public int Id { get; set; }public string Name { get; set; }/// <summary>/// 开始游戏/// </summary>public void Play(){Console.WriteLine("  当前玩家,mylove:{0}", this.Name);}//秀皮肤public abstract void Show();
}

②组合+继承的方式继承并且实现基类

public class BaseZhenJi : AbstractBaseCharacter
{private AbstractBaseCharacter _AbstractBaseCharacter = null;        public BaseZhenJi(AbstractBaseCharacter AbstractBaseCharacter){this._AbstractBaseCharacter = AbstractBaseCharacter;this.Id = _AbstractBaseCharacter.Id;this.Name = _AbstractBaseCharacter.Name;}//重写public override void Show(){this._AbstractBaseCharacter.Show();}
}

③获取各种皮肤类的实现

public class ZhenJiWith_冰雪圆舞曲 : BaseZhenJi
{public ZhenJiWith_冰雪圆舞曲(AbstractBaseCharacter abstractBaseCharacter): base(abstractBaseCharacter){}public override void Show(){base.Show();Console.WriteLine("  获得皮肤-冰雪圆舞曲");}
}public class ZhenJiWith_花好人间 : BaseZhenJi
{public ZhenJiWith_花好人间(AbstractBaseCharacter abstractBaseCharacter): base(abstractBaseCharacter){}public override void Show(){base.Show();Console.WriteLine("  获得皮肤-花好人间");}
}public class ZhenJiWith_游园惊梦 : BaseZhenJi
{public ZhenJiWith_游园惊梦(AbstractBaseCharacter abstractBaseCharacter): base(abstractBaseCharacter){}public override void Show(){base.Show();Console.WriteLine("  获得皮肤-游园惊梦-mylove");}
}public class ZhenJiWith_幽恒 : BaseZhenJi
{public ZhenJiWith_幽恒(AbstractBaseCharacter abstractBaseCharacter): base(abstractBaseCharacter){}public override void Show(){base.Show();Console.WriteLine("  获得皮肤-幽恒");}
}

④基础玩家类

基础玩家自带经典皮肤,并且会发出人生感叹。。。

public class ZhenjiPlay : AbstractBaseCharacter
{ //选择甄宓自动获得经典皮肤public override void Show(){            Console.WriteLine("  真的,会有人选择阿宓吗?");Console.WriteLine("  沦陷在爱情的泡影中。");Console.WriteLine("  明明说好的,要永远在一起。");Console.WriteLine("  果然,先爱上的那个人,是输家。");            Console.WriteLine("  获得皮肤-经典");}
}

⑤上端调用

Console.WriteLine("  装饰器模式");
Console.WriteLine("  *********************");
AbstractBaseCharacter zhenji = new ZhenjiPlay()
{Id = 1,Name = "颖宝"
};
zhenji = new ZhenJiWith_冰雪圆舞曲(zhenji);
zhenji = new ZhenJiWith_花好人间(zhenji);
zhenji = new ZhenJiWith_幽恒(zhenji);
zhenji = new ZhenJiWith_游园惊梦(zhenji);
zhenji.Show();
zhenji.Play();
Console.WriteLine($"  当前时间{System.DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss")}");

分析:从上端调用的地方可以看出,实际上每次进行调用都是使用的基类因此可以不停的嵌套,并且可以随意调整顺序。

4:装饰器模式的优缺点

1:优点

动态扩展灵活:对于扩展一个对象的功能,装饰模式比继承更加灵活,不会导致类的个数急剧增加。通过选择不同的具体装饰类,可以动态扩展对象的行为

多次装饰:可以对一个对象进行多次装饰,使用不同的具体装饰类以及这些装饰类的排列组合,可以创造很多不同行为的组合

构件与装饰类独立变化:具体构件类以及具体装饰类可以独立变化,用户可以根据需要增加新的具体构件类或者具体装饰类,无须修改原有代码,符合开闭原则

2:缺点

对象较多:使用装饰模式会产生很多小对象,这些对象的区别在于相互连接方式的不同,小对象过多会一定程度上影响性能

排查繁琐:尽管装饰模式比继承更加灵活,但也意味着比继承更加容易出错,排错也很困难,对于多次装饰后的对象可能需要逐级排查

5:适用场景

在不影响其他对象的情况下,以动态和透明的方式给单个对象增加职责。

在不能采用继承扩展系统或者采用继承不利于对系统扩展和维护时可以使用装饰模式。

如果想要动态的给一个类增加功能,并且这个功能还希望可以动态的撤销。

6:相关扩展

1:运行结果

2:甄姬皮肤

1:冰雪圆舞曲

2:花好人间

3:幽恒

4:游园惊梦

3:甄姬手办

1:原型版

2:Q版

4:甄姬的历史身份

甄姬:“果然,先爱上的那个人是输家”,您知道那个人是谁吗?

5:王者前辈的指导

6:忠告

多读书,多看报,少打王者,多睡觉!

“果然,先爱上的那个人,是输家”,缘于王者,终于甄姬,卸载了,离开了。

【手写源码-设计模式9】-装饰器模式-基于王者荣耀英雄-甄姬皮肤场景相关推荐

  1. 【设计模式-手写源码-2】-工厂方法模式-基于魔兽争霸冰封王座

    1:主题拆解 ① 对比简单工厂,建立工厂方法(FactoryMethod) ②工厂方法的优缺点和应用 ③对修改关闭对扩展开放 ④面向切面编程 2:基本介绍 定义一个用于创建对象的接口,让子类决定实例化 ...

  2. Mybatis源码:Cache 装饰器模式

    装饰器模式介绍 装饰器模式(Decorator Pattern)允许向一个现有的对象添加新的功能,同时又不改变其结构.这种类型的设计模式属于结构型模式,它是作为现有的类的一个包装. 这种模式创建了一个 ...

  3. 【手写源码-设计模式6】-适配器模式-基于IPhoneX手机充电场景

    1:主题拆解 ①基本介绍 ②IPhone手机充电场景模拟 ③类适配器与对象适配器的区别 ④适配器模式的优缺点 ⑤适用场景 ⑥C#.NET中的使用场景 2:基本介绍 Adapter适配器模式,将一个类的 ...

  4. 【手写源码-设计模式15】-责任链模式-基于人事请假单工作流场景

    1:主题拆解 ①基本介绍 ②人事请假单工作流模拟 ③责任链模式的优缺点 ④适用场景 ⑤应用实例 ⑥ASP.NET 管道模型 2:基本介绍 责任链模式很像异常的捕获和处理,当一个问题发生的时候,当前对象 ...

  5. 面试前端岗,你被要求手写源码了吗?

    如今前端开发的任职要求越来越高了,不仅要掌握 javascript,熟悉vue.react等各种框架,甚至连后端和 python 都得懂. 前几年只要熟练HTML.CSS.JavaScript ,靠扒 ...

  6. 前端为什么有的接口明明是成功回调却执行了.catch失败回调_前端进阶高薪必看-手写源码篇(高频技术点)...

    前言 此系列作为笔者之前发过的前端高频面试整理的补充 会比较偏向中高前端面试问题 当然大家都是从新手一路走过来的 感兴趣的朋友们都可以看哈 初衷 我相信不少同学面试的时候最怕的一个环节就是手写代码 大 ...

  7. all方法 手写promise_前端进阶高薪必看手写源码篇

    前言 此系列作为笔者之前发过的前端高频面试整理的补充 会比较偏向中高前端面试问题 当然大家都是从新手一路走过来的 感兴趣的朋友们都可以看哈 初衷 我相信不少同学面试的时候最怕的一个环节就是手写代码 大 ...

  8. fortran中call的用法_手写源码系列(一)——call、apply、bind

    什么是手写源码 平时面试时经常会遇到让手写一个已有方法的实现,其实面试官是想考察你对于JS底层逻辑是否熟悉,经常面试会出的会在下面: call.apply.bind promise requireJS ...

  9. TransmittableThreadLocal的简单使用 + 手写源码

    文章目录 使用方法 原理 手写源码 之前有一篇文章谈到链路追踪场景下,需要在异步线程之间,实现跨线程的ThreadLocal传递, 简单场景可以用InheritableThreadLocal,但ITL ...

  10. 设计模式学习----装饰器模式

    这两天本来是自在学习java collection Framework的Fail Fast底层机制,看到核心的部分时,突然意识到设计模式的问题,上大学到现在我还没有真正理解过设计模式的概念,于是用了大 ...

最新文章

  1. 何恺明等人新作:效果超ResNet,利用NAS方法设计随机连接网络 | 技术头条
  2. 设计模式(19)-Observer Pattern
  3. Linq to objects示例
  4. Docker中使用Dockerfile定制化jar启动时:at sun.awt.FontConfiguration.getVersion(FontConfiguration.java:1264)
  5. scala基础语法:for/while/do...while/
  6. 珠海 第十届亚洲机器人锦标赛_2016年第十届亚洲机器人锦标赛在广东珠海成功举办...
  7. 1 uC/OS工程目录
  8. Keil5 编译生成bin二进制文件的设置方法
  9. 如何将 Linux 系统转移至 LVM 卷
  10. c# DES 加密解密方法
  11. spring配置文件最全约束
  12. 【CMAKE系列】cmake中CMakeLists.txt脚本的常用语法
  13. mysql的db.opt文件_MySQL数据库的db.opt文件
  14. Hyper-V 2016 系列教程56 SCVMM 2016 Client的安装
  15. 关于高速光耦6N137的使用总结
  16. IAR 8.50.9破解后,遇到IarIdePm Encoutered an improper argument错误记录
  17. 随机森林回归预测r语言_R包randomForest的随机森林回归模型以及对重要变量的选择...
  18. java图形界面美化_在Java中使用图片实现GUI的美化.doc
  19. How to build openssl with fips module on Linux and Windows?
  20. 微型计算机硬件系统基本组成一般应用包括,计算机系统的基本组成,一般应包括哪些...

热门文章

  1. 微博视频自动投稿视频社区大师软件下载
  2. linux学习(跟着b站尚硅谷老师学习)
  3. 新年贺卡php,PS设计2016猴年大吉新年贺卡
  4. 立创开源丨无刷电机驱动FOC驱动板
  5. 云计算技术基础【10】
  6. GUI学习笔记——04更改背景板颜色,鼠标进入事件
  7. 技术分享 | show engine innodb status中Pages flushed up to 的含义
  8. SuperView和View的区别
  9. Linux 运维职业困惑?给你史上最全互联网 Linux 工作规划!
  10. 强烈呼吁弃用Notepad++,推荐几款优秀替代品