1.装饰者模式概述
指在不改变对象结构的情况下,动态的给对象增加一些额外的职责(即附加一些额外的功能)。
意图:动态地给一个对象添加一些额外的职责。就增加功能来说,装饰器模式相比生成子类更为灵活。
使用场景: 1、扩展一个类的功能。 2、动态增加功能,动态撤销。
主要解决:一般的,我们为了扩展一个类经常使用继承方式实现,由于继承为类引入静态特征,并且随着扩展功能的增多,子类会很膨胀。
装饰者模式中有以下的几个角色:
- 抽象构件:定义一个接口接收附加责任的对象
- 具体构建:实现了抽象构建,通过装饰角色为其添加职责
- 抽象装饰:继承或实现抽象构建,并持有一个具体构件的实例,可以通过其子类扩展具体的功能。
- 具体装饰:实现抽象装饰的方法,并给具体构建对象添加额外的职责。
现在引入这样一个场景,快餐店往往有炒粉,炒饭,炒面等多种选择,往往还需要往这些东西当中加鸡蛋,香肠之类的。结合装饰者模式应有的角色,我们画出如下的UML类图:
- FastFood:对应抽象构件类。
- FriedRice和FriedNoodles:对应具体构件类
- FoodDeractor:对应抽象装饰
- Egg和Backon对应具体的装饰类。
public abstract class FastFood {
protected float price;
protected String desc;
public FastFood(float price,String desc){
this.price=price;
this.desc=desc;
}
public FastFood(){
}
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 abstract float getCost();
}
public class FriedNoodles extends FastFood{
public FriedNoodles(float price,String desc){
super(12,"炒面");
}
@Override
public float getCost() {
return getPrice();
}
}
public class FriedRice extends FastFood{
public FriedRice(){
super(10,"炒饭");
}
@Override
public float getCost() {
return getPrice();
}
}
public abstract class FoodDeractor extends FastFood{
protected FastFood fastFood;
public FoodDeractor(float price,String desc,FastFood fastFood){
super(price,desc);
this.fastFood=fastFood;
}
}
public class Egg extends FoodDeractor{
public Egg(FastFood fastFood){
super(1,"鸡蛋",fastFood);
}
@Override
public float getCost() {
return getPrice()+fastFood.getPrice();
}
@Override
public String getDesc(){
return super.getDesc()+fastFood.getDesc();
}
}
public class Client {
public static void main(String[] args) {
FastFood rice=new FriedRice();
System.out.println(rice.getDesc()+rice.getCost());
rice=new Egg(rice);
System.out.println(rice.getDesc());
System.out.println(rice.getCost());
//炒饭10.0
//鸡蛋炒饭
//11.0
实际上抽象修饰类继承抽象构建的目的不是继承其行为,而是需要其类型,持有抽象构件类的对象是为了在其方法的基础上增加或添加它的功能。
试想如果我们如果不这样做的话,我们必须创建一个FriedRiceEgg类,而且不能保证一定会用到。当添加新的菜品时,配菜和主菜方面需要双向扩展,会产生类爆炸。