应用场景

京东、天猫双十一,情人节商品大促销,各种商品有不同的促销活动

  • 满减:满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());
}
}



上面的改进代码,就是装饰者模式的基本运用

装饰者模式

定义

以装饰的方式,动态地将责任附加到对象上,同时又不改变其结构

意图

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

主要解决问题

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

何时使用

在不想增加很多子类的情况下扩展类

优缺点

优点:

  1. 不改变具体类代码,动态叠加增强行为功能
  2. 若要扩展功能,装饰者提供了比继承更有弹性的替代方案
  3. 装饰类和被装饰类可以独立发展,不会相互耦合

缺点:

  1. 多层装饰比较复杂

类图:



涉及到的角色:

  1. 抽象构建(Component)角色:给出一个抽象接口,来规范准备接收附加责任的对象
  2. 具体构建(ConcreteComponent)角色:定义一个将要接收附加责任的类,即被装饰者
  3. 装饰(Decorator)角色:持有一个构建(Component)对象的实例,并定义一个与抽象接口一致的接口
  4. 具体装饰(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设计模式:装饰者模式的更多相关文章

  1. JAVA设计模式--装饰器模式

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

  2. 从源码角度理解Java设计模式——装饰者模式

    一.饰器者模式介绍 装饰者模式定义:在不改变原有对象的基础上附加功能,相比生成子类更灵活. 适用场景:动态的给一个对象添加或者撤销功能. 优点:可以不改变原有对象的情况下动态扩展功能,可以使扩展的多个 ...

  3. 【设计模式】Java设计模式 - 装饰者模式

    Java设计模式 - 装饰者模式 不断学习才是王道 继续踏上学习之路,学之分享笔记 总有一天我也能像各位大佬一样 原创作品,更多关注我CSDN: 一个有梦有戏的人 准备将博客园.CSDN一起记录分享自 ...

  4. Java设计模式——装饰者模式

    JAVA 设计模式 装饰者模式 用途 装饰者模式 (Decorator) 动态地给一个对象添加一些额外的职责.就增加功能来说,Decorator 模式相比生成子类更为灵活. 装饰者模式是一种结构式模式 ...

  5. JAVA 设计模式 装饰者模式

    用途 装饰者模式 (Decorator) 动态地给一个对象添加一些额外的职责.就增加功能来说,Decorator 模式相比生成子类更为灵活. 装饰者模式是一种结构式模式. 结构

  6. Java 设计模式—装饰者模式

    在Java编程语言中,嵌套了非常多设计模式的思想,比如IO流中的缓冲流就使用到以下要介绍的装饰者设计模式. 演示样例代码: * 抽象构件角色:定义一个抽象接口,来规范准备附加功能的类 * @autho ...

  7. Java设计模式--装饰器模式到Java IO 流

    装饰器模式 抽象构件角色:给出一个抽象接口,以规范准备接受附加责任的对象. 具体构件角色:定义准备接受附加责任的对象. 抽象装饰角色:持有一个构件对象的实例,并对应一个与抽象构件接口一致的接口. 具体 ...

  8. Java设计模式の装饰者模式

    目录 一.问题引入 二.设计原则 三.用装饰者模式解决问题 四.装饰者模式的特点 五.装饰者模式的定义 六.装饰者模式的实现 七.java.io包内的装饰者模式 一.问题引入 咖啡店的类设计: 一个饮 ...

  9. JAVA设计模式---装饰者模式

    写在前面的话: 该模式动态的将责任附加到对象上,若要扩展功能,装饰者提供了比继承更有弹性的替代方案.装饰者可以在被装饰者的行为前面与/或后面加上自己的行为,甚至将被装饰者的行为整个取代掉,而达到特定的 ...

随机推荐

  1. E百科 | 基于MEC的边缘AI服务

    简介: 阿里云边缘计算团队付哲解读5G下热门场景:边缘AI.作者:阿里云付哲,计算机科学与技术专业博士后,在流量检测.资源调度领域有深入研究,其论文<Astraea: Deploy AI Ser ...

  2. SpringBoot常见的异常问题

    1. org.mybatis.logging.LoggerFactory Springboot启动报错 Caused by: java.lang.ClassNotFoundException: org ...

  3. Java常用类:Arrays类

    一.简介 全类名:java.util.Arrays 描述: 此类包含用来操作数组(比如排序和搜索)的各种方法. 此类还包含一个允许将数组作为列表来查看的静态工厂. 注意: 除非特别注明,否则如果指定数 ...

  4. 阿里云CentOS8.0服务器配置Django3.0+Python 3.7 环境

    ---恢复内容开始--- 1. 下载并安装python # 安装Python3.7.6 wget https://www.python.org/ftp/python/3.7.6/Python-3.7. ...

  5. 《Asp.Net Core3 + Vue3入坑教程》 - Vue 1.使用vue-cli创建vue项目

    简介 <Asp.Net Core3 + Vue3入坑教程> 此教程适合新手入门或者前后端分离尝试者.可以根据图文一步一步进操作编码也可以选择直接查看源码.每一篇文章都有对应的源码 目录 & ...

  6. Linux 文件和目录管理

    绝对路径:路径的写法一定由根目录/写起的,例如 /usr/local/mysql 相对路径:和绝对路径相反 不是由根目录/写起的,例如用户首先进入到/home,然后进入test 执行命令:cd /ho ...

  7. AmazonS3 使用AWS SDK for Java实现跨源资源共享 (CORS)

    CORS 配置 创建 CORS 配置并对存储桶设置该配置 通过添加规则来检索并修改配置 向存储桶添加修改过的配置 删除配置 import com.amazonaws.AmazonServiceExce ...

  8. POJ_2533 Longest Ordered Subsequence 【LIS】

    一.题目 Longest Ordered Subsequence 二.分析 动态规划里的经典问题.重在DP思维. 如果用最原始的DP思想做,状态转移方程为$DP[i] = max(DP[j] + 1) ...

  9. java IO流文件拷贝文件(字节流标准写法)

    public static void copyFile(String srcPath, String destPath) { FileInputStream fis = null; FileOutpu ...

  10. 电影AI修复,让重温经典有了新的可能

    摘要:有没有一种呈现,不以追求商业为第一目的,不用花大价钱,不用翻拍,没有画蛇添足,低成本的可共赏的让经典更清晰? 本文分享自华为云社区<除了重映和翻拍,重温经典的第三种可能>,原文作者: ...