通常可以使用继承来实现功能的扩展,如果这些需要扩展的功能的种类很繁多,那么势必生成很多子类,增加系统的复杂性,同时使用继承实现功能拓展,我们必须可预见这些拓展功能,这些功能是编译时就确定了,是静态的。
装饰模式(Decorator),指在不改变现有对象结构的情况下,动态地给该对象增加一些职责(即增加其额外功能)的模式。装饰者与被装饰者拥有共同的父类,继承的目的是继承类型,而不是行为。
装饰者模式的原理:装饰者类内部含有被装饰者(组合),且被装饰者与装饰者都继承自共同的父类。这样可以将被装饰者的子类实例对象传入装饰者子类的实例对象中,拓展被装饰者继承类即可实现动态的将新功能附加到装饰者子类实例对象上。在对象功能扩展方面,它比继承更有弹性,装饰者模式也体现了开闭原则(OCP)。
实现案例参考自此博客——[装饰者模式](设计模式 —— 装饰者模式_不埋雷的探长的博客-CSDN博客_装饰者模式)

AbstractDrink 源码示例:
public abstract class AbstractDrink {
public String des; // 描述
private float price = 0.0f;
public String getDes() {
return des;
}
public void setDes(String des) {
this.des = des;
}
public float getPrice() {
return price;
}
public void setPrice(float price) {
this.price = price;
}
// 计算费用的抽象方法
// 子类来实现
public abstract float cost();
}
Coffee 源码示例:
public class Coffee extends AbstractDrink {
@Override
public float cost() {
return super.getPrice();
}
}
Espresso 源码示例:
public final class Espresso extends Coffee {
public Espresso() {
setDes(" 意大利咖啡 ");
setPrice(6.0f);
}
}
LongBlack 源码示例:
public final class LongBlack extends Coffee {
public LongBlack() {
setDes(" longBlack ");
setPrice(5.0f);
}
}
ShortBlack 源码示例:
public final class ShortBlack extends Coffee {
public ShortBlack() {
setDes(" shortBlack ");
setPrice(4.0f);
}
}
Decaf 源码示例:
public class Decaf extends Coffee {
public Decaf() {
setDes(" 无因咖啡 ");
setPrice(1.0f);
}
}
Decorator 源码示例:
public class Decorator extends AbstractDrink {
private AbstractDrink drink;
public Decorator(AbstractDrink drink) { // 组合
this.drink = drink;
}
@Override
public float cost() {
// getPrice 自己价格
return super.getPrice() + drink.cost();
}
@Override
public String getDes() {
// drink.getDes() 输出被装饰者的信息
return super.des + " " + getPrice() + " && " + drink.getDes();
}
}
Chocolate 源码示例:
// 具体的Decorator, 这里就是调味品
public class Chocolate extends Decorator {
public Chocolate(AbstractDrink drink) {
super(drink);
setDes(" 巧克力 ");
setPrice(3.0f); // 调味品的价格
}
}
Milk 源码示例:
public class Milk extends Decorator {
public Milk(AbstractDrink drink) {
super(drink);
setDes(" 牛奶 ");
setPrice(2.0f);
}
}
Soy 源码示例:
public class Soy extends Decorator {
public Soy(AbstractDrink drink) {
super(drink);
setDes(" 豆浆 ");
setPrice(1.5f);
}
}
CoffeeBar 源码示例:
public class CoffeeBar {
public static void main(String[] args) {
// 装饰者模式下的订单:2份巧克力 + 一份牛奶的LongBlack
// 1. 点一份 LongBlack
AbstractDrink order = new LongBlack();
System.out.println("费用1=" + order.getPrice());
System.out.println("描述=" + order.getDes());
// 2. order 加入一份牛奶
order = new Milk(order);
System.out.println("order 加入一份牛奶 费用 = " + order.cost());
System.out.println("order 加入一份牛奶 描述 = " + order.getDes());
// 3. order 加入一份巧克力
order = new Chocolate(order);
System.out.println("order 加入一份巧克力 费用 = " + order.cost());
System.out.println("order 加入一份巧克力 描述 = " + order.getDes());
// 4. order 加入2份巧克力
order = new Chocolate(order);
System.out.println("order 加入2份巧克力 费用 = " + order.cost());
System.out.println("order 加入2份巧克力 描述 = " + order.getDes());
System.out.println("======================================");
AbstractDrink order2 = new Decaf();
System.out.println("order2 无因咖啡 费用 = " + order2.cost());
System.out.println("order2 无因咖啡 描述 = " + order2.getDes());
order2 = new Milk(order2);
System.out.println("order2 无因咖啡 加入一份牛奶 费用 = " + order2.cost());
System.out.println("order2 无因咖啡 加入一份牛奶 描述 = " + order2.getDes());
}
}
当不能采用继承的方式对系统进行扩充或者采用继承不利于系统扩展和维护时。
不能采用继承的情况主要有两类:
在不影响其他对象的情况下,以动态、透明的方式给单个对象添加职责。
当对象的功能要求可以动态地添加,也可以再动态地撤销时。
IO流中的包装类使用到了装饰者模式。BufferedInputStream,BufferedOutputStream,BufferedReader,BufferedWriter。