一、模式介绍
1.1、定义
在不改变现有对象结构的情况下,动态地将责任附加到对象上,若要扩展功能,装饰者提供了比继承更有弹性的替代方案。它是对象结构型模式。
1.2、优点
- 装饰者是继承的有力补充,比继承灵活,在不改变原有对象的情况下,动态的给一个对象扩展功能,即插即用
- 通过使用不用装饰类及这些装饰类的排列组合,可以实现不同效果
- 装饰者模式完全遵守开闭原则
1.3、缺点
装饰者模式会增加许多子类,过度使用会增加程序的复杂度
二、结构与实现
2.1、结构
- 装饰模式主要包含以下角色。
- 抽象组件(Compzonent)角色:定义一个抽象接口以规范准备接收附加责任的对象。
- 具体组件(ConcreteComponent)角色:实现抽象组件,可以动态地对具体组件加上新的行为。
- 抽象装饰(Decorator)角色:实现抽象组件,并包含具体构件的实例,可以通过其子类扩展具体构件的功能。这是装饰者共同实现的接口(也可以是抽象类)
- 具体装饰(ConcreteDecorator)角色:实现抽象装饰的相关方法,并给具体构件对象添加附加的责任。
2.2、实现
设计一个咖啡订单系统,购买咖啡时,可以要求在其中加入各种调料,比如:摩卡(Mocha)、牛奶(Milk)。咖啡店会根据加入的调料不同收取不同的费用,所以订单系统必须考虑这些调料部分。类图如下:
2.2.1、Beverage
package com.erlang.decorator;
/**
* @description: 抽象装饰者:饮料
* @author: erlang
* @since: 2022-02-13 22:39
*/
public abstract class Beverage {
protected String description = "Unknown Beverage";
public String getDescription() {
return description;
}
public abstract double cost();
}
2.2.2、HouseBlend
package com.erlang.decorator;
/**
* @description: 综合咖啡
* @author: erlang
* @since: 2022-02-13 22:39
*/
public class HouseBlend extends Beverage {
public HouseBlend() {
description = "House Blend Coffee";
}
@Override
public double cost() {
return .89;
}
}
2.2.3、DarkRoast
package com.erlang.decorator;
/**
* @description: 深焙咖啡
* @author: erlang
* @since: 2022-02-13 22:40
*/
public class DarkRoast extends Beverage {
public DarkRoast() {
description = "DarkRoast coffee";
}
@Override
public double cost() {
return 0.99;
}
}
2.2.4、CondimentDecorator
package com.erlang.decorator;
/**
* @description: 具体装饰者:调料
* @author: erlang
* @since: 2022-02-13 22:39
*/
public abstract class CondimentDecorator extends Beverage {
/**
* 描述信息
*
* @return 描述信息
*/
@Override
public abstract String getDescription();
}
2.2.5、Milk
package com.erlang.decorator;
/**
* @description: 牛奶
* @author: erlang
* @since: 2022-02-13 22:45
*/
public class Milk extends CondimentDecorator {
private Beverage beverage;
public Milk(Beverage beverage) {
this.beverage = beverage;
}
@Override
public String getDescription() {
return beverage.getDescription() + ", Milk";
}
@Override
public double cost() {
return 0.99 + beverage.cost();
}
}
2.2.6、Mocha
package com.erlang.decorator;
/**
* @description: 摩卡
* @author: erlang
* @since: 2022-02-13 22:45
*/
public class Mocha extends CondimentDecorator {
private Beverage beverage;
public Mocha(Beverage beverage) {
this.beverage = beverage;
}
@Override
public String getDescription() {
return beverage.getDescription() + ", Mocha";
}
@Override
public double cost() {
return 0.20 + beverage.cost();
}
}
2.2.7、StarBuzzCoffee
package com.erlang.decorator;
/**
* @description: 咖啡店
* @author: erlang
* @since: 2022-02-13 22:48
*/
public class StarBuzzCoffee {
public static void main(String[] args) {
test1();
test2();
test3();
}
public static void test1() {
Beverage houseBlend = new HouseBlend();
System.out.println(houseBlend.getDescription() + " $" + houseBlend.cost());
System.out.println("------------------------------------------");
}
public static void test2() {
DarkRoast darkRoast = new DarkRoast();
Mocha mocha = new Mocha(darkRoast);
System.out.println(mocha.getDescription() + " $" + mocha.cost());
System.out.println("------------------------------------------");
}
public static void test3() {
HouseBlend houseBlend = new HouseBlend();
Milk milk = new Milk(houseBlend);
Mocha mocha = new Mocha(milk);
System.out.println(mocha.getDescription() + " $" + mocha.cost());
System.out.println("------------------------------------------");
}
}
2.2.8、运行结果
House Blend Coffee $0.89
------------------------------------------
DarkRoast coffee, Mocha $1.19
------------------------------------------
House Blend Coffee, Milk, Mocha $2.08
------------------------------------------