在讲装饰器模式之前,我先讲讲代码实例,在讲具体的原理和结构。

情景:游戏中经常使用枪(英文:Gun),有手枪(英文:Pistol),狙击枪(英文:SniperRifle)等等。
然后枪有个基本功能,肯定是fire,也许shot更恰当,如果用代码实现,大致如下:

  • 抽象类:枪(Gun)
public abstract class Gun {//开火public abstract Fire fire();
}
  • 具体类:手枪(Pistol),继承于 Gun
public class Pistol extends Gun{@Overridepublic Fire fire() {Fire fire = new Fire();fire.setRange(50); //射程50fire.setVoice(false); //开火有声音return fire;}
}
  • 具体类:狙击枪(SniperRifle),继承于 Gun
public class SniperRifle extends Gun{@Overridepublic Fire fire() {Fire fire = new Fire();fire.setRange(400);//射程400fire.setVoice(false);//开火有声音return fire;}
}

枪可能有很多种,这里,就是举两个。

  • 开火属性类,表示开火的属性。
public class Fire {//射程private int range; //开枪是否有声音private boolean voice; @Overridepublic String toString() {return "[射程:" + range + ","+((voice) ? "消音":"没有消音")+"]";}/***************************getter & setter*******************************/public int getRange() {return range;}public void setRange(int range) {this.range = range;}public boolean isVoice() {return voice;}public void setVoice(boolean voice) {this.voice = voice;}/***************************getter & setter*******************************/
}

在没有给枪装任何配件的情况下,这就是裸枪了。开火始终有声音,射程总是不变。
现在,我们用装饰器模式给枪装配件,我们设定如下:

  1. 如果装上消音器(英文:Silencer),可以消音
  2. 如果装上瞄准镜(英文:Collimation Mirror),可以增加射程。

我们代码实现如 :

  • 我们定义一个配件的父类,这个类可以不是抽象类,但是很明显,定义为abstract 更符合语义
/*** 配件父类*/
public abstract class DecorateParts extends Gun{protected Gun gun;/**核心方法,这个方法很关键,是装饰器模式的核心 */@Overridepublic Fire fire() {return (gun != null) ? gun.fire() : null;}/**安装配件*/public void install(Gun gun) {this.gun = gun;}}
  • 具体配件类:消音器
/*** 消音器*/
public class Silencer extends DecorateParts{@Overridepublic Fire fire() {Fire fireResult = super.fire();fireResult.setVoice(true);//装上消音return fireResult;}}
  • 具体配件类:瞄准镜
/*** 瞄准镜*/
public class CollimationMirror extends DecorateParts{//增加的射程,这里设定增加100射程private int addRange = 100;@Overridepublic Fire fire() {Fire fireResult = super.fire();//增加射程fireResult.setRange(fireResult.getRange() + addRange);return fireResult;}}

至此,配件相关的类也写完了,接下来,测试一下:

public class DecorateMain {public static void main(String[] args) {//创建一把手枪Pistol gun = new Pistol();System.out.println("手枪-[裸枪]-" + gun.fire());//创建一个瞄准镜,裸枪上,安装瞄准镜CollimationMirror mirrorGun = new CollimationMirror();mirrorGun.install(gun);System.out.println("手枪-[瞄准镜]-" + mirrorGun.fire());//创建一个消音器,在安装了瞄准镜的基础上,再安装消音器Silencer silencerMirrorGun = new Silencer();silencerMirrorGun.install(mirrorGun);System.out.println("手枪-[瞄准镜,消音器]-" + silencerMirrorGun.fire());//创建一个消音器,裸枪上,安装消音器Silencer silencerGun = new Silencer();silencerGun.install(gun);System.out.println("手枪-[消音器]-" + silencerGun.fire());}
}

具体的运行结果如下:

在不影响枪的情况下,对枪进行装饰,主要还是看配件的3个类。
DecorateParts 本质上他不是配件,他继承了Gun,然后还有一个Gun的引用(protected Gun gun),
可以说这是装饰器模式关键。
我们从代码中可以知道,手枪,狙击枪是在Gun的基础上进行扩展,而消音器,瞄准器是在DecorateParts 上扩展。

/*** 消音器*/
public class Silencer extends DecorateParts{@Overridepublic Fire fire() {Fire fireResult = super.fire();fireResult.setVoice(true);//装上消音return fireResult;}}

我们主要分析下消音器,使用装饰器模式,基本上第一个的方法的就是super.fire(),也就是调用父类的同名方法,
这也代理模式有些相似,但是并不相同。看如下代码,也是就是配件的装配过程:
Pistol gun = new Pistol();
mirrorGun.install(gun);
silencerMirrorGun.install(mirrorGun);

对于silencerMirrorGun;super.fire()其实就是mirrorGun.fire();
对于mirrorGun,super.fire()其实是gun.fire()
由此可见:silencerMirrorGun.fire()中第一步调用了mirrorGun.fire(),mirrorGun.fire()第一步调用了gun.fire()。
所以mirrorGun.fire()是在gun.fire()上装饰,而silencerMirrorGun.fire()在mirrorGun.fire()的基础上装饰。
这就是装饰模式的真正意义。而代理模式也是类似,不过代理一般不会改变方法的返回结果,装饰器模式一遍都是多层的,也就是说装配了很多东西,而代理模式一般也就只有一层而已。

最后来看看装饰器模式的类图结构,图片来自大话设计模式,如下:

与我上面的例子其实很容易对应,如下:
(Component – Gun)
(ConcreteComponent – Pistol)
(Decorator – DecorateParts)
(ConreteDecoratorA – Silencer)
(ConreteDecoratorB – CollimationMirror)

结语:当系统需要新的功能的时候,而且是像旧的类中添加新的代码。这些新的逻辑通常修饰了原有类的核心设计和职责。这时候可以考虑用装饰器模式

从吃鸡中论装饰器模式相关推荐

  1. 【设计模式(九)】结构型模式之装饰器模式

    个人学习笔记分享,当前能力有限,请勿贬低,菜鸟互学,大佬绕道 如有勘误,欢迎指出和讨论,本文后期也会进行修正和补充 前言 中秋刚过没多久,虽然我这种粗人对月饼无感,但是公司发的肯定得收的嘛 拿回家当零 ...

  2. JS设计模式——装饰器模式

    什么是装饰器模式? 装饰器模式(Decorator Pattern)允许向一个现有的对象添加新的功能,同时又不改变其结构.这种类型的设计模式属于结构型模式,它是作为现有的类的一个包装. 实例 拿最近比 ...

  3. 装饰器模式与java.io包

    为什么80%的码农都做不了架构师?>>>    Decorator设计模式是典型的结构型模式(在GOF的那本模式的Bible中将模式分为:1.创建型模式:2.结构型模式:3.行为模式 ...

  4. 设计模式之门面模式与装饰器模式详解和应用

    目录 1 门面模式定义 1.1 门面模式的应用场景 1.2 门面模式的通用写法 1.3 门面模式业务场景实例 1.4 门面模式在源码中的应用 1.5 门面模式的优缺点 2 装饰器模式 2.1 装饰器模 ...

  5. 从一碗小米粥谈装饰器模式,代理模式的区别

    代理与装饰器 场景描述 代理即代替意思,可替代原类的所有功能,即和原类实现相同的规范.代理模式和装饰器模式很像. 每天清晨起来,紧张的洗漱之后,来到楼下的早餐店,我通常都会要一碗小米粥,这时候盛粥的大 ...

  6. C++设计模式:装饰器模式

      装饰器模式(Decorator Mode), 别名,包装器Wraaper.   ​装饰器模式的作用是为了实现动态的给对象添加职能,即从外部给对象添加相关职能.可以这样理解,比如说一个Person类 ...

  7. 设计模式--装饰器模式(8)

    目录 前言 定义 优点与缺点 优点 缺点 装饰器模式的结构与实现 模式的结构 结构图 代码实现 需求 代码 component Morrigan concreteComponent Original ...

  8. 设计模式系列【24】:装饰器模式(装饰设计模式)详解

    上班族大多都有睡懒觉的习惯,每天早上上班时间都很紧张,于是很多人为了多睡一会,就会用方便的方式解决早餐问题.有些人早餐可能会吃煎饼,煎饼中可以加鸡蛋,也可以加香肠,但是不管怎么"加码&quo ...

  9. 手抓饼加生菜加鸡蛋的装饰器模式

    装饰器模式 装饰器模式(Decorator Patter),也称为包装模式(Wrapper Pattern)是指在不改变原有对象的基础之上,将功能附加在对象上,提供了比继承更有弹性的替代方案(扩展原有 ...

最新文章

  1. 亿级系统的Redis缓存如何设计???
  2. 如何利用单片机IO口产生两倍的电源电压
  3. 容易被误读的IOSTAT
  4. python中configparser详解_Python中的ConfigParser模块使用详解
  5. android脚步---不同activity之间参数传递
  6. Git实战(二)原理
  7. 离线登陆_iphone手机,苹果手机如何登陆网易163邮箱
  8. java控制单元测试_java – 当单元测试控制器时,模拟一个Spring Validator
  9. 从头来之【iOS及历史版本特性介绍】
  10. arcgis支持python3吗_常见问题解答:ArcGIS 中使用的 Python 是什么版本?
  11. 输入输出系统的发展概况
  12. 基于Qt设计的学生考勤系统
  13. ISSCC2021 基于SRAM的存内计算16.3阅读记录
  14. VBA 下载图片到word
  15. 第九章 亚瑟龙的召唤
  16. vue 页脚_如何将页脚固定在页面底部_sticky footer, Layout, templates, 会员专栏 教程_w3cplus...
  17. 我们认为2是第一个素数,3是第二个素数,5是第三个素数,依次类推。 现在,给定两个整数n和m,0<n<=m<=200,你的程序要计算第n个素数到第m个素数之间所有的素数的和,包括第n个素数和第m个素数
  18. 一文搞定细菌基因组De Novo测序分析
  19. 2018noip普及组初赛竞赛总结
  20. mac修改mysql密码(亲测)

热门文章

  1. 在CentOS7.x版本上搭建Greenplum5.1.0数据库详细步骤讲解
  2. 微信小程序 - 考试前三排名实现
  3. elementUI日常使用tips
  4. 哈哈哈哈 (外一则)
  5. 从《雷神3》洛基下落30分钟学英语时态
  6. 利用windows自带的工具终止顽固进程
  7. 英雄联盟大师预测赛方案分享-模型融合
  8. ubuntu如何挂载硬盘
  9. vue两个按钮切换_vue实现按钮切换图片
  10. 关于AJAX的ScriptManager.RegisterClientScriptBlock无法弹出对话框的解决方法【归类】