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

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

作者: 钉某人 | 来源:发表于2017-11-15 19:28 被阅读0次
    源码地址 https://github.com/DingMouRen/DesignPattern
    装饰者模式.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();
        }
    
    总结

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

    相关文章

      网友评论

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

          本文链接:https://www.haomeiwen.com/subject/xtvhvxtx.html