一、结构型模式
1.1、装饰者模式
1.1.1、概念
装饰者模式就是指在不改变现有对象结构的情况下,动态的给该对象增加一些职责(增加额外功能)的模式.
例如,现在要开发一个点餐系统,有一个抽象类快餐类,快餐店里有炒面、炒饭,分别去继承实现. 如果现在需要添加额外的配料(比如 鸡蛋),那么计算额外加钱就会不叫麻烦,就需要分别给 炒面类 和 炒饭类 定义一个子类(鸡蛋炒面类、鸡蛋炒饭类). 再者,如果要新增一个快餐类(比如 凉皮),就需要定义更多的子类. 通过装饰者模式就可以在不需要添加子类的情况下,动态的添加配料.
装饰者模式中的角色如下:
- 抽象构件角色:定义一个抽象接口用来规范附加的对象(比如上述的 快餐类).
- 具体构件角色:实现抽象构件,将来会被添加一些职责(比如上述的 炒面类 和 炒饭类).
- 抽象装饰角色:继承抽象构件 和 持有抽象构件的引用,可以通过 子类 扩展具体的构件.
- 具体装饰角色:继承抽象装饰,重写相关方法,给具体的构件对象添加附加责任.
1.1.2、案例实现
实现上述案例.
/**
* 抽象构建角色: 快餐
*/
public abstract class FastFood {
private float price; //价格
private String desc; //描述
public abstract float cost(); //获取最终价格
public FastFood() {
}
public FastFood(float price, String desc) {
this.price = price;
this.desc = desc;
}
public float getPrice() {
return price;
}
public void setPrice(float price) {
this.price = price;
}
public String getDesc() {
return desc;
}
public void setDesc(String desc) {
this.desc = desc;
}
}
/**
* 具体构建角色: 炒饭类
*/
public class Rice extends FastFood{
public Rice() {
super(10, "炒饭");
}
@Override
public float cost() {
return getPrice();
}
}
/**
* 具体构建角色: 面条类
*/
public class Noodles extends FastFood {
public Noodles() {
super(12, "炒面");
}
@Override
public float cost() {
return getPrice();
}
}
/**
* 抽象装饰角色: 配料类
*/
public abstract class Garnish extends FastFood {
private FastFood fastFood;
public FastFood getFastFood() {
return fastFood;
}
public void setFastFood(FastFood fastFood) {
this.fastFood = fastFood;
}
public Garnish(FastFood fastFood, float price, String desc) {
super(price, desc);
this.fastFood = fastFood;
}
}
/**
* 抽象装饰角色: 配料类
*/
public abstract class Garnish extends FastFood {
private FastFood fastFood;
public FastFood getFastFood() {
return fastFood;
}
public void setFastFood(FastFood fastFood) {
this.fastFood = fastFood;
}
public Garnish(FastFood fastFood, float price, String desc) {
super(price, desc);
this.fastFood = fastFood;
}
}
/**
* 具体装饰角色: 鸡蛋配料
*/
public class Egg extends Garnish{
public Egg(FastFood fastFood) {
super(fastFood, 1, "鸡蛋");
}
@Override
public float cost() {
return getPrice() + getFastFood().cost();
}
@Override
public String getDesc() {
return super.getDesc() + getFastFood().getDesc();
}
}
/**
* 具体装饰角色: 培根配料
*/
public class Bacon extends Garnish{
public Bacon(FastFood fastFood) {
super(fastFood, 2, "培根");
}
@Override
public float cost() {
return getPrice() + getFastFood().cost();
}
@Override
public String getDesc() {
return super.getDesc() + getFastFood().getDesc();
}
}
public class Client {
public static void main(String[] args) {
//1.带你一份炒饭
FastFood food = new Rice();
System.out.println(food.getDesc() + " " + food.cost() + "元");
System.out.println("================");
//2.加一份鸡蛋
food = new Egg(food);
System.out.println(food.getDesc() + " " + food.cost() + "元");
System.out.println("================");
//3.加一份鸡蛋
food = new Egg(food);
System.out.println(food.getDesc() + " " + food.cost() + "元");
System.out.println("================");
//4.加一个培根
food = new Bacon(food);
System.out.println(food.getDesc() + " " + food.cost() + "元");
}
}
执行结果如下:
1.1.3、优缺点
优点:
动态扩展:比继承具有更好的扩展性(继承时静态附加责任,装饰者时动态添加责任),可以在不修改原类的情况下,给对象添加责任.
缺点:
增加系统复杂度:装饰者比继承使用的类可能会少,但比继承使用的对象可能更多,更多的对象在程序排查错误的时候可能更复杂.
1.1.4、使用场景
1. 当不能采用继承的方式对程序进行扩展,比如存在大量的独立扩展,为了支持每一种组合产生大量子类(例如上述栗子中的给 炒饭加鸡蛋,导致出现 鸡蛋炒饭类),导致子类数目爆炸增长、或者是 类定位为 final 类型(不能继承).
2. 在不影响其他类的情况下,以动态的方式添加责任.