由孙悟空的七十二变看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设计模式---装饰者模式
写在前面的话: 该模式动态的将责任附加到对象上,若要扩展功能,装饰者提供了比继承更有弹性的替代方案.装饰者可以在被装饰者的行为前面与/或后面加上自己的行为,甚至将被装饰者的行为整个取代掉,而达到特定的 ...
随机推荐
- ASM的基础用法
本文转载自ASM的基础用法 导语 新闻里使用的热补丁修复方案是基于AspectJ,AspectJ是AOP的一种实现. 无意接触到一种小巧轻便的Java字节码操控框架ASM,它也能方便地生成和改造Jav ...
- 别再人云亦云了!!!你真的搞懂了RDD、DF、DS的区别吗?
几年前,包括最近,我看了各种书籍.教程.官网.但是真正能够把RDD.DataFrame.DataSet解释得清楚一点的.论据多一点少之又少,甚至有的人号称Spark专家,但在这一块根本说不清楚.还有国 ...
- 通过CollectionUtils工具类判断集合是否为空,通过StringUtils工具类判断字符串是否为空
通过CollectionUtils工具类判断集合是否为空 先引入CollectionUtils工具类: import org.apache.commons.collections4.Collectio ...
- Git 命令将电脑上的文件上传到 Github
1.在电脑上安装 Windows 版 Git下载地址:https://git-scm.com/downloads2.使用 Git GUI 生成 SSH Key 3.将 SSH Key 添加到 Gith ...
- SpringBoot(一):使用IDEA快速搭建一个SpringBoot项目(详细)
环境: JDK1.8 Maven:3.5.4 1.打开IDEA,右上角选择File→New→Project 选择Spring Initializr(使用IDEA自带的插件创建需要电脑联网) 2.点 ...
- [个人总结]pytorch中用checkpoint设置恢复,在恢复后的acc上升
原因是因为checkpoint设置好的确是保存了相关字段.但是其中设置的train_dataset却已经走过了epoch轮,当你再继续训练时候,train_dataset是从第一个load_data开 ...
- Shell脚本控制docker容器启动顺序
1.遇到的问题 在分布式项目部署的过程中,经常要求服务器重启之后,应用(包括数据库)能够自动恢复使用.虽然使用docker update --restart=always containerid能够让 ...
- let、const、var区别?
let.const.var区别? let和const不存在变量提升(没有预解析,var有预解析). let和const在同一作用域范围内不能重复定义变量.(var可以). let和const有严格的作 ...
- ClickHouse元数据异常-MySQLHandlerFactory:Failed to read RSA key pair from server
Clickhouse版本:20.3.6.40-2 clickhouse集群三个节点,一分片,三副本,三个节点数据完全一样 1. 问题描述 在使用连接工具操作时,发现其中一个节点连接拒绝,无法操作,另外 ...
- vue项目安装sass步骤等遇到的问题
1.安装sass依赖包 npm install --save-dev sass-loader 注释(可能会出现问题:sass-loader版本过高导致,可以将其package.json中的版本改为7. ...