架构师之路--装饰模式

Posted 红-旺永福

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了架构师之路--装饰模式相关的知识,希望对你有一定的参考价值。

目录

介绍

定义

使用场景

代码实现


介绍

     装饰模式也称为包装模式,是结构型设计模式之一,其使用一种对客户端透明的方式来动态地扩展对象的功能,同时它也是继承关系的一种替代方案,在现实生活中我们也可以看到很多装饰模式的实例,比如人需要各种各样的衣服,不管你穿着怎么样,但是对个人来说本质是不变的,充其量只是在外面包装了一层而已,这就是装饰模式,装饰物也许各不相同,但是执行实质功能的主体是一样的。

     网上也有其他朋友介绍的资料:设计模式之装饰者模式

定义

     动态地给一个对象添加一些额外的职责,就增加功能来说,装饰模式相比生成子类更加灵活。

使用场景

     需要透明且动态的扩展类的功能时。

代码实现

     我们就以人穿衣服为例来描述一下,人的接口定义如下:

public abstract class Person {

    public abstract void dressed();
}

     人有一个穿衣服的接口行为,装饰模式有一个实质性实现的类,肯定是要实现这个接口的,比如男孩,示例如下:

public class Boy extends Person {

    @Override
    public void dressed() {
        System.out.println("男孩穿了帅气的衣服");
    }
}

     这个Boy就是我们最终要装饰的对象,还需要一个装饰者,它当中需要持有一个Boy实体类对象,比如我们定义一个穿衣服的人:

public abstract class ClothPerson extends Person {
    protected Person person;

    public ClothPerson(Person per) {
        person = per;
    }

    @Override
    public void dressed() {
        person.dressed();
    }
}

     它就是我们的抽象装饰者,但是还需要注意,虽然它的成员变量person最终我们想指向Boy,但是为了更好的扩展性,它必须定义为Person接口,保持两者间的隔离,而不能直接定义为Boy类对象。继续看一下,我们如何实现这个抽象装饰者:

public class ExpensiveClothPerson extends ClothPerson {

    public ExpensiveClothPerson(Person per) {
        super(per);
    }

    private void dressLeather() {
        System.out.println("穿的高级牛皮大衣");
    }

    @Override
    public void dressed() {
        super.dressed();
        dressLeather();
    }
}
public class CheapClothPerson extends ClothPerson {

    public CheapClothPerson(Person per) {
        super(per);
    }

    private void dressShorts() {
        System.out.println("穿的短裤");
    }

    @Override
    public void dressed() {
        super.dressed();
        dressShorts();
    }
}

     这两个实现类都是我们的抽象装饰者的实现,他们都调用了Boy的dress方法,但是又各自有独特的业务逻辑,这也就是为什么我们可以在不破坏原类层次结构的情况下为类增加一些功能的原因所在,我们只需要在被装饰对象的相应方法前后增加相应的功能逻辑即可,当然在装饰物只有一个的情况下,完全可以不必声明抽象装饰者,直接定义一个普通类表示装饰者都行,这里我们写的例子定义了两个穿衣服的人,一种是穿高档衣服的,一种是穿便宜衣服的。

     两个类其实没有什么本质上的区别,都是为Boy类的dress方法提供功能扩展,不过这种扩展并非直接修改原有的方法逻辑,更恰当的说,仅仅是在另一个类中将原有方法和新逻辑进行封装融合而已。最后我们来看一下测试类。

public class Test {

    public static void main() {
        Person boy = new Boy();

        Person expensive = new ExpensiveClothPerson(boy);
        expensive.dressed();

        Person cheap = new CheapClothPerson(boy);
        cheap.dressed();
    }
}

     在android系统源码中,也有很多装饰模式的实例,我们最最常用的就是Context,大家可能没有感觉到,平时我们调用各种Context的方法,它的底层是如何实现的呢?我们以Activity为例来学习一下,源码如下:

     从Activity的定义中可以看到,它是继承了ContextThemeWrapper,再往上,ContextThemeWrapper继承了ContextWrapper,ContextWrapper再往上继承了Context,源码截图如下:

     而我们再看看ContextWrapper类中的实现,基本都是调用mBase的方法完成业务逻辑的,这个mBase也是一个Context的实例,也就是装饰模式的被装饰者了,而这里的各种wrapper就是装饰者了,所有装饰者都通过父类的protected成员变量mBase操作被装饰者,而这个mBase对象的实例就是ContextImpl,它是在ActivityThread中启动各个Application、Activity、Service等等实例时创建的,源码如下:

     我们这里截图是createservice时候的逻辑,其他组件基本都是类似的流程,大家感兴趣可以自己去查一下。我们再来看一下ContextImpl类中业务方法的具体实现,源码如下:

     上面两张截图是sendBroadcast和startActivity两个业务方法的实现,可以看到,实质性的逻辑就是在这里完成的,这也就是真正的被装饰者了。

     如果当前的wrapper满足不了我们新的需求了,那我们可以考虑在不修改ContextImpl类的逻辑情况下,新建wrapper,在其中增加我们的新逻辑,这样就可以达到目的了。

以上是关于架构师之路--装饰模式的主要内容,如果未能解决你的问题,请参考以下文章

架构师之路--装饰模式

架构师之路 — 软件架构 — 应用架构设计模式

架构师之路 — 软件架构 — 系统架构设计模式

架构师内功心法,有重构项目经验必备的装饰者模式详解

架构师内功心法,有重构项目经验必备的装饰者模式详解

架构师之路:一个架构师需要掌握的知识技能