在之前的我为 RecyclerView 添加 HeaderView 和 FooterView 的时候就提到了 ListView 在添加头布局和脚布局时就用到了装饰者模式,装饰者模式又称为包装模式(Wrapper Pattern),它使用一个对客户端透明的方式来动态扩展对象的功能,同时也是替代继承关系的方案之一。在生活中也能体现装饰者模式,比如人要穿衣服,可以穿运动装和正装,但是无论怎么样,本质都还是一个人,只是装饰了不同的衣着。所以装饰者模式就是装饰物不同,但是本质不变。
第二十一章 装饰模式
1.定义
动态地给一个对象添加一些额外的职责, 就增加功能来说,装饰模式相对于生成子类来说要更灵活。
2.使用场景
1).需要透明且动态地扩展类的功能时。
3.简单实现
装饰模式一般有四类角色:
Component :抽象组件,一般为接口或者抽象类,充当被装饰的原始对象。
ConcreteComponent :具体组件,具体的被装饰对象。
Decorator :抽象装饰者,一般为抽象类,内部有一个指向组件的引用,根据不同的装饰逻辑实现不同的具体子类,如果具体装饰者只有一个的话,可以省略此类。
ConcreteDecorator :具体装饰者,对抽象装饰者作出具体实现。
就拿开头提到了例子来说,人的衣着可能会随时变化,一个男生,在家穿得可能比较随便,但是出去运动或者约会时,就会装饰不同的穿着,我们就可以用装饰模式来实现,而不用创建多个男生子类,比如运动型男生和约会型男生了。
Person(抽象组件)类:
public abstract class AbstractPerson {
public abstract void dressed();
}
Boy(具体组件)类:
public class Boy extends AbstractPerson {
private AbstractDressing mAbstractDressing;
@Override
public void dressed() {
System.out.println("男生夏天在家一般只穿条内裤");
}
public void sport() {
if (mAbstractDressing == null || !(mAbstractDressing instanceof SportDressing)) {
mAbstractDressing = new SportDressing(this);
mAbstractDressing.dressed();
}
}
public void date(){
if (mAbstractDressing == null || !(mAbstractDressing instanceof DateDressing)) {
mAbstractDressing = new DateDressing(this);
mAbstractDressing.dressed();
}
}
}
AbstractDressing(抽象装饰者):
public abstract class AbstractDressing extends AbstractPerson {
private AbstractPerson mAbstractPerson;
public AbstractDressing(AbstractPerson mAbstractPerson) {
this.mAbstractPerson = mAbstractPerson;
}
@Override
public void dressed() {
mAbstractPerson.dressed();
}
}
SportDressing(具体装饰者):
public class SportDressing extends AbstractDressing {
public SportDressing(AbstractPerson mAbstractPerson) {
super(mAbstractPerson);
}
private void sportsVest() {
System.out.println("穿上运动背心");
}
private void sportShorts() {
System.out.println("穿上运动短裤");
}
private void sportShoes() {
System.out.println("穿上运动鞋");
}
@Override
public void dressed() {
super.dressed();
sportsVest();
sportShorts();
sportShoes();
}
}
public class DateDressing extends AbstractDressing {
public DateDressing(AbstractPerson mAbstractPerson) {
super(mAbstractPerson);
}
private void shirts() {
System.out.println("穿上衬衣");
}
private void trousers() {
System.out.println("穿上西裤");
}
private void leatherShoes() {
System.out.println("穿上皮鞋");
}
@Override
public void dressed() {
super.dressed();
shirts();
trousers();
leatherShoes();
}
}
Boy mBoy = new Boy();
System.out.println("在家穿的衣服");
mBoy.dressed();
System.out.println("运动时穿的衣服");
mBoy.sport();
System.out.println("约会时穿的衣服");
mBoy.date();
Boy 的本质还是那个 Boy,只是根据不同的行为而装饰了不同的东西,SportDressing 和 DateDressing 为 Boy 对象提供了功能扩展,而且是在没有直接修改原有的逻辑和结构的基础上扩展了功能。
4.总结
装饰模式与代理模式有些相似,往往会把装饰模式误以为是代理模式,它们的区别在于装饰模式是以对客户端透明的方式扩展对象的功能,是替代继承关系的方案之一,而代理模式则是给对象提供一个代理对象,由代理对象来控制对原对象的引用;装饰模式是为对象增加功能,而代理模式只是对对象施加控制,并不会对原对象的功能有所增强。