Android中的设计模式初级篇

10 篇文章 0 订阅

前言

设计模式伴随着我们写代码的一生,总是看了又忘,忘了又看,然后依次循环。在这里用实例或者工作心得记录下设计模式的使用,23种太多,本篇只记录用过的模式,不作过多扩展,后续会针对各个设计模式详细分析。

设计模式分类

创建型模式

对象的创建会消耗掉系统的很多资源,所以单独对对象的创建进行研究,从而能够高效地创建对象就是创建型模式要探讨的问题。

结构型模式

在解决了对象的创建问题之后,对象的组成以及对象之间的依赖关系就成了开发人员关注的焦点,因为如何设计对象的结构、继承和依赖关系会影响到后续程序的维护性、代码的健壮性、耦合性等,对象结构的设计很容易体现出设计人员水平的高低。

行为型模式

在对象的结构和对象的创建问题都解决了之后,就剩下对象的行为问题了,如果对象的行为设计的好,那么对象的行为就会更清晰,它们之间的协作效率就会提高。

Android源码中设计模式

1.单例

android.app.AppComponentFactory中通过class.newInstance创建,保证一个app只有一个Application实例。

PS:注意class.newInstance()被调用前必须保证类已经被ClassLoader加载,其实本篇不想作这些扩展说明,还是说一下吧。

public class AppComponentFactory {

    /**
     * Allows application to override the creation of the application object. This can be used to
     * perform things such as dependency injection or class loader changes to these
     * classes.
     * <p>
     * This method is only intended to provide a hook for instantiation. It does not provide
     * earlier access to the Application object. The returned object will not be initialized
     * as a Context yet and should not be used to interact with other android APIs.
     *
     * @param cl        The default classloader to use for instantiation.
     * @param className The class to be instantiated.
     */
    public @NonNull Application instantiateApplication(@NonNull ClassLoader cl,
            @NonNull String className)
            throws InstantiationException, IllegalAccessException, ClassNotFoundException {
        return (Application) cl.loadClass(className).newInstance();
    }
}

2.建造者模式

使用多个简单的对象一步一步构建成一个复杂的对象,它提供了一种创建对象的方式,比如AlertDialog,其中setTitle方法返回this,是建造者典型的特征。

     public Builder setTitle(CharSequence title) {
            P.mTitle = title;
            return this;
     }        

     //弹框
     new AlertDialog.Builder(getActivity())
                .setTitle("标题")
                .setMessage(msg)
                .setNegativeButton("取消", new DialogInterface.OnClickListener() {
                    @Override
                    public void onClick(DialogInterface dialog, int which) {
                      
                    }
                })
                .setPositiveButton("确定", null)
                .setCancelable(false)
                .show();

3.原型模式

将一个对象进行拷贝,创建重复的对象,一般都是使用clone()方法,对象深浅拷贝这里暂不探究。Android中Intent中提供了clone()方法,有时候Intent很多参数相同,同时跳转2个或多个页面时,Intent加入相同参数后就可以clone()出另外一个Intent,分别用于差异化参数跳转。

public class Intent implements Parcelable, Cloneable {
    @Override
    public Object clone() {
      return new Intent(this);
    }
}

//测试伪代码
private void test() {
        Intent intent = new Intent();
        intent.putExtra("param_1", "1");
        intent.putExtra("param_2", "2");
        startActivity(intent);

        Intent intent2 = (Intent)intent.clone();
        intent2.putExtra("param_3", "3");
        startActivity(intent2);
}

4.工厂方法模式

创建对象时不会对调用者暴露创建逻辑,通过一个共同的接口来指向新创建的对象。android中通过getSystemService()方法传入不同参数获取对应xxxManager。

        //WindowManager
        WindowManager windowManager = (WindowManager) getActivity()
                .getSystemService(Service.WINDOW_SERVICE);

        //SearchManager
        SearchManager searchManager = (SearchManager) getActivity()
                .getSystemService(Service.SEARCH_SERVICE);

4.抽象工厂模式

多个接口分别负责创建多个相关对象的工厂,调用时根据名称获取一个工厂,获取某个工厂后,后续操作同工厂方法模式,伪代码如下。

        A工厂 =  总厂("A工厂");
        A包 = A工厂.("A包");

        B工厂 =  总厂("B工厂");
        B包 = B工厂.("B包");

5.简单工厂模式

无接口,直接通过静态方法提供功能,android中比如BitmapFactory。

BitmapFactory.decodeFile();
BitmapFactory.decodeResource();

6.适配器模式

两个不兼容的接口之间的桥梁。android中平时用的最多是RecyclerView.Adapter,Adapter是Item布局、列表数据间的桥梁,通过不同的Adapter,我们能够实现不同的布局。

public abstract static class Adapter<VH extends ViewHolder> {
  ...
  public abstract VH onCreateViewHolder(@NonNull ViewGroup parent, int viewType);
  public abstract void onBindViewHolder(@NonNull VH holder, int position);
  ...
}

7.观察者模式

定义对象间的一种一个对多的依赖关系,当一个对象的状态发送改变时,所以依赖于它的对象都得到通知并被自动更新。android中当RecyclerView列表数据变更时,需要调用Adapter.notifyDataSetChanged()通知列表刷新。

RecyclerView.setAdapterInternal()方法中可以清楚看到registerAdapterDataObserver / unregisterAdapterDataObserver 方法用来订阅与取消订阅。

//观察者   
private final RecyclerViewDataObserver mObserver = new RecyclerViewDataObserver();

//RecyclerViewDataObserver
private class RecyclerViewDataObserver extends AdapterDataObserver {
        RecyclerViewDataObserver() {
        }

        @Override
        public void onChanged() {
            assertNotInLayoutOrScroll(null);
            mState.mStructureChanged = true;

            processDataSetCompletelyChanged(true);
            if (!mAdapterHelper.hasPendingUpdates()) {
                //刷新页面
                requestLayout();
            }
        }
}

//Adapter
public abstract static class Adapter<VH extends ViewHolder> {
        //被观察者
        private final AdapterDataObservable mObservable = new AdapterDataObservable();

        //注册观察者
        public void registerAdapterDataObserver(@NonNull AdapterDataObserver observer) {
            mObservable.registerObserver(observer);
        }

        //取消注册观察者
        public void unregisterAdapterDataObserver(@NonNull AdapterDataObserver observer) {
            mObservable.unregisterObserver(observer);
        }

       //notifyDataSetChanged
       public final void notifyDataSetChanged() {
            mObservable.notifyChanged();
       }
}

//setAdapterInternal
private void setAdapterInternal(@Nullable Adapter adapter, boolean compatibleWithPrevious,
            boolean removeAndRecycleViews) {
        //...
        final Adapter oldAdapter = mAdapter;
        mAdapter = adapter;
        if (adapter != null) {
            //被观察者注册观察者
            adapter.registerAdapterDataObserver(mObserver);
            adapter.onAttachedToRecyclerView(this);
        }
        //...
}

 //被观察者对象
static class AdapterDataObservable extends Observable<AdapterDataObserver> {
        public boolean hasObservers() {
            return !mObservers.isEmpty();
        }

        public void notifyChanged() {

            for (int i = mObservers.size() - 1; i >= 0; i--) {
                mObservers.get(i).onChanged();
            }
        }
}

8.策略模式

一个类的行为或其算法可以在运行时更改,定义一系列的算法,把每一个算法封装起来,并且使它们可相互替换。策略模式模式使得算法可独立于使用它的客户而独立变化。android中如RecyclerView.setLayoutManager(),可以是线性、网格、交错,还有图片缓存策略如磁盘缓存、内存缓存等。

RecyclerView.setLayoutManager(new LinearLayoutManager());
RecyclerView.setLayoutManager(new GridLayoutManager());
RecyclerView.setLayoutManager(new StaggeredGridLayoutManager());

9.装饰模式

动态地给一个对象添加一些额外的职责。就增加功能来说,装饰模式相比生成子类更为灵。android中ContextWrapper就是具体的装饰角色,Context类在这里就充当了抽象组件的角色,ContextImpl类则是具体的组件,通过扩展ContextWrapper增加不同的功能。

public class ContextWrapper extends Context {//Context包装类
   Context mBase;//Context是一个abstract修饰的抽象类

   public ContextWrapper(Context base) {//这里实际上是Context的实现类ContextImpl
       mBase = base;
   }

   @Override
   public void startActivity(Intent intent) {
      mBase.startActivity(intent);//调用ContextImpl的startActivity()方法
   }

   //其他代码略
}

10.迭代器模式

顺序访问集合对象的元素,不需要知道集合对象的内部细节。常用的Map、List等都支持迭代器模式遍历,Android中使用数据库查询时返回的Cursor游标对象,也是使用了迭代器模式来实现。

Cursor cursor = database.rawQuery("sql", new String[]{"name"});
if (cursor != null) {
    while (cursor.moveToNext()) {
        cursor.getInt(0);
        cursor.getString(1);
    }
}

11.责任链模式

一个行为或者操作沿着一条“链”传递,直到该“链”上的某个处理者处理或者消费它为止。android中最直接的体现就是触摸事件分发机制,比如一个Activity,页面包含一个ViewGroup,ViewGroup中包含一个View,页面中元素无任何点击、触摸事件,分别重写他们的dispatchTouchEvent、onInterceptTouchEvent、onTouchEvent,我们触摸View,日志输出如下,事件一路传递下来,又一路回溯回去,最终事件被Activity的onTouchEvent消费了后续的UP事件。

E/Activity: =====dispatchTouchEvent=====ACTION_DOWN
E/ViewGroup: dispatchTouchEvent: ======ACTION_DOWN
             onInterceptTouchEvent: ======ACTION_DOWN
E/View: dispatchTouchEvent: ======ACTION_DOWN
        onTouchEvent: ======ACTION_DOWN
E/ViewGroup: onTouchEvent: ======ACTION_DOWN
E/Activity: =====onTouchEvent=====ACTION_DOWN
            =====dispatchTouchEvent=====ACTION_UP
            =====onTouchEvent=====ACTION_UP

在View的onTouchEvent返回true日志如下:

E/Activity: =====dispatchTouchEvent=====ACTION_DOWN
E/ViewGroup: dispatchTouchEvent: ======ACTION_DOWN
             onInterceptTouchEvent: ======ACTION_DOWN
E/View: dispatchTouchEvent: ======ACTION_DOWN
        onTouchEvent: ======ACTION_DOWN
E/MainActivity: =====dispatchTouchEvent=====ACTION_UP
E/ViewGroup: dispatchTouchEvent: ======ACTION_UP
             onInterceptTouchEvent: ======ACTION_UP
E/View: dispatchTouchEvent: ======ACTION_UP
        onTouchEvent: ======ACTION_UP

12.代理模式

为其他对象提供一种代理以控制这个对象的访问。android中的Retrofit2框架就是通过动态代理生成请求对象,动态代理本质上是生成大量样板代码的过程,相比于静态代理,动态代理可以减少编写代理类(比如XXXImpl)的工作量。

public <T> T create(final Class<T> service) {
    Utils.validateServiceInterface(service);
    if (validateEagerly) {
      eagerlyValidateMethods(service);
    }
    return (T) Proxy.newProxyInstance(service.getClassLoader(), new Class<?>[] { service },
        new InvocationHandler() {
          private final Platform platform = Platform.get();
          private final Object[] emptyArgs = new Object[0];

          @Override public @Nullable Object invoke(Object proxy, Method method,
              @Nullable Object[] args) throws Throwable {
            // If the method is a method from Object then defer to normal invocation.
            if (method.getDeclaringClass() == Object.class) {
              return method.invoke(this, args);
            }
            if (platform.isDefaultMethod(method)) {
              return platform.invokeDefaultMethod(method, service, proxy, args);
            }
            return loadServiceMethod(method).invoke(args != null ? args : emptyArgs);
          }
        });
  }

13.外观模式

外观模式隐藏系统的复杂性,并向客户端提供了一个客户端可以访问系统的接口。这

在android中,Context就用了外观模式,Context可以打开Activity,可打开Service,广播等等。

14.享元模式

使用共享对象可有效地支持大量的细粒度的对象,享元模式尝试重用现有的同类对象,如果未找到匹配的对象,则创建新对象。在android中,获取Message,可以通过Message.obtain()去获取Message,源码可以看到先去池中找,有则用池中的Message,无则新创建。

public static Message obtain() {
        synchronized (sPoolSync) {
            if (sPool != null) {
                Message m = sPool;
                sPool = m.next;
                m.next = null;
                m.flags = 0; // clear in-use flag
                sPoolSize--;
                return m;
            }
        }
        return new Message();
    }

15.桥接模式

用一个作为桥接的接口,使得实体类的功能独立于接口实现类。比如一个USB线左边可以插不同的手机,右边可以插不同的电源。

public abstract class Shape {

   //实现了一些方法   

   //桥接方法,子类自行实现画什么内容
   public abstract void draw();  
}

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值