装饰者模式(包装一个对象,来提供新的行为)
源码地址 | https://github.com/DingMouRen/DesignPattern |
---|
- Component:抽象组件,可以是一个接口或者抽象类,是被装饰的原始对象。
- ConcreteComponent:组件具体实现类。该类是Component类的基本实现,也是我们装饰的具体对象。
- Decorator:抽象装饰者。它承担的职责是为了装饰组件对象,其内部一定要有一个指向组件对象的引用。在多数情况下,该类为抽象类,需要根据不同的装饰逻辑实现不同的具体子类。如果装饰逻辑单一,只有一个情况下我们可以省略该类直接作为具体的装饰者。
- ConcreteDecoratorA:装饰者具体实现类,只是对抽象装饰者作出具体的实现。
定义
装饰者模式动态地给一个对象添加一些额外的职责。在增加功能方面,装饰者模式比生成子类更为灵活。
使用场景
- 在不影响其他对象的情况下,以动态、透明的方式给单个对象添加功能
- 处理可以撤销的职责
- 当不能采用生成子类的方式进行扩展功能时。1.为类扩展功能造成产生大量子类,子类数目爆炸性增长。2.不能生成子类的情况,比如被final修饰的类
协作
Decorator将请求转发给它的Component对象,并有可能在转发请求前后执行一些附加的动作,也就是想要添加的新行为。
举个栗子
不管男的女的都是要穿衣服的,我们抽象成一个抽象类Person,行为就是穿衣服,定义一个穿衣服的抽象方法dressed(),定义两个类Boy、Girl分别继承Person类,它们只有一个行为。假设Boy Girl都通过调用自己实现的dressed()方法,已经穿了一件衣服,可是人不能只穿一件衣服吧(o)/~,但是我们不想去修改Boy Gril的对象,同时让创建出来的这两个实例对象能穿更多的衣服,也就是说在不影响对象的情况下,为对象添加功能。好啦,可以开始使用装饰者模式了。我们定义一个装饰的抽象类PersonCloth,让它继承抽象组件Person类,同时我们让PersonCloth类持有一个Person类的引用,通过构造器传入。因为继承了Person类,就要实现dressed()这个抽象方法,里面的具体实现自然是Person类的引用调用dressed(),这就是保存这个引用的主要原因,可以方便的调用具体被装饰对象的dressed()方法(java运行时类型判断)。现在我们要定义装饰者的具体实现对象,定义CheapCloth类继承PersonCloth类,实现dressed()方法,这里面有一个super.dressed()这就是被装饰对象自己原来的实现,我们想添加的行为怎么办呢?只要在CheapCloth这个具体装饰对象中定义新的行为,然后在super.dressed()前或者后调用就可以了,这样就添加了功能,调用的时候自然调用的是这个装饰者对象CheapCloth的dressed()方法。就好像通过CheapCloth类包裹了Boy类一样,我们没有动Boy这样的具体组件对象,也没有使用继承可能会造成类爆炸的方式。
//抽象组件类:类Person定义一个穿衣的抽象方法
public abstract class Person {
public abstract void dressed();
}
//组件具体实现类:需要被装饰的具体对象
public class Boy extends Person {
@Override
public void dressed() {
System.out.println(getClass().getSimpleName()+"穿牛仔褂");
}
}
//装饰抽象类:表示人要穿的衣服
public abstract class PersonCloth extends Person{
/**
* 保持一个Person类的引用,方便调用具体被装饰对象中的方法
* 这样可以在不破坏原类层次结构的情况下为类添加一些功能,只需要在被装饰对象的相应方法
* 前或后增加相应的逻辑功能就行。
* 如果装饰物只有一个的话,不必声明一个抽象类作为装饰者抽象的提取。只要定义一个普通的类表示装饰者就行
*/
private Person person;
public PersonCloth(Person person) {
this.person = person;
}
@Override
public void dressed() {
person.dressed();//调用Person类型的dressed()方法
}
public Person getPerson() {
return person;
}
}
//具体装饰者
public class CheapCloth extends PersonCloth {
public CheapCloth(Person person) {
super(person);
}
@Override
public void dressed() {
//原来具体组件实现
super.dressed();
//添加的新行为的具体实现
dressShorts();
}
private void dressShorts(){
System.out.println(getPerson().getClass().getSimpleName()+"穿短裤");
}
}
public static void main(String[] args) {
//创建被装饰对象
Person person = new Boy();
//给他穿便宜衣服
PersonCloth clothCheap = new CheapCloth(person);
clothCheap.dressed();
//穿贵的衣服
PersonCloth clothExpensive = new ExpensiveCloth(person);
clothExpensive.dressed();
Person girl = new Girl();
PersonCloth clothCheapGirl = new CheapCloth(girl);
clothCheapGirl.dressed();
}
使用
public static void main(String[] args) {
//创建被装饰对象
Person person = new Boy();
//给他穿便宜衣服
PersonCloth clothCheap = new CheapCloth(person);
clothCheap.dressed();
//穿贵的衣服
PersonCloth clothExpensive = new ExpensiveCloth(person);
clothExpensive.dressed();
Person girl = new Girl();
PersonCloth clothCheapGirl = new CheapCloth(girl);
clothCheapGirl.dressed();
}
总结
装饰者模式为所装饰的对象增加功能,而不使用继承的方式,也不会影响被装饰对象。有的时候会跟代理模式混淆,代理模式做的不是增加功能,而是对代理的对象进行控制。