应用场景

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

  • 满减:满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. 音视频+ffmpeg

    雷霄骅:https://me.csdn.net/leixiaohua1020 致敬! 1.[总结]视音频编解码技术零基础学习方法 https://blog.csdn.net/leixiaohua102 ...

  2. 翻译:《实用的Python编程》03_01_Script

    目录 | 上一节 (2.7 对象模型) | 下一节 (3.2 深入函数) 3.1 脚本 在该部分,我们将深入研究编写 Python 脚本的惯例. 什么是脚本? 脚本就是运行和终止一系列语句的程序. # ...

  3. Centos7安装Docker&镜像加速

    目录 Docker Docker安装 方式一 方式二 docker 镜像加速 Docker Docker安装 Docker安装 方式一 step1: 删除老版本(Uninstall old versi ...

  4. 使用 Java 开发 Gradle 插件

    Gradle 插件代码可以在 build.gradle 中,buildSrc 项目中,以及独立的插件项目中编写.本文将介绍如何在一个独立的项目中使用 Java 语言编写 Gradle 插件,并发布到仓 ...

  5. 解决springboot项目打成jar包部署到linux服务器后上传图片无法访问的问题

    前言:目前大三,自己也在学习和摸索的阶段.在和学校的同学一起做前后端分离项目的时候,我们发现将后端打包成jar,然后部署到服务器中通过java -jar xxx.jar运行项目以后,项目中存在文件上传 ...

  6. 模式识别Pattern Recognition

    双目摄像头,单目摄像头缺少深度 Train->test->train->test->predicive

  7. Python3.x 基础练习题100例(81-90)

    练习81: 题目: 809??=800??+9?? 其中??代表的两位数, 809??为四位数,8??的结果为两位数,9??的结果为3位数.求??代表的两位数,及809*??后的结果. 程序: a = ...

  8. Chrome OS超便捷安装指南

    Chrome OS是一款Google开发的基于PC的操作系统. Google Chrome OS是一款基于Linux的开源操作系统.Google在自己的官方博客表示,初期,这一操作系统将定位于上网本. ...

  9. python 操作符** (两个乘号就是乘方)

    一个乘号*,如果操作数是两个数字,就是这两个数字相乘,如2*4,结果为8**两个乘号就是乘方.比如3**4,结果就是3的4次方,结果是81 *如果是字符串.列表.元组与一个整数N相乘,返回一个其所有元 ...

  10. 选择 FreeBSD 而不是 Linux 的技术性原因2

    ZFSZFS 文件系统是 FreeBSD 上的一等公民.这不仅意味着可以在 ZFS 上安装根目录,安装程序也支持这一点,而且还意味着很多基础系统工具都已经紧密地集成或构建了对 ZFS 的支持.在 Fr ...