装饰器模式(Decorator Pattern)
定义:装饰器模式也叫包装模式,是指在不改变原有对象的基础之上,将功能附加到对象上,提供了比继承更有弹性的替代方案。
属于结构型模式。
适用场景
- 用于扩展一个类的功能或给一个类添加附加职责
- 动态的给一个对象添加功能,这些功能可以在动态的撤销
通用写法
public abstract class Component {
/**
* 示例方法
*/
public abstract void operation();
}
public class ConcreteComponent extends Component {
public void operation() {
//相应的功能处理
System.out.println("处理业务逻辑");
}
}
public abstract class Decorator extends Component {
/**
* 持有组件对象
*/
protected Component component;
/**
* 构造方法,传入组件对象
* @param component 组件对象
*/
public Decorator(Component component) {
this.component = component;
}
public void operation() {
//转发请求给组件对象,可以在转发前后执行一些附加动作
component.operation();
}
}
public class ConcreteDecoratorA extends Decorator {
public ConcreteDecoratorA(Component component) {
super(component);
}
private void operationFirst(){ } //在调用父类的operation方法之前需要执行的操作
private void operationLast(){ } //在调用父类的operation方法之后需要执行的操作
public void operation() {
//调用父类的方法,可以在调用前后执行一些附加动作
operationFirst(); //添加的功能
super.operation(); //这里可以选择性的调用父类的方法,如果不调用则相当于完全改写了方法,实现了新的功能
operationLast(); //添加的功能
}
}
public class ConcreteDecoratorB extends Decorator {
public ConcreteDecoratorB(Component component) {
super(component);
}
private void operationFirst(){ } //在调用父类的operation方法之前需要执行的操作
private void operationLast(){ } //在调用父类的operation方法之后需要执行的操作
public void operation() {
//调用父类的方法,可以在调用前后执行一些附加动作
operationFirst(); //添加的功能
super.operation(); //这里可以选择性的调用父类的方法,如果不调用则相当于完全改写了方法,实现了新的功能
operationLast(); //添加的功能
}
}
public class Client{
public static void main(String[] args){
Component c1 = new ConcreteComponent (); //首先创建需要被装饰的原始对象(即要被装饰的对象)
Decorator decoratorA = new ConcreteDecoratorA(c1); //给对象透明的增加功能A并调用
decoratorA .operation();
Decorator decoratorB = new ConcreteDecoratorB(c1); //给对象透明的增加功能B并调用
decoratorB .operation();
Decorator decoratorBandA = new ConcreteDecoratorB(decoratorA);//装饰器也可以装饰具体的装饰对象,此时相当于给对象在增加A的功能基础上在添加功能B
decoratorBandA.operation();
}
}
一个简单的装饰器的例子
public abstract class Battercake {
protected abstract String getMsg();
protected abstract int getPrice();
}
public class BaseBattercake extends Battercake{
protected String getMsg(){ return "煎饼";}
public int getPrice(){ return 5;}
}
// 装饰器类
public class BattercakeDecorator extends Battercake{
private Battercake battercake;
public BattercakeDecorator(Battercake battercake) {
this.battercake = battercake;
}
protected String getMsg(){ return this.battercake.getMsg();}
public int getPrice(){ return this.battercake.getPrice();}
}
public class EggDecorator extends BattercakeDecorator{
public EggDecorator(Battercake battercake) {
super(battercake);
}
protected String getMsg(){ return super.getMsg() + "1个鸡蛋";}
public int getPrice(){ return super.getPrice() + 1;}
}
public class SauageDecorator extends BattercakeDecorator{
public SauageDecorator(Battercake battercake) {
super(battercake);
}
protected String getMsg(){ return super.getMsg() + "1根香肠";}
public int getPrice(){ return super.getPrice() + 2;}
}
public class Test {
public static void main(String[] args) {
Battercake battercake;
battercake = new BaseBattercake();
battercake = new EggDecorator(battercake);
battercake = new EggDecorator(battercake);
battercake = new SauageDecorator(battercake);
System.out.println(battercake.getMsg() + ",总价" + battercake.getPrice());
}
}
装饰器模式和代理模式对比
- 装饰器模式就是一种特殊的代理模式
- 装饰器模式强调自身的功能扩展
- 代理模式强调代理过程的控制
装饰器模式的优点
- 装饰器是继承的有力补充,比继承灵活,不改变原有对象的情况下动态地给一个对象扩展功能,即插即用。
- 通过使用不同装饰类以及这些装饰类的排列组合,可实现不同效果
- 装饰器完全遵守开闭原则
装饰器模式的缺点
- 会增加代码量和类,增加程序的复杂性
- 动态装饰时,多层装饰时会更复杂