应用场景

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

  • 满减:满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. Java基本概念:异常

    一.简介 描述: 异常(Exception)指不期而至的各种状况,异常发生的原因有很多,通常包含以下几大类: 用户输入了非法数据. 要打开的文件不存在. 网络通信时连接中断,或者JVM内存溢出. 异常 ...

  2. Ability之间或者进程间数据传递之对象(Sequenceable序列化)

    鸿蒙入门指南,小白速来!0基础学习路线分享,高效学习方法,重点答疑解惑--->[课程入口] 这两天51cto上的一个粉丝朋友问了我一个问题,Ability之间使用Sequenceable序列化传 ...

  3. 后端程序员之路 44、Redis结合protobuf

    protobuf序列化速度不错,在往Redis里存对象时,用protobuf序列化可以节省内存,省去写序列化反序列化代码的工作. google protocol buffer 与 redis 结合使用 ...

  4. Java 集合框架 04

    集合框架·Map 和 Collections集合工具类 Map集合的概述和特点 * A:Map接口概述 * 查看API可知: * 将键映射到值的对象 * 一个映射不能包含重复的键 * 每个键最多只能映 ...

  5. Java 多线程 02

    多线程·线程间通信 和 GUI 单例设计模式 * A:单例设计模式 * 保证类在内存中只有一个对象 * B:如何保证 * a:控制类的创建,不让其他类来创建泵类的对象,私有化构造方法 * b:在本类中 ...

  6. Asp.Net Core WebAPI中启用XML格式数据支持

    因为XML是一种非常常用的数据格式,所以Asp.Net core提供了非常便利的方式来添加对XML格式的支持 只需要在IOC注册Controller服务的后面跟上.AddXmlDataContract ...

  7. CentOS 8.3安装MySQL 8.0.21后无法登录管理数据库

    安装mysql后登录不了,提示: ERROR 1045 (28000): Access denied for user 'root'@'localhost' (using password: YES) ...

  8. VScode 自定义用户代码块

    1定义html中的vue 见地址 https://blog.csdn.net/qq_40191093/article/details/82915028 2  https://www.cnblogs.c ...

  9. Nodejs学习笔记(2) 阻塞/非阻塞实例 与 Nodejs事件

    1. Node.js异步编程的特点 2. 阻塞与非阻塞的实例 2.1 阻塞代码实例 2.2 非阻塞代码实例 3. Node.js的事件驱动 4. 事件循环实例 1. Node.js异步编程的特点 参考 ...

  10. css实现一个电影卡片

    1 <!DOCTYPE html> 2 <html lang="en"> 3 <head> 4 <meta charset="U ...