本文介绍结构、demo、使用场景选用、与代理模式的区别对比
简介
Decorator模式又叫包装模式。
通过一种对客户端透明的方式来扩展对象的功能,是继承关系的一个替换方案
在原有方法上包装更多的方法。通过子类包装。核心是子类扩展父类。类比于代理、springAOP。区别于继承的扩展。横向扩展性强
结构图
角色和职责
- 抽象组件角色:一个抽象接口,是被装饰类和装饰父类的接口
- 具体组件角色:作为抽象组件的实现类
- 抽象装饰角色:包含一个组件的引用,并定义了与抽象组件一致的接口
- 具体装饰角色:为抽象装饰角色的实现类。负责具体的装饰
实现
本demo是对car的功能进行装饰。也就是扩展车的功能。横向扩展。
UML图如:
被装饰的接口
package com.mym.designmodel.decorator;
/**
* 职责:Component
*/
public interface Car {
public void show();
public void run();
}
被装饰的接口的一个具体实现类
package com.mym.designmodel.decorator;
/**
* 职责 :ConcreteComponent.具体组件角色
*/
public class RunCar implements Car{
@Override
public void show() {
this.run();
}
@Override
public void run() {
System.out.println("车车可以run!");
}
}
开始装饰
装饰抽象组件
package com.mym.designmodel.decorator;
/**
* 职责 :Decorator 抽象接口,装饰规则。
*/
public abstract class CarDecorator implements Car{
Car car = null;
public CarDecorator(Car car){
this.car = car;
}
public abstract void show();//具体要装饰的方法
@Override
public void run() {
this.getCar().run();//不做任何处理,我们装饰的是show方法,其他方法就先放过
}
public Car getCar() {
return car;
}
public void setCar(Car car) {
this.car = car;
}
}
具体装饰类1
package com.mym.designmodel.decorator;
/**
* 职责:ConcreteDecorator 具体装饰实现
*/
public class SwimCarDecorator extends CarDecorator{
public SwimCarDecorator(Car car){
super(car);
}
@Override
public void show() {
this.getCar().show();
this.swim();
}
public void swim(){
System.out.println("车车可以swim!");
}
}
具体装饰类2
package com.mym.designmodel.decorator;
/**
* 职责:ConcreteDecorator 具体装饰实现
*/
public class FlyCarDecorator extends CarDecorator{
public FlyCarDecorator(Car car){
super(car);
}
@Override
public void show() {
car.show();
this.fly();
}
public void fly(){
System.out.println("车车可以fly!");
}
}
测试:
package com.mym.designmodel.decorator;
public class Test {
public static void main(String[] args) {
Car car = new RunCar();
car.show();
System.out.println("---------------------");
Car swimCarDecorator = new SwimCarDecorator(car);
swimCarDecorator.show();
System.out.println("---------------------");
Car flyCarDecorator = new FlyCarDecorator(swimCarDecorator);
flyCarDecorator.show();
}
}
执行结果
车车可以run!
---------------------
车车可以run!
车车可以swim!
---------------------
车车可以run!
车车可以swim!
车车可以fly!
一般使用场景
需要对一个类功能扩展的地方
优缺点
- 横向扩展非常方便
- 同样是会有很多子类
对比代理模式
代理模式详细可以查看另一博文
这里简单讨论一下区别(参考网上很多思考,然后这里做个小总结):
关注点
- 装饰器模式关注于在一个对象上动态的添加方法
- 代理模式关注于控制对对象的访问
也可理解为:
- 代理模式,代理类可以对它的客户隐藏一个对象的具体信息。因此,当使用代理模式的时候,我们常常在一个代理类中创建一个对象的实例。
- 装饰模式,通常是将原始对象作为一个参数传给装饰者的构造器。
方法增强时机
- 代理模式,代理和真实对象之间的的关系通常在编译时就已经确定
- 装饰模式,装饰者能够在运行时递归地被构造
使用场景
- 用装饰模式,一般意味着增加功能:装饰模式:对被装饰的对象增加额外的职责,满足里氏代换原则(子类可以代替父类)。
- 如,自行车可以脚踏骑车,装饰模式使用后,可能装饰了电动功能,就像大街上有的那种又可以脚踏又可以电动的自行车,装饰最基本的是保证原始功能正常使用。
- 用代理模式,一般意味着在限制使用:代理模式是修改被代理对象的行为。
- 如权限判断,权限即是限制。如网吧上网,网管代理你的访问,并会限制访问一些资源
用户(使用)角度
场景设置:A类是原始功能的类, B是装饰模式中对A类的扩展类,C是代理模式中对A类的扩展类
那么对于用户调用来说:
- 使用装饰模式,用户更关系的是B的功能(包含A的原始功能)。
- 使用代理模式,用户更关心A的功能。并不关系C的功能。
选用方向
- 扩展一个类的功能时,用装饰
- 对有的方法进行改进,用代理