由孙悟空的七十二变看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());
}
}
类图: