由孙悟空的七十二变看Java设计模式:装饰者模式
应用场景
京东、天猫双十一,情人节商品大促销,各种商品有不同的促销活动
- 满减:满200减50
- 每满减:每满100减10
- 打折:买两件8折,三件7折
- 数量减:满三件减去最低价的一件
假设现在顾客买了两件衣服先是打了8折,然后又满200减了50,促销活动多重叠加了,该如何灵活实现订单金额计算?
代码示例
PromotionAlgorithm接口,计算订单金额:
public interface PromotionAlgorithm {
Order promotionAlgorithm(Order order);
}
实现类PromotionAlgorithm1、PromotionAlgorithm2:
public class PromotionAlgorithm1 implements PromotionAlgorithm {
@Override
public Order promotionAlgorithm(Order order) {
System.out.println("打8折");
order.setPrice(order.getPrice() * 0.8);
return order;
}
}
public class PromotionAlgorithm2 implements PromotionAlgorithm {
@Override
public Order promotionAlgorithm(Order order) {
System.out.println("满200减了50");
order.setPrice(order.getPrice() - 50);
return order;
}
}
OrderService类:
public class OrderService {
public Order getOrderPrices(Order order, String... promotion) {
for (String s : promotion) {
if (s.equals("promotion-1")) {
new PromotionAlgorithm1().promotionAlgorithm(order);
} else if (s.equals("promotion-2")) {
new PromotionAlgorithm2().promotionAlgorithm(order);
}
}
return order;
}
}
测试类:
public class Test {
public static void main(String[] args) {
OrderService service = new OrderService();
Order order = new Order();
order.setPrice(1000.0);
String[] array = {"promotion-1", "promotion-2"};
Order result = service.getOrderPrices(order, array);
System.out.println("最终我花了:" + result.getPrice());
}
}

现在思考一下,当需要对一个类的多个方法进行增强时,使用者会随意使用被增强方法时,上面的for循环还灵活吗
改进代码
定义一个接口OrderComponent:
public interface OrderComponent {
/** 促销方式 */
String getPromotion();
/** 价格 */
Double getPrice();
}
OrderConcreteComponent类:需要进行计算的类
public class OrderConcreteComponent implements OrderComponent {
@Override
public String getPromotion() {
return "我买了三件衣服,衣服总共1000元,";
}
@Override
public Double getPrice() {
return 1000.0;
}
}
OrderDecorator类:有一个属性,是上面的接口OrderComponent,实现了OrderComponent接口
public class OrderDecorator implements OrderComponent {
public OrderComponent component;
public OrderDecorator(OrderComponent component) {
this.component = component;
}
@Override
public String getPromotion() {
return this.component.getPromotion();
}
@Override
public Double getPrice() {
return this.component.getPrice();
}
}
OrderDecoratorA类:打折类
public class OrderDecoratorA extends OrderDecorator {
public OrderDecoratorA(OrderComponent component) {
super(component);
}
@Override
public String getPromotion() {
return this.component.getPromotion() + "衣服打了8折,";
}
@Override
public Double getPrice() {
return this.component.getPrice() * 0.8;
}
}
OrderDecoratorB类:满减类
public class OrderDecoratorB extends OrderDecorator {
public OrderDecoratorB(OrderComponent component) {
super(component);
}
@Override
public String getPromotion() {
return this.component.getPromotion() + "又满200减了50。";
}
@Override
public Double getPrice() {
return this.component.getPrice() - 50;
}
}
测试类:
public class Test {
public static void main(String[] args) {
OrderComponent component = new OrderConcreteComponent();
OrderComponent c = new OrderDecorator(component);
OrderComponent d = new OrderDecoratorA(c);
OrderComponent e = new OrderDecoratorB(d);
System.out.println(e.getPromotion());
System.out.println("最终我花了:" + e.getPrice());
}
}

上面的改进代码,就是装饰者模式的基本运用
装饰者模式
定义
以装饰的方式,动态地将责任附加到对象上,同时又不改变其结构
意图
动态地给一个对象添加一些额外的职责。就增加功能来说,装饰者模式相比生成子类更为灵活
主要解决问题
一般的,我们为了扩展一个类经常使用继承方式实现,由于继承为类引入静态特征,并且随着扩展功能的增多,子类会很膨胀
何时使用
在不想增加很多子类的情况下扩展类
优缺点
优点:
- 不改变具体类代码,动态叠加增强行为功能
- 若要扩展功能,装饰者提供了比继承更有弹性的替代方案
- 装饰类和被装饰类可以独立发展,不会相互耦合
缺点:
- 多层装饰比较复杂
类图:

涉及到的角色:
- 抽象构建(Component)角色:给出一个抽象接口,来规范准备接收附加责任的对象
- 具体构建(ConcreteComponent)角色:定义一个将要接收附加责任的类,即被装饰者
- 装饰(Decorator)角色:持有一个构建(Component)对象的实例,并定义一个与抽象接口一致的接口
- 具体装饰(ConcreteDecorator)角色:即上图中的DecoratorA、DecoratorB,负责给构建对象贴上附加的责任,即具体的功能增强行为在这个角色里面
Component类:
public interface Component {
void sampleOperation();
}
ConcreteComponent类:
public class ConcreteComponent implements Component {
@Override
public void sampleOperation() {
//do something
}
}
Decorator类:
public class Decorator implements Component {
private Component component;
public Decorator(Component component) {
this.component = component;
}
@Override
public void sampleOperation() {
this.component.sampleOperation();
}
}
ConcreteDecorator类:
public class ConcreteDecorator extends Decorator {
public ConcreteDecorator(Component component) {
super(component);
}
@Override
public void sampleOperation() {
super.sampleOperation();
}
}
装饰者模式常常也被称为包裹模式,就是因为每一个具体的装饰类都将下一个具体装饰类或者具体构建类包裹起来
假设有2个具体装饰类Decorator1、Decorator2,还有一个具体构建类ConcreteComponent:

是的没错,就是像套娃一样,一层包裹一层
孙悟空的七十二变
大家都知道,孙悟空有七十二般变化,每一种变化都会给他带来一种附加的本领,变成鱼可以在水中游,变成鸟可以在空中飞,但是无论怎么样的变化,在二郎神眼中,还是一只猴子

齐天大圣类:拥有七十二般变化
public interface MonkeyKing {
/** 七十二变 */
String change();
}
大圣本尊类:
public class ConcreteMonkey implements MonkeyKing {
@Override
public String change() {
return "我是齐天大圣本尊!";
}
}
大圣化身类:
public class DecoratorMonkeyChange implements MonkeyKing {
public MonkeyKing king;
public DecoratorMonkeyChange(MonkeyKing king) {
this.king = king;
}
@Override
public String change() {
return this.king.change();
}
}
大圣具体化身类:
public class DecoratorMonkeyChange1 extends DecoratorMonkeyChange {
public DecoratorMonkeyChange1(MonkeyKing king) {
super(king);
}
@Override
public String change() {
return this.king.change() + "变成了鱼!";
}
}
public class DecoratorMonkeyChange2 extends DecoratorMonkeyChange {
public DecoratorMonkeyChange2(MonkeyKing king) {
super(king);
}
@Override
public String change() {
return this.king.change() + "变成了鸟!";
}
}
测试类:
public class TestMonkey {
public static void main(String[] args) {
MonkeyKing king = new ConcreteMonkey();
MonkeyKing a = new DecoratorMonkeyChange(king);
MonkeyKing b = new DecoratorMonkeyChange1(a);
MonkeyKing c = new DecoratorMonkeyChange2(b);
System.out.println(c.change());
}
}

类图:

由孙悟空的七十二变看Java设计模式:装饰者模式的更多相关文章
- JAVA设计模式--装饰器模式
装饰器模式 装饰器模式(Decorator Pattern)允许向一个现有的对象添加新的功能,同时又不改变其结构.这种类型的设计模式属于结构型模式,它是作为现有的类的一个包装. 这种模式创建了一个装饰 ...
- 从源码角度理解Java设计模式——装饰者模式
一.饰器者模式介绍 装饰者模式定义:在不改变原有对象的基础上附加功能,相比生成子类更灵活. 适用场景:动态的给一个对象添加或者撤销功能. 优点:可以不改变原有对象的情况下动态扩展功能,可以使扩展的多个 ...
- 【设计模式】Java设计模式 - 装饰者模式
Java设计模式 - 装饰者模式 不断学习才是王道 继续踏上学习之路,学之分享笔记 总有一天我也能像各位大佬一样 原创作品,更多关注我CSDN: 一个有梦有戏的人 准备将博客园.CSDN一起记录分享自 ...
- Java设计模式——装饰者模式
JAVA 设计模式 装饰者模式 用途 装饰者模式 (Decorator) 动态地给一个对象添加一些额外的职责.就增加功能来说,Decorator 模式相比生成子类更为灵活. 装饰者模式是一种结构式模式 ...
- JAVA 设计模式 装饰者模式
用途 装饰者模式 (Decorator) 动态地给一个对象添加一些额外的职责.就增加功能来说,Decorator 模式相比生成子类更为灵活. 装饰者模式是一种结构式模式. 结构
- Java 设计模式—装饰者模式
在Java编程语言中,嵌套了非常多设计模式的思想,比如IO流中的缓冲流就使用到以下要介绍的装饰者设计模式. 演示样例代码: * 抽象构件角色:定义一个抽象接口,来规范准备附加功能的类 * @autho ...
- Java设计模式--装饰器模式到Java IO 流
装饰器模式 抽象构件角色:给出一个抽象接口,以规范准备接受附加责任的对象. 具体构件角色:定义准备接受附加责任的对象. 抽象装饰角色:持有一个构件对象的实例,并对应一个与抽象构件接口一致的接口. 具体 ...
- Java设计模式の装饰者模式
目录 一.问题引入 二.设计原则 三.用装饰者模式解决问题 四.装饰者模式的特点 五.装饰者模式的定义 六.装饰者模式的实现 七.java.io包内的装饰者模式 一.问题引入 咖啡店的类设计: 一个饮 ...
- JAVA设计模式---装饰者模式
写在前面的话: 该模式动态的将责任附加到对象上,若要扩展功能,装饰者提供了比继承更有弹性的替代方案.装饰者可以在被装饰者的行为前面与/或后面加上自己的行为,甚至将被装饰者的行为整个取代掉,而达到特定的 ...
随机推荐
- 【Notes】现代图形学入门_02
跟着闫令琪老师的课程学习,总结自己学习到的知识点 课程网址GAMES101 B站课程地址GAMES101 课程资料百度网盘[提取码:0000] 光栅化 着色(Shading) 在图形学中,着色的定义可 ...
- CentOS7安装ZooKeeper3.4.14
1:下载安装包 wget https://downloads.apache.org/zookeeper/zookeeper-3.4.14/zookeeper-3.4.14.tar.gz 点击进入官网下 ...
- docker轻量级监控-sysdig
sysdig Sysdig = system(系统)+dig(挖掘).Sysdig 是一个开源系统发掘工具,用于系统级别的勘察和排障,可以把它看作一系列Linux系统工具的组合,主要包括: strac ...
- Python镜像源集合——镜像源更改方法
python在线安装库时会较慢,那是因为python的默认镜像源在国外,因此会慢:而国内有很多可以用的python镜像源,将python镜像源更改为国内的,则可以大大加快python库的安装速度. 1 ...
- Python函数注解
目录 函数注解概述 实际应用 inspect模块 业务代码 总结 以下内容基于Python 3x 涉及的知识前提: 建议理解Python装饰器后学习此内容 函数注解概述 函数注解可以针对函数的参数.返 ...
- 40. 组合总和 II + 递归 + 回溯 + 记录路径
40. 组合总和 II LeetCode_40 题目描述 题解分析 此题和 39. 组合总和 + 递归 + 回溯 + 存储路径很像,只不过题目修改了一下. 题解的关键是首先将候选数组进行排序,然后记录 ...
- HDR(高动态范围)
一: 简介 一般来说,当存储在帧缓冲(Framebuffer)中时,亮度和颜色的值是默认被限制在0.0到1.0之间的. 但是如果我们遇上了一个特定的区域,其中有多个亮光源使这些数值总和超过了1.0,又 ...
- Mock 框架 Moq 的使用
Mock 框架 Moq 的使用 Intro Moq 是 .NET 中一个很流行的 Mock 框架,使用 Mock 框架我们可以只针对我们关注的代码进行测试,对于依赖项使用 Mock 对象配置预期的依赖 ...
- 选择 FreeBSD 而不是 Linux 的技术性原因3
选择 FreeBSD 而不是 Linux 的技术性原因3 jail FreeBSD Jails 系统是另一个惊人的工程壮举. 在 2000 年 3 月 14 日的 4.0 版本中,FreeBSD 引入 ...
- ECMAScript 2016(ES7)新特性简介
简介 自从ES6(ECMAScript 2015)在2015年发布以来,ECMAScript以每年一个版本的速度持续向前发展.到现在已经是ECMAScript 2020了. 每个版本都有一些新的特性, ...