装饰模式和Context类结构

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/www851903307/article/details/80763406

一、基本概念:

1、定义:动态地给一个对象添加一些额外的职责。装饰模式比子类就增加功能来说更为灵活。

2、应用场景:
* 需要扩展一个类的功能。
* 动态的为一个对象增加功能,而且还能动态撤销。

3、缺点:
多层装饰者存在的层级复杂的情况

4、通用类图:
这里写图片描述
* Component:抽象类或者接口,这是装饰者和被装饰者都需要实现的接口或者继承的基类。
* ConcreteComponent:被装饰者的具体构件
* Decorate:装饰者角色,一般是一个抽象类,定义一个private变量指向Component。
* ConcreteDecotator:装饰者具体实现类,一些在方法中实现一些功能的添加

二、示例:

1、Component:
定义了一个接口,定义了一个sing的方法

public interface Component {
    void sing();
}

2、ConcreteComponent:
定义了具体的被装饰者,实现了Component接口

public class ConcreteComponent implements Component {
    @Override
    public void sing() {
        System.out.print("sing....");
    }
}

3、Decorator:
定义了抽象装饰者,内部持有被装饰者的引用,才能操作被装饰者

public abstract class Decorator implements Component {
    private Component mComponent;

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

    @Override
    public void sing() {
        mComponent.sing();
    }
}

4、ConcreteDecorator:
定义了具体的装饰者,可以在方法内做一些功能扩展的工作。

public class ConcreteDecorator extends Decorator {

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


    //先交钱,后唱歌(添加了收费的功能)
    @Override
    public void sing() {
        System.out.print("先交钱....");
        super.sing();
    }
}

5、测试:

public class DecoratorTest {

    public static void main(String[] args){
        Component component = new ConcreteComponent();
        Decorator decorator = new ConcreteDecorator(component);
        decorator.sing();
    }
}

结论:
这里写图片描述

6、更换装饰者:

public class ConcreteDecorator2 extends Decorator{
    public ConcreteDecorator2(Component component) {
        super(component);
    }

    @Override
    public void sing() {
        System.out.print("奏乐....");
        super.sing();
    }
}
public class DecoratorTest {

    public static void main(String[] args){
        Component component = new ConcreteComponent();
        Decorator decorator = new ConcreteDecorator2(component);
        decorator.sing();
    }
}

更换了一个装饰者,提供了一些其他功能,方便装饰者的更换。

三、Android中装饰模式

1、Context相关类图:
这里写图片描述

  • Context 对应的是装饰者和被装饰者都需要继承的抽象类
  • ContextWrapper 对应的是装饰者的基类
  • ContextImpl 对应的是被装饰者
  • Activity、Service、Application对应的事装饰者的具体实现类

2、ContextWrapper:

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;
    }
    ......
}

装饰者ContextWrapper持有被装饰者Context的引用。虽然不是抽象类,但主要负责Context的方法调用,可以将ContextWrapper理解为是一个装饰者的基类。
问题:被装饰的Context 什么时候创建,如何通过attachBaseContext 将其传入。

3、Application Context 创建:
应用程序启动最后是通过ActivityThread去启动Activity
ActivityThread:

private Activity performLaunchActivity(ActivityClientRecord r, Intent customIntent) {

    ......
    Application app = r.packageInfo.makeApplication(false, mInstrumentation);
    ......
}

通过调用LoadedApk的makeApplication方法创建了Application实例对象。

LoadedApk:

public Application makeApplication(boolean forceDefaultAppClass,
                                   Instrumentation instrumentation) {
    ......
    ContextImpl appContext = ContextImpl.createAppContext(mActivityThread, this);
    app = mActivityThread.mInstrumentation.newApplication(
            cl, appClass, appContext);
    appContext.setOuterContext(app);
    ......
}

创建了被装饰者ContextImpl对象,然后调用了Instrumentation的newApplication方法。

Instrumentation:

 static public Application newApplication(Class<?> clazz, Context context)
            throws InstantiationException, IllegalAccessException, 
            ClassNotFoundException {
        Application app = (Application)clazz.newInstance();
        app.attach(context);
        return app;
    }

通过调用Application(装饰者)的attach方法,将ContextImpl对象传入。

final void attach(Context context) {
    attachBaseContext(context);
    mLoadedApk = ContextImpl.getImpl(context).mPackageInfo;
}

通过调用装饰基类ContextWrapper的attachBaseContext方法来将ContextImpl对象传入,然后对被装饰者进行操作。

4、Activity Context的创建:

ActivityThread:

private Activity performLaunchActivity(ActivityClientRecord r, Intent customIntent) {
    ......
    //(1)创建了ContextImpl
    ContextImpl appContext = createBaseContextForActivity(r);
    Activity activity = null;
    try {
        java.lang.ClassLoader cl = appContext.getClassLoader();
        //(2) 创建Activity对象
        activity = mInstrumentation.newActivity(
                cl, component.getClassName(), r.intent);
        ......

        if (activity != null) {
            appContext.setOuterContext(activity);
            //(3)将ContextImpl传入到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);

            ......

    return activity;
}

调用了Activity的attach方法:
Activity:

  final void attach(Context context, ActivityThread aThread,
            Instrumentation instr, IBinder token, int ident,
            Application application, Intent intent, ActivityInfo info,
            CharSequence title, Activity parent, String id,
            NonConfigurationInstances lastNonConfigurationInstances,
            Configuration config, String referrer, IVoiceInteractor voiceInteractor,
            Window window, ActivityConfigCallback activityConfigCallback) {

        attachBaseContext(context);
        ......
}

完成了ContextImpl的创建,并传入到Activity中

5、Service Context的创建

Service的启动最后调用到了ActivityThread的handleCreateService方法
ActivityThread:

private void handleCreateService(CreateServiceData data) {
    ......
    Service service = null;
    try {
        java.lang.ClassLoader cl = packageInfo.getClassLoader();
        //(1)service创建
        service = (Service) cl.loadClass(data.info.name).newInstance();

        ......
        //(2)ContextImpl创建
        ContextImpl context = ContextImpl.createAppContext(this, packageInfo);
        context.setOuterContext(service);

        Application app = packageInfo.makeApplication(false, mInstrumentation);
        //(3)ContextImpl传入
        service.attach(context, this, data.info.name, data.token, app,
                ActivityManager.getService());
        service.onCreate();
        ......
    }
}

Service:

public final void attach(
        Context context,
        ActivityThread thread, String className, IBinder token,
        Application application, Object activityManager) {
    attachBaseContext(context);
    ......
}

完成了Service创建和ContextImpl的传入

猜你喜欢

转载自blog.csdn.net/www851903307/article/details/80763406