一、引言

先看一个开发问题,很多人都玩过英雄联盟这款游戏:里面有各种英雄,每个英雄都有各自的技能(一般是4个主动技能),每升一级可以升级一个技能,但是可升级的技能不固定。我们需要通过技能状态来计算伤害,这个时候组合就非常多了(理论上是英雄数*技能数)。如果用继承来解决的话,那么子类就爆炸多了。

除了继承还有一种设计,就是在基类上增加布尔变量,如Q,E等,然后提供一些has(get)和set方法来设置这些布尔值,子类里通过扩展计算伤害值,这个看起来是一个可行的设计,但这个设计也会有一些问题。

1.每个技能可以多次加点,单纯靠布尔值是处理不了的。

2.技能有可能会进行调整,那么我们就必须通过修改基类来处理。

3.游戏里面还有装备这种情况,增加装备也是相当于多了技能(貌似用装备来做例子更合适)。。。

我们用更好的方法来解决这个问题

这个问题的本质是扩展,我们想要扩展一些功能,但是不想用继承。装饰者模式可以解决这个问题

二、装饰者模式

定义:动态地将责任附加到对象上。若要扩展功能,装饰者提供了比继承更有弹性的替代方案。

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

主要解决:一般的,我们为了扩展一个类经常使用继承方式实现,由于继承为类引入静态特征,并且随着扩展功能的增多,子类会很膨胀。

何时使用:在不想增加很多子类的情况下扩展类。

如何解决:将具体功能职责划分,同时继承装饰者模式。

装饰者通用类图:

三、实现

英雄联盟游戏实现

//抽象基类
public abstract class Hero {//学习技能public abstract void learnSkills();
}//具体英雄兰博,需要被扩展的类
public class Lanbo extends Hero {//英雄属性private String name;public Lanbo(String name){this.name = name;}@Overridepublic void learnSkills() {System.out.println(name + "学习了以上技能!");}
}//抽象技能类,装饰者的抽象基类
public abstract class Skills extends Hero {private Hero hero;public Skills(Hero hero){this.hero = hero;}@Overridepublic void learnSkills() {if(hero!=null){hero.learnSkills();}}
}//具体装饰子类,用来装饰 Q技能
public class Skill_Q extends Skills {private  String skillName;public Skill_Q(Hero hero,String skillName) {super(hero);this.skillName=skillName;}@Overridepublic void learnSkills() {System.out.println("学习了技能Q:" +skillName);super.learnSkills();}
}
//具体装饰子类,用来装饰 W技能
public class Skill_W extends Skills {private  String skillName;public Skill_W(Hero hero,String skillName) {super(hero);this.skillName=skillName;}@Overridepublic void learnSkills() {System.out.println("学习了技能W:" +skillName);super.learnSkills();}
}
//具体装饰子类,用来装饰E技能
public class Skill_E extends Skills {private  String skillName;public Skill_E(Hero hero,String skillName) {super(hero);this.skillName=skillName;}@Overridepublic void learnSkills() {System.out.println("学习了技能E:" +skillName);super.learnSkills();}
}
//具体装饰子类,用来装饰R技能
public class Skill_R extends Skills {private  String skillName;public Skill_R(Hero hero,String skillName) {super(hero);this.skillName=skillName;}@Overridepublic void learnSkills() {System.out.println("学习了技能R:" +skillName);super.learnSkills();}
}

运行:

        //选择英雄Hero hero = new Lanbo("兰博");Skills q = new Skill_Q(hero,"纵火盛宴");Skills w = new Skill_W(q,"破碎护盾");Skills e = new Skill_E(w,"电子鱼叉");Skills r = new Skill_R(e,"恒温灼烧");//学习技能r.learnSkills();

运行结果:

四、总结

优点

  1. 装饰这模式和继承的目的都是扩展对象的功能,但装饰者模式比继承更灵活
  2. 通过使用不同的具体装饰类以及这些类的排列组合,设计师可以创造出很多不同行为的组合
  3. 装饰者模式有很好地可扩展性

缺点:装饰者模式会导致设计中出现许多小对象,如果过度使用,会让程序变的更复杂。并且更多的对象会是的差错变得困难,特别是这些对象看上去都很像。

java.io类就是用的装饰者模式

转载于:https://www.cnblogs.com/yuanqinnan/p/10155806.html

设计模式第三篇-装饰者模式相关推荐

  1. 吃透设计模式第六篇-装饰者模式

    设计模式的重要性对于程序员来说,相当于盾牌对于美国队长,暴风战斧相对于雷神,内裤对于绿巨人(绿巨人最强武器,手动狗头)来说,是必不可少的. 在此,特别总结下23钟设计模式: 创建型模式:单例模式.抽象 ...

  2. 设计模式(三)—— 装饰者模式

    由于之前看的容易忘记,因此特记录下来,以便学习总结与更好理解,该系列博文也是第一次记录,所有有好多不完善之处请见谅与留言指出,如果有幸大家看到该博文,希望报以参考目的看浏览,如有错误之处,谢谢大家指出 ...

  3. 每天两个设计模式(三)装饰器模式(今天就一个)

    文章目录 装饰器模式 引言 概念分析 分析 适配器模式 解决套娃式功能 分析步骤 代码 再次升级 装饰器模式 引言 初看装饰器模式的时候,一脸懵逼,网上一堆博客,也是千篇一律,上来就是举例子,然后直接 ...

  4. 设计模式第三集——装饰者模式(Decorator)

    再次强调设计的重要原则:对扩展开放,对修改关闭.在设计中要尽量避免对之前源代码的修改. 为适应扩展的特性,除了继承之外,还可以用装饰者模式:动态的将新的功能附加到对象上.换句话说,装饰者模式就是有一群 ...

  5. 米线店结账程序 装饰着模式_设计模式(三)装饰者模式

    装饰者模式是以对客户端透明的方式扩展对象的功能,是继承关系的一个替代方案.装饰者模式动态地将责任附加到对象身上,若要扩展功能,装饰者提供了比继承更有弹性的替代方案,比生成子类更加灵活. 通常在继承关系 ...

  6. Java进阶专题(八) 设计模式之适配器模式、装饰者模式、观察者模式

    本章节将介绍:三个设计模式,适配器模式.装饰者模式和观察者模式.通过学习适配器模式,可以优雅的解决代码功能的兼容问题.另外有重构需求的人群一定需要掌握装饰者模式.本章节参考资料书籍<Spring ...

  7. 设计模式(三)结构型模式介绍及实例

    文章目录 一.适配器模式 1.1 适配器模式定义 1.2 适配器模式主要角色 1.3 适配器模式特点 1.4 适配器模式实现方式 1.4.1 类适配器模式 1.4.2 对象适配器模式 1.5 适配器模 ...

  8. php设计模式课程---7、装饰器模式如何使用

    php设计模式课程---7.装饰器模式如何使用 一.总结 一句话总结: 装饰器的核心是获取了文章类整个类,而不是获取了文章内容,有了这个文章类,我想给你加多少装饰就给你加多少装饰(将文章这个类封装进去 ...

  9. 肝一肝设计模式【六】-- 装饰器模式

    系列文章目录 肝一肝设计模式[一]-- 单例模式 传送门 肝一肝设计模式[二]-- 工厂模式 传送门 肝一肝设计模式[三]-- 原型模式 传送门 肝一肝设计模式[四]-- 建造者模式 传送门 肝一肝设 ...

最新文章

  1. android关闭触摸声音,如何在Android中以编程方式禁用触摸时的振动和声音?
  2. 老李推荐: 第8章4节《MonkeyRunner源码剖析》MonkeyRunner启动运行过程-启动AndroidDebugBridge 1...
  3. Request_获取请求行数据_方法介绍
  4. ng-template和对应生成的注释
  5. 使用javax.tools.JavaCompiler根据字符串内容动态生成新的Java类并编译成.class
  6. vtkBorderWidget设置窗口位置的问题
  7. 这是一款深受学生党喜爱的PDF阅读器
  8. layuiajax提交表单控制层代码_Ninja Forms:免费的联系表单插件,却提供了付费表单才有的功能【视频+图文】...
  9. jquery中serialize()序列化函数
  10. “RPC好,还是RESTful好?”,这个问题不简单!
  11. linux centos设置共享目录,在CentOS上配置SAMBA共享目录
  12. 原生ajax接收json字符串(简单介绍)
  13. 浅谈WebView利用localStore websql和IndexDB 来存储数据
  14. JAVA实现Html转Pdf(wkhtmltopdf)
  15. matlab生成16进制正弦波表
  16. 论文阅读笔记|Unsuperised Deep Homography
  17. linux添加键盘布局,Linux 定制键盘布局
  18. 洛蒂(Lottie)
  19. git pull时提示错误:warning: ignoring broken ref refs/remotes/origin/HEAD的解决办法
  20. 企业oa管理系统是什么

热门文章

  1. Struts2教程7:上传任意多个文件
  2. 转 Windows串口过滤驱动程序的开发
  3. (转)C++中extern “C”含义深层探索
  4. Python扑克牌发牌
  5. c语言大作业 模拟泊松分布,C语言下泊松分布以及指数分布随机数生成器实现
  6. 翁恺老师C语言学习笔记(十一)字符串
  7. 去中心化无险永续合约Shield即将在以太坊-Kovan网络发布测试活动
  8. DeFi信用合作社Xend Finance将于今日23时通过Balancer LBP开启公募
  9. Wootrade宣布加入SushiSwa旗下Mirin协议和子池计划
  10. SAP License:大话三国之企业点将