应用场景

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

  • 满减:满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. 1090 Highest Price in Supply Chain——PAT甲级真题

    1090 Highest Price in Supply Chain A supply chain is a network of retailers(零售商), distributors(经销商), ...

  2. eclipse输入时自动提示

    当输入一部分代码时,其他的候选代码提示出来,可以提高开发的效率,设置方法如下: 选择Window -> Perferences -> Java -> Editor -> Con ...

  3. 第一篇文章 vim的使用

    这么长时间以来,一直没有在博客园上写过博文.那第一篇博文就以vim的使用为开端吧. 不知道有多少人还在用着ctrl+c,ctrl+v这种方式,不过,就我个人而言,还是很倾向于vim的.不管是在服务器上 ...

  4. SpringBoot(五):SpringBoot使用拦截器

    1.按照SpringMVC的方式编写一个拦截器: 2.配置一个类   implements WebMvcConfigurer 接口 为该类添加注解@Configuration  (等价于一个sprin ...

  5. 学习java的第二天

    Java第二天 标识符 标识符开头只能以字母和_开头 严格区分大小写 不能以关键词命名 变量 变量是什么:就是可以变化的量 Java是一种强类型语言,定义变量必须声明后才能使用 Java变量是程序中最 ...

  6. 【DB宝42】MySQL高可用架构MHA+ProxySQL实现读写分离和负载均衡

    目录 一.MHA+ProxySQL架构 二.快速搭建MHA环境 2.1 下载MHA镜像 2.2 编辑yml文件,创建MHA相关容器 2.3 安装docker-compose软件(若已安装,可忽略) 2 ...

  7. CVE-2018-2628-WLS Core Components 反序列化

    漏洞参考 https://blog.csdn.net/csacs/article/details/87122472 漏洞概述:在 WebLogic 里,攻击者利用其他rmi绕过weblogic黑名单限 ...

  8. Shiro 反序列化漏洞利用

    环境搭建 docker pull medicean/vulapps:s_shiro_1 docker run -d -p 80:8080 medicean/vulapps:s_shiro_1 # 80 ...

  9. SQL-MYSQL的时间格式转换(持续补充)

    ======================SQLSERVER===================================== SELECT CONVERT(varchar(100), GE ...

  10. FreeBSD 将降低对 i386 架构的支持力度

    FreeBSD 开发团队宣布,从 FreeBSD 13.0 开始,对 i386 架构的支持级别将降级为 Tier 2,未来的 14.0 可能还将会在此基础上进一步降低对 i386 架构的支持.而对于 ...