Android学习Android专题

Android设计模式实战-代理模式

2019-04-15  本文已影响17人  九心_

前言

设计模式在Android进阶中不可避免,对一个Android工程师来说,学习好设计模式会给我们带来很多好处:

最近在看《Android源码设计模式解析与实战》,一直想深入了解Binder机制,奈何愚笨,读完《Android开发艺术探索》中的第二章节之后仍感觉云里雾里,看见Binder机制使用了代理模式,所以决定先学习代理模式。

目录

目录

一、定义

代理模式(Proxy Pattern)也称委托模式,我们引用《Android源码设计模式与实战》中的定义:

为其他对象提供一种代理以控制对这个对象的访问

二、使用场景

1. 举个栗子

定义好像说的不是那么明白?没关系,我们来举个例子:
我们称小王为著名演员,想要去国外,得去买飞机票吧,如果他自己去买票,就会被很多人认出,周围群众就会请求与他合影。为了不让自己暴露在大众面前,就让助理代替他去买票,他的助理就称为他的代理。我们用类图表示一下:

小王买票
著名演员小王就是这个Actor对象,助理就是Assistant对象,Buyer是我们买票要实现的接口,售票员就是Seller对象,演员的粉丝就是Fans,为了避免粉丝调用小王的合影方法takePhoto(),小王选择让助理代替其去买票,只不过最终还是小王付钱买票罢了。

2. 思考

那么我们来思考一下使用场景:
当我们不想让别人直接访问我们的对象(因为这样可能会暴露我们对象,别人可以直接调用我们对象的某些方法,我们不想让别人调用),又或者别人不能直接访问的对象,需要一个代理去接触我们的对象。

三、代理分类

如果我们单纯的从code分类,代理模式可以区分为:

那么从适用范围来讲,我们又可以区分为:

四、实战

学完了代理模式之后,我对我的照片库PhotoPagerView进行了重构,PhotoPagerView代码并不复杂,只是因为公司的代码日常需要,所以就封装起来,主要功能就是加载多个Bitmap通过ViewPager展示出来。为了好(zhuang)看(bi),特意选择了QQ主题的图片预览,其实普通主题的代码特别简单,如果单纯的学习代理模式,就不需要看QQ主题的Dialog.

qq主题

1. 需求

2. 实现

为了讲解,细节都被省略了,具体可查看代码
第一步:创建IPhotoPager的接口

public interface IPhotoPager {
    void show();
    void dismiss();
    void setConfig(Config config);

    /*
        config 构成图片的一些参数
     */
    class Config {
        ...
    }
}

第二步:创建基础的BasePager,供QQPagerNormalPager实现,这边只是简单的业务代码

public abstract class BasePager extends Dialog
        implements ViewPager.OnPageChangeListener,IPhotoPager {

    protected Context mContext;
    // all base info
    private IPhotoPager.Config mConfig;

    ... 

    public BasePager(@NonNull Context context) {
        this(context, R.style.Dialog);
    }

    public BasePager(@NonNull Context context, int themeResId) {
        super(context, themeResId);

        mContext = context;
    }

    @Override
    public void setConfig(Config config) {
        this.mConfig = config;
        initParams();
    }

    /*
        init parameter
     */
    private void initParams() {
         ...
    }

    @Override
    public void show() {
        if(bitmaps == null || bitmaps.size() == 0){
            throw new RuntimeException("bitmaps can't be null");
        }

       ...
    }
}

第三步:实现具体类型的IPhotoPagerQQPagerNormalPagerQQPager加入了更多的效果和弹幕功能,比较复杂,这里不作过多介绍,感兴趣可以看代码

public class NormalPager extends BasePager
    implements View.OnClickListener{
    private String TAG = "NormalPager";

    private MyViewPager mPhotoPager; // 继承自ViewPager,仅仅捕获异常
    private ImageView mDelete;
    private TextView mPosition;
    private ImageView mBack;

    private PhotoPagerAdapter mAdapter;

    public NormalPager(@NonNull Context context) {
        super(context);
    }

    public NormalPager(@NonNull Context context, int themeResId) {
        super(context, themeResId);
    }

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        View root = LayoutInflater.from(mContext).inflate(R.layout.layout_normal_pager, null);
        setContentView(root);
        initWidget(root);
    }

    private void initWidget(View root){
        ...
        // 初始化布局
    }


    @Override
    public void onClick(View v) {
        if (v.getId() == R.id.iv_back) {
            dismiss();
        } else {
            deleteCurrentPosition();
        }
    }

    private void deleteCurrentPosition() {
        // 省略具体实现 删除当前部分触发
        ...
    }

    @Override
    public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
        Log.e(TAG,"pos:"+position+",offset:"+positionOffset);
    }

    @Override
    public void onPageSelected(int position) {
        mPosition.setText(String.format(Locale.getDefault(), "%d/%d", position + 1, bitmaps.size()));
        curPosition = position;
    }
}

第四步:设置代理,通过类型创建不同主题的Pager

public class PhotoPagerViewProxy implements IPhotoPager {
    public static final int TYPE_NORMAL = 1;
    public static final int TYPE_QQ = 2;
    public static final int TYPE_WE_CHAT = 3;

    public static final int ANIMATION_SCALE_ALPHA = 1;
    public static final int ANIMATION_TRANSLATION = 2;

    private IPhotoPager photoPageView;

    private PhotoPagerViewProxy(Context context, int type, Config config) {
        switch (type) {
            case TYPE_QQ:
                photoPageView = new QQPager(context,R.style.Dialog);
                break;
            case TYPE_WE_CHAT:
                break;
            default:
                photoPageView = new NormalPager(context, R.style.Dialog);
                break;
        }
        setConfig(config);
    }

    @Override
    public void show() {
        photoPageView.show();
    }

    @Override
    public void dismiss() {
        photoPageView.dismiss();
    }

    @Override
    public void setConfig(Config config) {
        photoPageView.setConfig(config);
    }

    public static class Builder {
        private Activity context;
        private IPhotoPager.Config config;
        private int type;

        public Builder(Activity context, int type) {
            this.context = context;
            this.config = new IPhotoPager.Config();
            this.type = type;
        }

        public Builder(Activity context) {
            // default type is TYPE_NORMAL
            this(context, TYPE_NORMAL);
        }

       ... // 具体设置参数都省略

        public PhotoPagerViewProxy create() {
            return new PhotoPagerViewProxy(context, type, config);
        }
    }
}

大功告成,具体代码地址:PhotoPagerView

五、总结

总结

本人水品有限,难免有误,如有错误,欢迎指出。
Over~
引用:

《Android源码设计模式》
《代理模式》

上一篇 下一篇

猜你喜欢

热点阅读