傻皇帝真应该学习下装饰模式

300 阅读4分钟

       很多同学都看过《皇帝的新衣》,它是丹麦作家安徒生创作的童话,讲述的是一个愚蠢的皇帝被两个骗子愚弄,穿上了一件看不见的新装,赤裸裸的进行游行大典的故事。

       对于皇帝老儿来说,他的这件新衣为什么对于他来说起不到装饰的效果呢?

      下面我们就来分析一下,对于装饰来说,装饰以后要比原来的状态至少是更好看的,或者说是功能更强的,但是愚蠢的皇帝显然没有任何装饰,自身的供能也没有增强,当然我们从这个故事中可以说明这皇帝没皇帝有学习过装饰模式,所以有必要给他普及一下。

下面我将详细的讲解一下装饰模式:

装饰模式是什么

简单的说:给一个对象添加一些额外的功能。(比如我们给皇帝穿了件新衣服)

思考:我们想要给一个对象添加一些额外的功能,我们可以有几种做法?

1、采用继承。

比如TextView和EditText,EditText继承了TextView,EditText中不仅有TextView的功能,还有一些自己特有的功能。

2、采用静态代理或者动态代理。

请看这篇章:juejin.cn/post/705286…

其中实战篇中静态代理通过在内部封装不同API下的通知来实现各个android版本下通知的实现,现相当于通知功能的增强。

通过动态代理来代理Retrofit的接口API,来实现接口的增强功能,内部封装了OkHttp的请求体和请求的过程。

3、采用装饰模式。

4、适配器模式。

请看这篇文章:juejin.cn/post/705415…

适配器模式解决了2个问题,一个是接口API不匹配的问题,一个是统一输出的问题。

那么接口API不匹配,我们通过适配器,封装出来了另外的接口,这个接口也是满足要求的,那么我们认为就是功能的一种增强。

下面我们学习一下装饰模式的使用场景

装饰模式的使用场景

需要**扩展(增强)**类的功能时。

装饰模式的UML类图

装饰模式的模板代码

根据UML类图,生成的模板代码如下:

第一步:定义被装饰的组件接口,内部只有一个方法。

package com.example.createproject;

/**
 * 抽象组件
 */
public abstract class Component {

    public abstract void operate();

}

第二步:定义具体的被装饰组件。

package com.example.createproject;

import android.util.Log;

/**
 * 具体的被装饰组件
 */
public class ConcreteComponent extends Component{
    private static final String TAG = "ConcreteComponent";

    @Override
    public void operate() {
        Log.e(TAG,"ConcreteComponent 执行");
    }
}

第三步:定义装饰着基类。

package com.example.createproject;

/**
 * 装饰着抽象是为了有更多的装饰者
 */
public class Decorator extends Component{

    protected Component component;

    public Decorator(Component component) {
        this.component = component;
    }


    @Override
    public void operate() {
        component.operate();
    }
}

第四步:定义具体的装饰者。

package com.example.createproject;

/**
 * 具体的装饰者
 */
public class ConcreteDecorator extends Decorator{

    public ConcreteDecorator(Component component) {
        super(component);
    }

    public void operate1(){

    }

    public void operate2(){

    }

    @Override
    public void operate() {
        // 装饰的逻辑
        operate1();
        // 被装饰组件执行逻辑
        super.operate();
        // 装饰的逻辑
        operate2();
    }
}

第五步:装饰模式的使用。

// 定义原始组件
Component component = new ConcreteComponent();
// 定义装饰器
Decorator decorator = new ConcreteDecorator(component);
// 执行包装以后的逻辑
decorator.operate();

思考:装饰者模式的模板代码 和 代理模式的模板代码非常的相似。都是注入被装饰的类到装饰类或者代理类中。

思考:设计模式很多时候的边界不是很清晰,有的代码,也可以认为是装饰模式,也可以认为是代理模式,我们不需要纠结于设计模式的结构,而是应该关注它的思想。

下面我们学习一下Android源码中装饰模式的体现

源码中装饰模式的体现

第一步:寻找被装饰者接口

Context类中有startActivity方法。

第二步:寻找被装饰者。

ContextImpl:它是Context的实现类,在这个类中,实现了startActivity方法。

第三步:寻找装饰者基类。

ContextWrapper:在这个类中,首先在构造中注入了Context,赋值给了mBase变量,然后再ContextWrapper的startActivity方法中,调用了mBase.startActivity,这个不就是装饰着模式的例子吗?实现了注入被装饰者,然后调用被装饰者方法的逻辑

第四步:寻找装饰者类

Activity:Activity继承了ContextWrapper,相当于是装饰者,在Activity内部可以调用startActivity。

至此:Android源码中的装饰着模式寻找完毕。

装饰模式总结

      通过上面的学习,我们发现装饰模式其实并不是很复杂,其实就是一种类的封装,然后在此基础上对功能的增强。