前言
设计模式在Android进阶中不可避免,对一个Android工程师来说,学习好设计模式会给我们带来很多好处:
- 方便阅读和理解Android源码
- 写出优质的代码,易于拓展和他人阅读
最近在看《Android源码设计模式解析与实战》,一直想深入了解Binder
机制,奈何愚笨,读完《Android开发艺术探索》中的第二章节之后仍感觉云里雾里,看见Binder
机制使用了代理模式,所以决定先学习代理模式。
目录
![](https://img.haomeiwen.com/i9271486/9361cd20b9134ac8.png)
一、定义
代理模式(Proxy Pattern)也称委托模式,我们引用《Android源码设计模式与实战》中的定义:
为其他对象提供一种代理以控制对这个对象的访问
二、使用场景
1. 举个栗子
定义好像说的不是那么明白?没关系,我们来举个例子:
我们称小王为著名演员,想要去国外,得去买飞机票吧,如果他自己去买票,就会被很多人认出,周围群众就会请求与他合影。为了不让自己暴露在大众面前,就让助理代替他去买票,他的助理就称为他的代理。我们用类图表示一下:
![](https://img.haomeiwen.com/i9271486/f7717f46ab7249ac.png)
著名演员小王就是这个
Actor
对象,助理就是Assistant
对象,Buyer
是我们买票要实现的接口,售票员就是Seller
对象,演员的粉丝就是Fans
,为了避免粉丝调用小王的合影方法takePhoto()
,小王选择让助理代替其去买票,只不过最终还是小王付钱买票罢了。
2. 思考
那么我们来思考一下使用场景:
当我们不想让别人直接访问我们的对象(因为这样可能会暴露我们对象,别人可以直接调用我们对象的某些方法,我们不想让别人调用),又或者别人不能直接访问的对象,需要一个代理去接触我们的对象。
三、代理分类
如果我们单纯的从code分类,代理模式可以区分为:
- 静态代理:上述的类图用代码实现后就是一个典型的静态代理,编译前我们就知道
Assistant
是我们的代理类,并且已经存在。 - 动态代理:动态代理与静态代理相反,编译前我们并不知道谁是我们的代理类,它是通过反射机制实现的,Java给我们提供了便捷的动态代理接口
InvocationHandler
,具体的使用可以查看Java动态代理。
那么从适用范围来讲,我们又可以区分为:
- 远程代理:为某个对象在不同的地址空间提供局部代理。使系统可以将Server部分隐藏,以便Client不需要考虑Server的存在。
- 虚拟代理:使用一个代理对象表示一个十分耗资源的对象,并在真正需要的时候创建。
- 保护代理:使用代理控制对原始对象的访问。该类型的代理常被用于原始对象有不同访问权限的情况。
- 智能引用:在访问原始对象时执行一些自己的附加操作,并对指向原始对象的引用计数。
四、实战
学完了代理模式之后,我对我的照片库PhotoPagerView进行了重构,PhotoPagerView代码并不复杂,只是因为公司的代码日常需要,所以就封装起来,主要功能就是加载多个Bitmap
通过ViewPager
展示出来。为了好(zhuang)看(bi),特意选择了QQ主题的图片预览,其实普通主题的代码特别简单,如果单纯的学习代理模式,就不需要看QQ主题的Dialog
.
![](https://img.haomeiwen.com/i9271486/d0b277eefd4c8928.gif)
1. 需求
- 显示显示大图的
Dialog
-
Dialog
暂时分为两种类型:普通类型(NormalPager
)和QQ风格类型(QQPager
) - 简化操作,不需要让使用者知道这两种具体的实现,只知道有这两种类型即可
2. 实现
为了讲解,细节都被省略了,具体可查看代码
第一步:创建IPhotoPager
的接口
public interface IPhotoPager {
void show();
void dismiss();
void setConfig(Config config);
/*
config 构成图片的一些参数
*/
class Config {
...
}
}
第二步:创建基础的BasePager
,供QQPager
和NormalPager
实现,这边只是简单的业务代码
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");
}
...
}
}
第三步:实现具体类型的IPhotoPager
,QQPager
和NormalPager
,QQPager
加入了更多的效果和弹幕功能,比较复杂,这里不作过多介绍,感兴趣可以看代码
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
五、总结
![](https://img.haomeiwen.com/i9271486/ad62f3874a1f731b.png)
本人水品有限,难免有误,如有错误,欢迎指出。
Over~
引用:
《Android源码设计模式》
《代理模式》
网友评论