设计模式知识梳理(4) - 结构型 - 装饰模式

2018-11-26  本文已影响62人  泽毛

一、基本概念

1.1 定义

装饰模式使用一种对客户端透明的方式来 动态地扩展对象的功能,同时它是继承关系的一种替代方案,其包含以下四种角色:

1.2 例子

/**
 * 抽象组件类。
 *
 * @author lizejun
 **/
public abstract class Component {

    /**
     * 抽象组件类的抽象方法。
     */
    public abstract void operate();
}
/**
 * 组件具体实现类。
 *
 * @author lizejun
 **/
public class ConcreteComponent extends Component {

    @Override
    public void operate() {}
}
/**
 * 抽象装饰者。
 *
 * @author lizejun
 **/
public class Decorator extends Component {

    private Component mComponent;

    public Decorator(Component component) {
        mComponent = component;
    }

    @Override
    public void operate() {
        mComponent.operate();
    }
}
/**
 * 装饰者具体实现类。
 * 
 * @author lizejun
 **/
public class ConcreteDecoratorA extends Decorator {

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

    @Override
    public void operate() {
        //在父类之前调用装饰方法。
        operateBefore();
        super.operate();
        //在父类之后调用装饰方法。
        operateAfter();
    }

    /**
     * 装饰方法 A。
     */
    private void operateBefore() {

    }

    /**
     * 装饰方法 B。
     */
    private void operateAfter() {

    }
}

1.3 应用场景

1.4 优缺点

优点

缺点

二、Android 源码

Android源码当中,有一个装饰模式的典型应用 Context,它的类图我们在之前分析SP的内部实现原理的时候也有分析过, Android 数据存储知识梳理(3) - SharedPreference 源码解析

Context是一个抽象类,在其中定义了我们常用的大量抽象方法,它对应于我们上面谈到的 抽象组件

public abstract class Context {

    public abstract void startActivity(@RequiresPermission Intent intent);

    public abstract void sendBroadcast(@RequiresPermission Intent intent);

    public abstract ComponentName startService(Intent service);

}

其真正的实现是在ContextImpl当中,它继承自Context抽象类,它的角色是 组件的具体实现类

class ContextImpl extends Context {

    @Override
    public void startActivity(Intent intent) {
        warnIfCallingFromSystemProcess();
        startActivity(intent, null);
    }

    @Override
    public void sendBroadcast(Intent intent) {
        warnIfCallingFromSystemProcess();
        String resolvedType = intent.resolveTypeIfNeeded(getContentResolver());
        try {
            intent.prepareToLeaveProcess(this);
            ActivityManager.getService().broadcastIntent(
                    mMainThread.getApplicationThread(), intent, resolvedType, null,
                    Activity.RESULT_OK, null, null, null, AppOpsManager.OP_NONE, null, false, false,
                    getUserId());
        } catch (RemoteException e) {
            throw e.rethrowFromSystemServer();
        }
    }

    @Override
    public ComponentName startService(Intent service) {
        warnIfCallingFromSystemProcess();
        return startServiceCommon(service, false, mUser);
    }
}

而上面谈到的装饰者就是最常见的ActivityServiceApplication这三个,它们有一个共同的基类ContextWrapper,而在ContextWrapper中持有一个指向具体抽象对应的引用mBase,当调用Context定义的抽象方法时,其实是由mBase来完成的。

public class ContextWrapper extends Context {

    Context mBase;

    public ContextWrapper(Context base) {
        mBase = base;
    }

    protected void attachBaseContext(Context base) {
        if (mBase != null) {
            throw new IllegalStateException("Base context already set");
        }
        mBase = base;
    }

    @Override
    public void startActivity(Intent intent) {
        mBase.startActivity(intent);
    }

那么mBase是在哪里赋值的呢?

我们以Activity为例,看一下ActivityThread当中的代码,当启动一个Activity的时候,必然需要走到performLaunchActivity方法,这里会创建ContextImplActivity对象,最后通过setOuterContextattach方法建立双向的关联,其中Activity#attach就会给基类中的mBase变量赋值。

  private Activity performLaunchActivity(ActivityClientRecord r, Intent customIntent) {
        //为 Activity 创建 ContextImpl 对象。
        ContextImpl appContext = createBaseContextForActivity(r);
        Activity activity = null;
        try {
            java.lang.ClassLoader cl = appContext.getClassLoader();
            //创建 Activity。
            activity = mInstrumentation.newActivity(
                    cl, component.getClassName(), r.intent);
            StrictMode.incrementExpectedActivityCount(activity.getClass());
            r.intent.setExtrasClassLoader(cl);
            r.intent.prepareToEnterProcess();
            if (r.state != null) {
                r.state.setClassLoader(cl);
            }
        } catch (Exception e) {
            if (!mInstrumentation.onException(activity, e)) {
                throw new RuntimeException(
                    "Unable to instantiate activity " + component
                    + ": " + e.toString(), e);
            }
        }
       
       //ContextImpl 和 Activity 建立双向的关联关系。
       appContext.setOuterContext(activity);
       activity.attach(appContext, this, getInstrumentation(), r.token,
                        r.ident, app, r.intent, r.activityInfo, title, r.parent,
                        r.embeddedID, r.lastNonConfigurationInstances, config,
                        r.referrer, r.voiceInteractor, window, r.configCallback);
  }

三、项目应用

待补充。

四、参考文献

上一篇下一篇

猜你喜欢

热点阅读