装饰者模式(包装一个对象,来提供新的行为)

源码地址 https://github.com/DingMouRen/DesignPattern
装饰者模式(包装一个对象,来提供新的行为)_第1张图片
装饰者模式.png
  • 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();
    }
总结

装饰者模式为所装饰的对象增加功能,而不使用继承的方式,也不会影响被装饰对象。有的时候会跟代理模式混淆,代理模式做的不是增加功能,而是对代理的对象进行控制。

你可能感兴趣的:(装饰者模式(包装一个对象,来提供新的行为))