Android装饰者模式介绍(结合源码分析)

装饰者模式介绍

装饰模式(Decoraor pattern)也称包装模式(Wrapper),结构型设计模式之一,其使用一种对客户端透明的方式来动态的扩展对象的功能,同时也是继承关系的一种替代方案之一。比如人穿衣服,人可以穿各式各样的衣服,但是不管你穿什么衣服,人的本质是不变得,衣服只是人的一层遮掩物而已,这就是装饰者模式。

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

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

装饰模式的举例

抽象组件类

public abstract class Component {
	public abstract void operate();
}

组件具体实现类:这里就是我们所装饰的东西,比如人,此时这个人还没穿衣服

public class ConcrecteCompont extends Component{
	@Override
	public void operate() {
		// TODO Auto-generated method stub
		System.out.println("具体对象被调用");
	}
}

抽象装饰者:这是传递一个引用,目的是为了调用方法,这里当相于包装,把人包装起来。

public abstract class Decorateor extends Component{
	private Component compont;
	public  Decorateor(Component com) {
		// TODO Auto-generated constructor stub
		compont = com;
	}
	@Override
	public void operate() {
		// TODO Auto-generated method stub
		compont.operate();
	}
}

装饰着具体实现类:这里的operate1()相当于衣服

public class ConcrecteDecorateor extends Decorateor{
	public ConcrecteDecorateor(Component com) {
		super(com);
	}
	@Override
	public void operate() {
		// TODO Auto-generated method stub
		super.operate();
		operate1();
	}
	private void operate1() {
		// TODO Auto-generated method stub
		System.out.println("装饰的方法实现了");
	}
}

然后在客户端实现:

public class Client {

	public static void main(String[] args) {
		// TODO Auto-generated method stub
		Component component = new ConcrecteCompont();
		Decorateor decorateor = new ConcrecteDecorateor(component);
		decorateor.operate();
	}
}

在装饰模式结构图中包含如下几个角色:

  • Component(抽象构件):它是具体构件和抽象装饰类的共同父类,声明了在具体构件中实现的业务方法,它的引入可以使客户端以一致的方式处理未被装饰的对象以及装饰之后的对象,实现客户端的透明操作。

  • Concrete Component(具体构件):它是抽象构件类的子类,用于定义具体的构件对象,实现了在抽象构件中声明的方法,装饰器可以给它增加额外的职责(方法)。

  • Decorator(抽象装饰类):它也是抽象构件类的子类,抽象装饰类不一定是抽象方法。用于给具体构件增加职责,但是具体职责在其子类中实现。它维护一个指向抽象构件对象的引用,通过该引用可以调用装饰之前构件对象的方法,并通过其子类扩展该方法,以达到装饰的目的。

  • Concrete Decorator(具体装饰类):它是抽象装饰类的子类,负责向构件添加新的职责。每一个具体装饰类都定义了一些新的行为,它可以调用在抽象装饰类中定义的方法,并可以增加新的方法用以扩充对象的行为。

装饰者在Android源码中的实现:

我们所熟悉的Content类是个抽象类,其实就是装饰者中的Compont组件。在其内部定义了大量的抽象方法,比如startActivity

public abstract class Context {
      ....
      public abstract void startActivity(@RequiresPermission Intent intent);
      public abstract void sendBroadcast(@RequiresPermission Intent intent);
      .....

真正是实现是在ContextImpl类中实现的,其类继承了Context并且实现了Context的的抽象方法,相当于组件的实现类

比如:

public final class ContextImpl extends Context {
@Override
    public void startActivityAsUser(Intent intent, Bundle options, UserHandle user) {
        try {
            ActivityManagerNative.getDefault().startActivityAsUser(
                mMainThread.getApplicationThread(), getBasePackageName(), intent,
                intent.resolveTypeIfNeeded(getContentResolver()),
                null, null, 0, Intent.FLAG_ACTIVITY_NEW_TASK, null, options,
                user.getIdentifier());
        } catch (RemoteException re) {
        }
    }

    @Override
    public void startActivities(Intent[] intents) {
        warnIfCallingFromSystemProcess();
        startActivities(intents, null);
    }

在来看看activity:

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

public class ContextWrapper extends Context {
    Context mBase;

    public ContextWrapper(Context base) {
        mBase = base;
    }
    @Override
    public void startActivities(Intent[] intents) {
        mBase.startActivities(intents);
    }





public class ContextWrapper extends Context {

其实ContextThemeWrapper就是装饰者,在其中保存了一个content的引用。就调用content的startActivity方法。

那么问题来了,context中的方法都是由contextImpl实现了,那contextImpl又是子啊何时何地创建的呢?我们都知道java的入口函数都是在main方法,我们的Android都是从onCreat方法开始的。但是main方法在android确实存在,在Android源码的应用级别的代码里匿藏在ActivityThread类中

public final class ActivityThread {
  public static void main(String[] args) {
        Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "ActivityThreadMain");
        SamplingProfilerIntegration.start();

        // CloseGuard defaults to true and can be quite spammy.  We
        // disable it here, but selectively enable it later (via
        // StrictMode) on debug builds, but using DropBox, not logs.
        CloseGuard.setEnabled(false);

        Environment.initForCurrentUser();

        // Set the reporter for event logging in libcore
        EventLogger.setReporter(new EventLoggingReporter());

        AndroidKeyStoreProvider.install();

        // Make sure TrustedCertificateStore looks in the right place for CA certificates
        final File configDir = Environment.getUserConfigDirectory(UserHandle.myUserId());
        TrustedCertificateStore.setDefaultUserDirectory(configDir);

        Process.setArgV0("<pre-initialized>");

        Looper.prepareMainLooper();

        ActivityThread thread = new ActivityThread();
        thread.attach(false);

        if (sMainThreadHandler == null) {
            sMainThreadHandler = thread.getHandler();
        }

        if (false) {
            Looper.myLooper().setMessageLogging(new
                    LogPrinter(Log.DEBUG, "ActivityThread"));
        }

        // End of event ActivityThreadMain.
        Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
        Looper.loop();

        throw new RuntimeException("Main thread loop unexpectedly exited");
    }
在main中构造了一个ActivityThread对象,在通过调用getHandler为sMainThreadHandler赋值,按Ctrl+左键,方法getHandler返回的是一个H对象

public final class ActivityThread {
    private class H extends Handler {  
        public void handleMessage(Message msg) {
            if (DEBUG_MESSAGES) Slog.v(TAG, ">>> handling: " + codeToString(msg.what));
            switch (msg.what) {
                case LAUNCH_ACTIVITY: {
                    Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "activityStart");
                    final ActivityClientRecord r = (ActivityClientRecord) msg.obj;

                    r.packageInfo = getPackageInfoNoCheck(
                            r.activityInfo.applicationInfo, r.compatInfo);
                    handleLaunchActivity(r, null);
                    Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
                } break;
点击handleLaunchActivity(r, null);
private void handleLaunchActivity(ActivityClientRecord r, Intent customIntent) {
        // If we are getting ready to gc after going to the background, well
        // we are back active so skip it.
        unscheduleGcIdler();
        mSomeActivitiesChanged = true;

        if (r.profilerInfo != null) {
            mProfiler.setProfiler(r.profilerInfo);
            mProfiler.startProfiling();
        }

        // Make sure we are running with the most recent config.
        handleConfigurationChanged(null, null);

        if (localLOGV) Slog.v(
            TAG, "Handling launch of " + r);

        // Initialize before creating the activity
        WindowManagerGlobal.initialize();

        Activity a = performLaunchActivity(r, customIntent);

一般来说如果看源码出现perform**()之类的方法都是蛮关键的,点进去在看下

private Activity performLaunchActivity(ActivityClientRecord r, Intent customIntent) {
  try {
            Application app = r.packageInfo.makeApplication(false, mInstrumentation);

            if (localLOGV) Slog.v(TAG, "Performing launch of " + r);
            if (localLOGV) Slog.v(
                    TAG, r + ": app=" + app
                    + ", appName=" + app.getPackageName()
                    + ", pkg=" + r.packageInfo.getPackageName()
                    + ", comp=" + r.intent.getComponent().toShortString()
                    + ", dir=" + r.packageInfo.getAppDir());

            if (activity != null) {
                Context appContext = createBaseContextForActivity(r, activity);
                CharSequence title = r.activityInfo.loadLabel(appContext.getPackageManager());
                Configuration config = new Configuration(mCompatConfiguration);
                if (DEBUG_CONFIGURATION) Slog.v(TAG, "Launching activity "
                        + r.activityInfo.name + " with config " + config);
                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);

                if (customIntent != null) {
                    activity.mIntent = customIntent;
                }

createBaseContextForActivity(r, activity),顾名思义,创建一个activity的context,

 private Context createBaseContextForActivity(ActivityClientRecord r, final Activity activity) {
        int displayId = Display.DEFAULT_DISPLAY;
        try {
            displayId = ActivityManagerNative.getDefault().getActivityDisplayId(r.token);
        } catch (RemoteException e) {
        }

        ContextImpl appContext = ContextImpl.createActivityContext(
                this, r.packageInfo, displayId, r.overrideConfig);
        appContext.setOuterContext(activity);
        Context baseContext = appContext;

于是乎ContextImpl就被创建出来了。

到这里,装饰者的条件就全部有了,Application的关联context的套路都是一样的,,还有service。

有个问题思考下,一个应用中有几个context呢?一个application一个+activity的个数+service的个数。那么其他的2个Broadcast和Contentprovides没有保存context嘛?Broadcast并非直接或间接继承与context,但是每次接受广播的时候,onReceiver都会接受到一个context对象,改context对象是ReceiverRestritedContext的一个实例,而在ContentProvides中你可以getContent获得一个context对象。这些context都市直接或间接来自于Application,activity,service。

在开发中,当你无法确定是否造成长引用刀子内存泄露时就使用Application的context对象,因为这个context是存在于整个生命周期内的

模式应用

public class MainActivity extends Activity {
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        inintDatas();
        initViews();
        initEvents();
    }
    private void initEvents() {
    }
    private void initViews() {
    }
    private void inintDatas() {
    }
}

其实上面的一些新增方法就类似于装饰模式中装饰着的职责,只不过我们没有保持对组件的引用

PS:注意,装饰者模式和代理模式有点相似,不要搞混淆。




  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Android 源码中,适配器模式被广泛应用于 UI 层,特别是 ListView 和 RecyclerView 这样的列表控件中。 举例来说,ListView 和 RecyclerView 的数据源都是一个 Adapter 对象,该对象负责将数据绑定到列表中的视图上。Adapter 接口定义了一些方法,例如 getCount()、getItem() 和 getView() 等,用于获取数据总数、单个数据项和显示数据项对应的 View 视图。 具体来说,ListView 和 RecyclerView 会调用 Adapter 的 getCount() 方法获取数据总数,在绘制列表时会调用 getView() 方法获取每个数据项对应的 View 视图,并将数据绑定到视图上。如果数据源发生变化(例如添加或删除数据项),则需要调用 Adapter 的 notifyDataSetChanged() 方法通知列表控件重新绘制。 另外,RecyclerView 还引入了更高级的适配器模式,即 ViewHolder 模式。ViewHolder 模式可以减少 findViewById() 方法的调用次数,从而提高列表绘制的性能。在 ViewHolder 模式中,Adapter 会持有一个 ViewHolder 对象,该对象用于存储数据项的视图和相关信息。RecyclerView 在绘制列表时,会先检查 ViewHolder 是否已创建,如果已创建则直接使用该 ViewHolder 对象,否则会创建一个新的 ViewHolder 对象并绑定到数据项上。 因此,适配器模式在 Android 源码中起到了非常重要的作用,它使得列表控件的数据源和视图分离,提高了代码的可维护性和可重用性。同时,ViewHolder 模式更是提高了列表绘制的性能,优化了用户体验。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值