装饰者模式
装饰者模式(Decorator Pattern)能够在不修改目标类也不使用继承的情况下,动态地扩展一个类的功能。它是通过创建一个包装对象,也就是装饰者来达到增强目标类的目的的。
装饰者设计模式的实现有两个要求:
1、装饰者类与目标类要实现相同的接口,或继承自相同的抽象类。
2、装饰者类中要有目标类的引用作为成员变量,而具体的赋值一般通过带参构造器完成
装饰者模式包括以下主要角色
- 抽象构件角色:定义一个抽象接口以规范准备接收附加责任的对象
- 具体构件角色:实现抽象构件,通过装饰者角色为其添加一些职责
- 抽象装饰角色:继承或实现抽象构件,并包含具体构件的实例,可以通过其子类扩展具体构件的功能
- 具体装饰角色:实现抽象装饰的相关方法,并给具体构件对象添加附加职责
【案例】
快餐店炒面、炒饭这些快餐,并且可以附加鸡蛋、火腿、培根这些配菜,当然这些配菜需要额外的加强。每个配菜的价格都不一样,那么计算总价会显得比较麻烦
public class DecoratorTest {
public static void main(String[] args) {
FastFood food = new FiredRice();
System.out.println(food.getDesc()+"的价格是"+food.cost()+"元");
System.out.println("========炒饭加鸡蛋========");
food = new Egg(food);
System.out.println(food.getDesc()+"的价格是"+food.cost()+"元");
System.out.println("========炒饭加鸡蛋再加培根========");
food = new Bacon(food);
System.out.println(food.getDesc()+"的价格是"+food.cost()+"元");
}
}
abstract class FastFood{ //抽象构件角色
private float price; //价格
private String desc; //描述
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 abstract float cost();
}
class FiredRice extends FastFood{ //具体构件角色
public FiredRice() {super(10,"炒饭");}
public float cost() {return getPrice();}
}
class FiredNoodles extends FastFood{ //具体构件角色
public FiredNoodles() {super(8,"炒面");}
public float cost() {return getPrice();}
}
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;
}
}
class Egg extends Garnish{ //具体装饰角色
public Egg(FastFood fastFood) {super(fastFood,1,"鸡蛋");}
public float cost() {return getPrice() + getFastFood().cost();}//鸡蛋价格加快餐价格
public String getDesc(){return super.getDesc()+getFastFood().getDesc();}
}
class Bacon extends Garnish{ //具体装饰角色
public Bacon(FastFood fastFood) {super(fastFood,2,"培根");}
public float cost() {return getPrice() + getFastFood().cost();}
public String getDesc(){return super.getDesc()+getFastFood().getDesc();}
}
装饰者模式的优缺点
- 优点
1、 装饰者模式可以带来比继承更加灵活的扩展功能,可以通过组合不同的装饰者对象来获取具有不同行为状态多样化的结果
2、 继承是静态的附加责任,装饰者模式是动态的附加责任
3、 装饰者和被装饰者类可以独立发展,不会相互耦合,比如说我们想再加一个炒河粉只需创建一个炒河粉类继承FastFood即可,而想要增加火腿肠配料就增加一个类去继承Garnish抽象装饰者 - 缺点
多层装饰比较复杂
适用场景
1、当不能采用继承的方式对系统进行扩充或采用继承的方式不利于系统扩展和维护时1、继承导致类爆炸2、final修饰的类
2、在不影响其他对象的情况下以动态、透明的方式给单个对象添加职责
3、当对象的功能要求可以动态地添加,也可以动态的撤销时
装饰者模式和静态代理的区别
- 相同点:
都要实现于目标类相同的接口
在两个类中都要声明目标对象
都可以在不修改目标类的前提下增强方法 - 不同点:
1、装饰者设计模式就是为了增强目标类;静态代理设计模式是为了保护和隐藏目标对象
2、获取目标对象的构建不同,装饰者模式是由外界传递进来的,可以通过构造方法传递,静态代理是在代理类内部创建的,以此来隐藏目标对象
3、 装饰者基类一般不对目标对象进行增强,而是由不同的具体装饰者进行增强的,且这些具体的装饰者可以形成增强链,对目标对象进行连续增强。静态代理类会直接对目标对象进行增强,需要哪些增强的功能,一次性在静态代理类中完成,没有增强链的概念。