Android 源码的装饰者模式

Android 源码的装饰者模式

装饰者模式介绍

装饰者模式(Decorator Pattern)也称为包装模式 (Wrapper Pattern),结构型设计模式之一,其使用一种对客户端透明的方式来动态地扩展对象地功能,同时它也是继承关系的一种替代方案之一。

装饰者模式的定义

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

装饰模式的使用场景

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

Android 源码中的装饰模式

Context 类在 Android 中被称为“上帝对象”,它本质是一个抽象类,其在我们装饰者模式里相当于抽象组件,而在其内部定义了大量的抽象方法,比如我们经常会用到的 startActivity 方法。

    ...
    public abstract void startActivity(@RequiresPermission Intent intent);
    ...
    public abstract void startActivity(@RequiresPermission Intent intent,
            @Nullable Bundle options);
    ...

真正的实现是在 ContextImpl 中完成的,ContextImpl 继承自 Context 抽象类,并实现了 Context 中的抽象方法。

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

    /** @hide */
    @Override
    public void startActivityAsUser(Intent intent, UserHandle user) {
        startActivityAsUser(intent, null, user);
    }

    @Override
    public void startActivity(Intent intent, Bundle options) {
        warnIfCallingFromSystemProcess();

        // Calling start activity from outside an activity without FLAG_ACTIVITY_NEW_TASK is
        // generally not allowed, except if the caller specifies the task id the activity should
        // be launched in. A bug was existed between N and O-MR1 which allowed this to work. We
        // maintain this for backwards compatibility.
        final int targetSdkVersion = getApplicationInfo().targetSdkVersion;

        if ((intent.getFlags() & Intent.FLAG_ACTIVITY_NEW_TASK) == 0
                && (targetSdkVersion < Build.VERSION_CODES.N
                        || targetSdkVersion >= Build.VERSION_CODES.P)
                && (options == null
                        || ActivityOptions.fromBundle(options).getLaunchTaskId() == -1)) {
            throw new AndroidRuntimeException(
                    "Calling startActivity() from outside of an Activity "
                            + " context requires the FLAG_ACTIVITY_NEW_TASK flag."
                            + " Is this really what you want?");
        }
        mMainThread.getInstrumentation().execStartActivity(
                getOuterContext(), mMainThread.getApplicationThread(), null,
                (Activity) null, intent, -1, options);
    }

这里 ContextImpl 就相当于组件具体实现类,那么谁来承担装饰者的身份呢?

Activity 从类层次上来说本质是一个 Context。Activity 并非直接继承于 Context,而是继承于 ContextThemeWrapper。

public class Activity extends ContextThemeWrapper
        implements LayoutInflater.Factory2,
        Window.Callback, KeyEvent.Callback,
        OnCreateContextMenuListener, ComponentCallbacks2,
        Window.OnWindowDismissedCallback, WindowControllerCallback,
        AutofillManager.AutofillClient {
...
}

而这个 ContextThemeWrapper 又是继承于 ContextWrapper。

public class ContextThemeWrapper extends ContextWrapper {
...
}

最终这个 ContextWrapper 才继承于 Context。

为什么类层次会这么复杂呢?其实这里就是一个典型的装饰模式,ContextWrapper 就是我们要找的装饰者,在 ContextWrapper 中有一个 Context 的引用。

public class ContextWrapper extends Context {
    Context mBase;

    public ContextWrapper(Context base) {
        mBase = base;
    }
    
    /**
     * Set the base context for this ContextWrapper.  All calls will then be
     * delegated to the base context.  Throws
     * IllegalStateException if a base context has already been set.
     * 
     * @param base The new base context for this wrapper.
     */
    protected void attachBaseContext(Context base) {
        if (mBase != null) {
            throw new IllegalStateException("Base context already set");
        }
        mBase = base;
    }
    ...

ContextWrapper 类的 startActivity 方法如下:

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

可以看出它调用了 ContextImpl 中对应的方法。

装饰模式应用的套路都是很相似的,对于具体方法的包装扩展则由 ContextWrapper 的具体子类完成,比如我们的 Activity、Service 和 Application。

发布了105 篇原创文章 · 获赞 2 · 访问量 3748

猜你喜欢

转载自blog.csdn.net/caoshen2014/article/details/103231162