阅读目录什么是装饰者模式

普通示例

装饰者模式示例

类图关系

装饰者模式使用场景

装饰者模式优点

装饰者模式缺点

什么是装饰者模式

装饰者模式(DecoratorPattern)是指在不改变原有对象的基础之上,将功能附加到对

象上,提供了比继承更有弹性的替代方案(扩展原有对象的功能),属于结构型模式。

装饰者模式在生活中也有很多形象的例子,比如说给蛋糕加上一些水果,给披萨加上榴莲,或者说给烧饼加上鸡蛋火腿之类等等。

下面我们就以给蛋糕加上水果为例来看看如果不用装饰者模式要怎么实现,如果使用装饰者模式又要怎么实现,对比之后就知道装饰者模式的优势了。

普通示例

新建一个普通的蛋糕类:

package com.zwx.design.pattern.decorator.common;

import java.math.BigDecimal;

public class Cake {

public String getCakeMsg(){

return "我是一个8英寸的普通蛋糕";

}

public BigDecimal getPrice(){

return new BigDecimal("68");

}

}

这时候,我们需要给蛋糕加点芒果,那可以再新建一个类去继承普通Cake类,然后重写其中的方法:

package com.zwx.design.pattern.decorator.common;

import java.math.BigDecimal;

public class CakeAddMango extends Cake {

@Override

public String getCakeMsg() {

return super.getCakeMsg() + "+1个芒果";

}

@Override

public BigDecimal getPrice() {

return super.getPrice().add(new BigDecimal("10"));

}

}

这时候,如果不仅仅加芒果,还要再加点葡萄,那么可以再写一个类,继承CakeAddMango,然后重写其中的方法。

package com.zwx.design.pattern.decorator.common;

import java.math.BigDecimal;

public class CakeAddMangoAndGrape extends CakeAddMango {

@Override

public String getCakeMsg() {

return super.getCakeMsg() + "+1个葡萄";

}

@Override

public BigDecimal getPrice() {

return super.getPrice().add(new BigDecimal("5"));

}

}

写个测试类测一下:

package com.zwx.design.pattern.decorator.common;

public class TestCake {

public static void main(String[] args) {

//普通蛋糕 Cake cake = new Cake();

System.out.println(cake.getCakeMsg() + ",价格:" + cake.getPrice());

//加芒果蛋糕 CakeAddMango cakeAddMango = new CakeAddMango();

System.out.println(cakeAddMango.getCakeMsg() + ",价格:" + cakeAddMango.getPrice());

//加芒果和葡萄蛋糕 CakeAddMangoAndGrape cakeAddMangoAndGrape = new CakeAddMangoAndGrape();

System.out.println(cakeAddMangoAndGrape.getCakeMsg() + ",价格:" + cakeAddMangoAndGrape.getPrice());

}

}

输出如下结果:

我是一个8英寸的普通蛋糕,价格:68

我是一个8英寸的普通蛋糕+1个芒果,价格:78

我是一个8英寸的普通蛋糕+1个芒果+1个葡萄,价格:83

看起来挺好的,能实现,但是假如我们加2个芒果呢?或者是我要加2个普通呢,或者说芒果和葡萄要组合,数量不一定,那利用现有的类是无法实现的,只能不断加类去重写,如果业务变更频繁,修改起来会是致命的。

正因为普通的实现方法有这种缺陷,才有了装饰者模式,接下来我们来看看同一个需求利用装饰者模式是怎么实现的吧。

装饰者模式示例

1、新建一个蛋糕的抽象类:

package com.zwx.design.pattern.decorator;

import java.math.BigDecimal;

public abstract class Cake {

public abstract String getCakeMsg();

public abstract BigDecimal getPrice();

}

2、然后新建一个普通蛋糕的类:

package com.zwx.design.pattern.decorator;

import java.math.BigDecimal;

public class BaseCake extends Cake {

@Override

public String getCakeMsg() {

return "我是一个8英寸的普通蛋糕";

}

@Override

public BigDecimal getPrice() {

return new BigDecimal("68");

}

}

3、新建一个蛋糕的装饰器类,内部持有蛋糕Cake对象,这个就是扩展的关键:

package com.zwx.design.pattern.decorator;

import java.math.BigDecimal;

public abstract class CakeDecorator extends Cake{

private Cake cake;

public CakeDecorator(Cake cake) {

this.cake = cake;

}

@Override

public String getCakeMsg() {

return this.cake.getCakeMsg();

}

@Override

public BigDecimal getPrice() {

return this.cake.getPrice();

}

}

4、新建一个芒果蛋糕的装饰器类继承CakeDecorator类:

package com.zwx.design.pattern.decorator;

import java.math.BigDecimal;

public class CakeAddGrapeDecorator extends CakeDecorator {

public CakeAddGrapeDecorator(Cake cake) {

super(cake);

}

@Override

public String getCakeMsg() {

return super.getCakeMsg() + "+1个葡萄";

}

@Override

public BigDecimal getPrice() {

return super.getPrice().add(new BigDecimal("5"));

}

}

5、新建一个葡萄的装饰器类继承CakeDecorator类:

package com.zwx.design.pattern.decorator;

import java.math.BigDecimal;

public class CakeAddMangoDecorator extends CakeDecorator {

public CakeAddMangoDecorator(Cake cake) {

super(cake);

}

@Override

public String getCakeMsg() {

return super.getCakeMsg() + "+1个芒果";

}

@Override

public BigDecimal getPrice() {

return super.getPrice().add(new BigDecimal("10"));

}

}

6、最后写一个测试类测试一下:

package com.zwx.design.pattern.decorator;

public class TestCakeDecorator {

public static void main(String[] args) {

Cake cake = null;

//普通蛋糕 cake = new BaseCake();

System.out.println(cake.getCakeMsg() + ",价格:" + cake.getPrice());

//加一个芒果 cake = new CakeAddMangoDecorator(cake);

System.out.println(cake.getCakeMsg() + ",价格:" + cake.getPrice());

//加一个葡萄 cake = new CakeAddGrapeDecorator(cake);

System.out.println(cake.getCakeMsg() + ",价格:" + cake.getPrice());

//再加一个芒果 cake = new CakeAddMangoDecorator(cake);

System.out.println(cake.getCakeMsg() + ",价格:" + cake.getPrice());

}

}

输出结果为:

我是一个8英寸的普通蛋糕,价格:68

我是一个8英寸的普通蛋糕+1个芒果,价格:78

我是一个8英寸的普通蛋糕+1个芒果+1个葡萄,价格:83

我是一个8英寸的普通蛋糕+1个芒果+1个葡萄+1个芒果,价格:93

我们可以看到,使用装饰者模式之后,扩展之前的功能变得极为方便,可以根据现有的装饰器进行任意组合。

类图关系

看一下类图,首先是一个基础抽象类定义了基本方法,然后是基础实现和基础装饰器继承并重写抽象类中的方法:

装饰者模式使用场景1、用于扩展一个类的功能或给一个类添加附加职责。

2、动态的给一个对象添加功能,这些功能可以再动态的撤销。

注:MyBatis中的二级缓存就是用了装饰者模式来进行动态扩展,感兴趣的可以去了解下。

装饰者模式优点1、装饰者是继承的有力补充,比继承灵活,不改变原有对象的情况下动态地给一个对象 扩展功能,即插即用。

2、通过使用不同装饰类以及这些装饰类的排列组合,可以实现不同效果。

3、装饰者完全遵守开闭原则。

装饰者模式缺点1、会出现更多的代码,更多的类,增加程序复杂性。

2、动态装饰以及多层装饰时会更加复杂。

END

java 装饰者模式 替代方案_如何利用装饰者模式在不改变原有对象的基础上扩展功能...相关推荐

  1. 如何利用装饰者模式在不改变原有对象的基础上扩展功能

    点击上方蓝色"方志朋",选择"设为星标" 回复"666"获取独家整理的学习资料! 作者:双子孤狼 blog.csdn.net/zwx9001 ...

  2. java对接支付宝微信银联_经典设计模式之策略模式【如何重构聚合支付平台,对接【支付宝,微信,银联支付】】(示例代码)...

    写在前面:设计模式源于生活,而又高于生活! 为什么要使用设计模式重构代码 使用设计模式可以重构整体架构代码.提高代码复用性.扩展性.减少代码冗余问题. Java高级工程师装逼的技能! 什么是策略模式 ...

  3. netflix 模式创新_创新设计模式:工厂模式

    netflix 模式创新 以前,我们对创建模式进行了介绍,并使用抽象工厂模式来创建对象族. 下一个模式是Factory模式 . 当涉及到Java时,工厂模式是最常用的模式之一. 那么工厂模式到底是什么 ...

  4. 安卓访客模式_Android 5.0利用访客模式设置双桌面教程

    小编一直都在疑惑,为何Android系统不能够像电脑一样设置一个不同的桌面,以免别人在玩自己手机的时候把自己的系统弄得乱七八糟.这么方便的功能为何没有被考虑在内,难道是工程师们都忘记了?事实其实并不是 ...

  5. python装饰器调用顺序_聊一聊Python装饰器的代码执行顺序

    为什么写这篇文章? 起因是QQ群里边有人提了一个问题:之前导入模块只需要1~2秒,为什么现在变成需要2~3分钟? 我的第一感觉是:是不是导入的模块顶层代码里边,做了什么耗时的事情.隔了一天,他的问题解 ...

  6. java迭代器的使用场景_集合遍历利器 -- 迭代器模式 介绍 使用场景案例 优缺点及程序演示...

    一句话概括: 顺序访问集合对象的元素,不需要知道集合对象的底层表示. 补充介绍: 迭代器模式(Iterator Pattern)相信大家都已经见过不少次了,当你学习Java或者其他编程语言的开始你就会 ...

  7. java语言描述一个行为_设计模式之责任链模式——Java语言描述

    责任链模式为请求创建了一个接受者对象的链.这种模式给予请求的类型,对请求的发送者和接受者进行解耦.这种类型的设计模式属于行为模式.在这种模式下,通常每个接收者都包含对另一个接收者的引用.如果一个对象不 ...

  8. java 如何循环执行一个对象_养猪场循环生态循环模式及其效益分析,当前牧草成为生态循环猪场效益更好的选择,如何打造一个现代生态循环的高效益猪场?...

    养猪场循环生态循环模式及其效益分析 2010年前的推广模式参考 随着国民经济的快速发展,人民的生活水平在不断提高,民众对环境的要求也越来越高,包括人文环境和自然环境.同时,农村地区的环境治理工作也逐渐 ...

  9. java pdf增删改查_如何利用Java代码操作索引库?

    今天是刘小爱自学Java的第161天. 感谢你的观看,谢谢你. 学习计划安排如下: 学了几天的Elasticserch,但都是它本身的知识点,如何通过Java语言去操作它呢? 这就好比以前学数据库,在 ...

  10. java我的世界极限生存_我的世界极限生存模式攻略 极限生存心得

    我的世界minecraft中的极限模式可能会成为你所玩过的最难的游戏.请小心,一旦死亡,你将无法重生,即从磁盘上删除这个存档.(在极为罕见的情况下,可能不会从你的硬盘上删除,但是在重新打开时会弹出提示 ...

最新文章

  1. hdu5184 给出(和)前半段问后面有多少种加括号方法使合法:类似卡特兰数+逆元模板...
  2. HttpClient, 使用C#操作Web
  3. C++从入门到放肆!
  4. JDBC技术总结(一)
  5. linux能运行安卓模拟器吗,Ubuntu 14.04中使用模拟器运行Android系统
  6. R语言快速深度学习进行回归预测(转)
  7. 基于RPC原理的Dubbo
  8. ASP.NET 性能监控工具和优化技巧
  9. pycharm不能输入代码
  10. html中字体 楷体_html常用的字体样式
  11. 和利时dcs系统服务器设置,和利时DCS控制系统组态流程简介
  12. 【matlab图像处理】图像处理工具箱(1)
  13. 联想拯救者Y7000P2020 RTX2060显卡 AX201网卡 安装Ubuntu16.04采坑记录
  14. 程序员好用的 Markdown 笔记软件
  15. 一切皆是文件:UNIX,Linux 操作系統的設計哲學
  16. 用户计算机MAC地址在哪看,电脑mac地址查询_mac地址怎么查-太平洋IT百科
  17. 计算机课英语怎么读音标,英语的48个音标有哪些?英语的48个音标怎么读?
  18. Excel快捷键大全和35个函数---第二弹
  19. 华为的芯片战略:别忘记,代号—SD502!
  20. 如何用laragon框架运行php文件

热门文章

  1. 模块ntdll中出现异常eaccessviolation_SAP ERP软件中的物料凭证 MIGO
  2. Python3实现Win10桌面背景自动切换
  3. 【284天】每日项目总结系列022(2017.11.16)
  4. pg_stat wait timeout
  5. D3D 扎带 小样本
  6. vector容器——容量和大小
  7. java删除未引用的库_利用Proguard移除无用代码以及碰到的坑
  8. python文件中写中文_解决python中csv文件中文写入问题
  9. OpenCV-图像处理(25、直方图比较)
  10. 华硕主板如何设置开机自启_华硕主板自动开机的设置方法.doc