在日常开发过程中时常需要用到设计模式,但是设计模式有23种,如何将这些设计模式了然于胸并且能在实际开发过程中应用得得心应手呢?和我一起跟着《Android源码设计模式解析与实战》一书边学边应用吧!
设计模式系列文章
今天我们要讲的是代理模式(委托模式)
定义
为其他对象提供一种代理以控制对这个对象的访问
使用场景
- 当无法或不想直接访问某个对象或访问某个对象存在困难时,可以通过一个代理对象来间接访问,为了保证客户端使用的透明性,委托对象与代理对象需要实现相同的接口
使用例子
- Android源码中的ActivityManagerProxy代理ActivityManagerService类
实现
三大角色
- 抽象主题类:声明真实主题与代理的共同接口方法,该类既可以是一个抽象类也可以是一个接口
- 真实主题类:也称为被委托类或被代理类,该类定义了代理所表示的真实对象,由其执行具体的业务逻辑
- 代理类:也称为委托类或代理类,该类持有一个对真实主题类的引用,在其所实现的接口方法中调用真实主题类中相应的接口方法执行
实现的要点
- 代理模式从实现上分为静态代理和动态代理,这里我们主要关注静态代理
- 代理类和被代理类都要继承或实现相同的接口或方法
- 代理类通过被代理类的引用来调用具体的业务逻辑
实现方式
这里我们主要通过适配不同API版本下发送消息Notification来应用代理模式
抽象主题类
public abstract class Notify { protected Context context; protected NotificationManager notificationManager; protected NotificationCompat.Builder builder; public Notify(Context context) { this.context = context; notificationManager = (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE); builder = new NotificationCompat.Builder(context); builder.setSmallIcon(R.drawable.ic_launcher) .setContentIntent(PendingIntent.getActivity(context, 0, new Intent(context, NotifyActivity.class), PendingIntent.FLAG_UPDATE_CURRENT)); } /** * 发送一条通知 */ public abstract void send(); /** * 取消一条通知 */ public abstract void cancel();}复制代码
- 初始化了子类都会用到的NotificationManager和Builder,猜猜NotificationCompat类里面用了什么设计模式?
- 定义了2个公共的方法:send方法和cancel方法
真实主题类(被代理类)
- 常规的通知的构建
public class NotifyNormal extends Notify { public NotifyNormal(Context context) { super(context); } @Override public void send() { builder.setContent(new RemoteViews(context.getPackageName(), R.layout.layout_notify_normal)); Notification notification = builder.build(); notificationManager.notify(0, notification); } @Override public void cancel() { notificationManager.cancel(0); }}复制代码
- 大视图的通知的构建
public class NotifyBig extends Notify { public NotifyBig (Context context) { super(context); } @Override public void send() { builder.setContent(new RemoteViews(context.getPackageName(), R.layout.layout_notify_normal)); builder.setCustomBigContentView(new RemoteViews(context.getPackageName(), R.layout.layout_notify_normal)); Notification notification = builder.build(); notificationManager.notify(0, notification); } @Override public void cancel() { notificationManager.cancel(0); }}复制代码
- 浮动展示的通知的构建
public class NotifyHeadersUp extends Notify { public NotifyHeadersUp (Context context) { super(context); } @Override public void send() { builder.setContent(new RemoteViews(context.getPackageName(), R.layout.layout_notify_normal)); builder.setCustomBigContentView(new RemoteViews(context.getPackageName(), R.layout.layout_notify_normal)); builder.setCustomHeadsUpContentView(new RemoteViews(context.getPackageName(), R.layout.layout_notify_normal)); Notification notification = builder.build(); notificationManager.notify(0, notification); } @Override public void cancel() { notificationManager.cancel(0); }}复制代码
代理类
public class NotifyProxy extends Notify { private Notify notify; public NotifyProxy (Context context) { super(context); if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { notify = new NotifyHeadersUp(context); } else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) { notify = new NotifyBig(context); } else { notify = new NotifyNormal(context); } } @Override public void send() { notify.send(); } @Override public void cancel() { notify.cancel(); }}复制代码
调用
new NotifyProxy(MainActivity.this).send();复制代码
- 可见接口很简洁,通过代理模式,我们把复杂的判断和生成通知的逻辑都屏蔽了,这样代码更加清晰
补充
- 不知道大家看了上面的示例代码有什么想法?有没有可以优化的地方呢?
- 上面的示例中,3个Notify的子类中有很多重复的代码,有没有什么方法能进一步优化呢?
总结
- 代理模式应用广泛,会经常和其他设计模式结合使用
- 代理模式是细分化至很小的一种设计模式,几乎没有缺点
欢迎关注我的微信公众号,期待与你一起学习,一起交流,一起成长!