装饰者定义
Java 中的装饰者模式(Decorator Pattern)是一种结构型设计模式,它允许你通过将对象封装在装饰者类中来动态地扩展其行为。这种模式允许向现有对象添加新功能,同时又不改变其结构。
结构
基础组件接口(Component)
所有具体组件和装饰者都实现或继承这个接口。它规定了组件对象的基本行为。
具体组件类(ConcreteComponent)
实现基础组件接口的具体类,是装饰者模式中被装饰的对象。它定义了基础行为。
装饰者抽象类(Decorator)
实现了基础组件接口,并且持有一个指向基础组件对象的引用。它的存在是为了动态地为基础组件添加新的功能。
具体装饰者类(ConcreteDecorator)
继承自装饰者抽象类,实现了具体的功能扩展。可以根据需要添加额外的功能,而不影响其他组件或装饰者的行为。
方法栈的应用
调用链的顺序:装饰者模式中,装饰者和基础组件的方法调用顺序是非常关键的。通常,在 ConcreteDecorator 的方法中,会先调用父类的方法,然后再执行额外的操作。这种顺序保证了装饰者模式的特性,即可以动态地添加功能,而不影响其他对象的行为。
递归调用:由于装饰者模式允许嵌套使用装饰者,因此方法的调用可能会形成递归,类似于方法栈的结构。每个装饰者都调用其包装对象的方法,这样在运行时就能实现一系列的装饰效果。
案例
类图
代码
//快餐接口
public abstract class FastFood {
private float price;
private String desc;
public FastFood() {
}
public FastFood(float price, String desc) {
this.price = price;
this.desc = desc;
}
public void setPrice(float price) {
this.price = price;
}
public float getPrice() {
return price;
}
public String getDesc() {
return desc;
}
public void setDesc(String desc) {
this.desc = desc;
}
public abstract float cost(); //获取价格
}
//炒饭
public class FriedRice extends FastFood {
public FriedRice() {
super(10, "炒饭");
}
public float cost() {
return getPrice();
}
}
//炒面
public class FriedNoodles extends FastFood {
public FriedNoodles() {
super(12, "炒面");
}
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 class Egg extends Garnish {
public Egg(FastFood fastFood) {
super(fastFood,1,"鸡蛋");
}
public float cost() {
return getPrice() + getFastFood().getPrice();
}
@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().getPrice();
}
@Override
public String getDesc() {
return super.getDesc() + getFastFood().getDesc();
}
}
//测试类
public class Client {
public static void main(String[] args) {
//点一份炒饭
FastFood food = new FriedRice();
//再加鸡蛋和培根
food = new Bacon(new Egg(food));
System.out.println(food.getDesc() + " " + food.cost() + "元");
}
}
好处
饰者模式可以带来比继承更加灵活性的扩展功能,使用更加方便,可以通过组合不同的装饰者对象来获取具有不同行为状态的多样化的结果。装饰者模式比继承更具良好的扩展性,完美的遵循开闭
原则,继承是静态的附加责任,装饰者则是动态的附加责任。装饰类和被装饰类可以独立发展,不会相互耦合,装饰模式是继承的一个替代模式,装饰模式可以动态扩展一个实现类的功能。
使用场景
当不能采用继承的方式对系统进行扩充或者采用继承不利于系统扩展和维护时。不能采用继承的情况主要有两类:
第一类是系统中存在大量独立的扩展,为支持每一种组合将产生大量的子类,使得子类数目呈爆炸性增长;
第二类是因为类定义不能继承(如final类)在不影响其他对象的情况下,以动态、透明的方式给单个对象添加职责。当对象的功能要求可以动态地添加,也可以再动态地撤销时。
代理和装饰者的区别
静态代理和装饰者模式的区别:
相同点:
都要实现与目标类相同的业务接口
在两个类中都要声明目标对象
都可以在不修改目标类的前提下增强目标方法
不同点:
目的不同 装饰者是为了增强目标对象 静态代理是为了保护和隐藏目标对象
获取目标对象构建的地方不同 装饰者是由外界传递进来,可以通过构造方法传递 静态代理
是在代理类内部创建,以此来隐藏目标对象