当前位置:主页 > 论文百科 > 英文数据库 >

设计模式解析之代理模式

发布时间:2017-01-11 15:12

  本文关键词:设计模式解析,由笔耕文化传播整理发布。


设计模式解析之代理模式

设计模式-代理模式代理模式的概念  代理模式(proxy pattern)是一种结构型的设计模式,代理模式在程序开发中的运用非常广泛。简单地描述代理模式就是:为其他对象(被代理对象)提供一种代理以控制对原有对象的操作。实际的行为是由被代理对象完成的。

  代理模式可以分为两部分,静态代理 和 动态代理,它们的区别将在下面详细介绍。

角色介绍:  Suject: 抽象主题类

  该类的主要职责是申明真是主题与代理的共同接口方法,该类既可以是个抽象类也可以是个接口(具有抽象方法)。

  RealSubject: 真实主题类

  该类也称为委托类或者被代理类,改类定义了代理所表示的真是对象(也就是实现了抽象方法),由其执行具体的业务逻辑。

  ProxySubject:代理类

  这个类的对象持有一个对真实主题的引用,在这个类所实现的接口方法中调用真实主题类中相应的方法执行,这样就实现了代理的目的。

  Client:客户类

  也就是使用代理类的类型,客户类通过代理类间接地调用了真实主题类中定义的方法。

代理模式的实现简单的例子针对,上方的角色介绍,举一个简单的例子:在现实的世界中,打公司一般有,原告 和原告的代理律师这样两个角色,他们要做的事情是 辩护。于是,我们可以实现以下几个类。

抽象主题类:interface IDefender,这个接口中有个 抽象方法 abstract public void defend(); 表示辩护这个行为。

[code]public interface IDefender { abstract public void defend();//辩护行为 }

真实主题类: class Accuser,实现IDefender这个接口,具有具体的逻辑行为

[code] public class Accuser implements IDefender { @Override public void defend() { System.out.println("被告严重侵犯了公民的人身自由权...哔哩哔哩"); } }

代理类:AccuserProxy 类,原告请了个代理律师帮助它打官司,也就是AccuserProxy,由代理律师控制原告的表现

[code]public class AccuserProxy implements IDefender { //持有被代理类的引用 private IDefender iDefend; public AccuserProxy(IDefender iDefend) { this.iDefend = iDefend; } @Override public void defend() { beforeDefend(); // 被代理类的行为 iDefend.defend(); afterDefend(); } //修饰的方法 private void beforeDefend(){ System.out.print("我是原告律师,以下是我方辩词"); } //修饰的方法 private void afterDefend(){ System.out.print("辩护完毕"); } }

客户端:Client类,使用代理类的角色

[code]public class Client { public static void main(String[] args) { Accuser accuser = new Accuser(); accuser.defend();//此时输出 被告严重侵犯了公民的人身自由权...哔哩哔哩 AccuserProxy accuserProxy = new AccuserProxy(accuser); accuserProxy.defend(); // 输出:我是原告律师,以下是我方辩词,被告严重侵犯了公民的人身自由权...哔哩哔哩,辩护完毕 ///////////////////////////////////////////////////// // 因为,我们的代理类和被代理类 实现的是同一接口,如果将引用类型 写成IDfender, // 那么在调用 defend(),方法的使用 客户完全感觉不到被代理类的存在,当然因为我们这里的 // 被代理类是通过构造函数传进去的,软件开发中,有时候直接在被代理类中实例化代理类,这样使用起来就更完美了。 IDefender accuser2 = new Accuser(); IDefender accuser2Proxy = new AccuserProxy(accuser2); accuser2.defend(); } }

  代理模式的运用符合开闭原则的定义,软件中的对象(类、模块、函数)应该对于拓展是开发的,对于修改是封闭的。我们不需要修改被代理类 (Accuser),使用代理模式就可以实现对原有功能的加强。以上代码只是一个简答的运用场景,现实开发中代理模式的运用非常广泛,它可以解决多方面的问题。

Androd 开发中的运用例子  Android API的版本迭代很快,在每次的版本更新中 通常会加强一些原有的功能,对原有的类会增加新的接口,而每个版本能够调用的API 可能会都不同,比如 状态栏 Notification 。

Notfification可以分为4类,一类是正常视图,也就是我们通常在状态栏看到的 高度为 64dp 的长条状通知视图;一类是在 API16 中引入的以 Style 方式展示的 MediaStyle、InboxStyle、BigTextStyle 和 BigPictureStyle 四种Notification 风格样式;一类也是在 API16 中引入的可以将通知视图显示为256dp 高度大视图的 bingContentView;最后一类是在 L 中引入的 headsUpContentVIew

  现在,我们的 App需要根据不同的版本实例化不同 Notification 显示不同的视图,在高版本显示的视图当然就更丰富,低版本更单调。如果你直接在 Activity 中判断版本,加上一坨的 switch 或者 if else 语句当然也是可以的。但是,我们现在来看一下 运用设计模式的思想,如何将代码抽离,对于客户端来说(Activity or Fragment),不应该关心这些细节。

以下的代码来自《Android源码设计模式解析与实战》一书。

抽象主题类: Notify类, Notify抽象类 声明了 NotificationManager 和NotificatoinCompat.Builder 2个成员变量来处理和通知的一些逻辑。在构造函数中初始化所有子类都会调用的逻辑方法。

[code]public abstract class Notify { protected Context context; protected NotificationManager nm; protected NotificationCompat.Builder builder; public Notify(Context context){ this.context = context; nm = (NotificationManager)context.getSystemService(Context.NOTIFICATION_SERVICE); builder = new NotificationCompat.Builder(context); builder.setSmallIcon(R.mipmap.ic_launcher) .setContentIntent(PendingIntent.getActivities( context, 0, new Intent[]{new Intent(context, NotifyActivity.class)}, PendingIntent.FLAG_UPDATE_CURRENT)); } /** * 发送一条通知 */ public abstract void send(); /** * 取消一条通知 */ public abstract void cancel(); }

真实主题类:NotifyNormal ,继承抽象主题类,简单重写抽象方法

[code]public class NotifyNormal extends Notify{ public NotifyNormal(Context context) { super(context); } @Override public void send() { Notification n = builder.build(); n.contentView = new RemoteViews(context.getPackageName(), R.layout.remote_notify_proxy_normal); nm.notify(0,n); } @Override public void cancel() { nm.cancel(0); } }

真实主题类 : 与NormalNotify的不同在于 还实现了bigContentView 的初始化,,这是在 API 16以上才能调用的

[code]public class NotifyBig extends Notify{ public NotifyBig(Context context) { super(context); } @TargetApi(Build.VERSION_CODES.JELLY_BEAN) @Override public void send() { Notification n = builder.build(); n.contentView = new RemoteViews(context.getPackageName(), R.layout.remote_notify_proxy_normal); n.bigContentView = new RemoteViews(context.getPackageName(),R.layout.remote_notify_proxy_big); nm.notify(0,n); } @Override public void cancel() { nm.cancel(0); } }

  源码中还有个 NotifyHeadUp 类,它的唯一区别就是 在bigContentVie 的基础上还能实现 Notification 的 headsUpContentView ,这个 View 是在 API 20以上 才能使用的,当我们的 App 以全屏的方式展开的时候如果收到了通知,这个 View 就会浮动展示于屏幕顶部。

  代理类: NotifyProxy ,持有被代理类对象,在这个示例中,我们根据不同的运行时环境 API 实例化不同的 被代理类对象。

[code]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 NotifyHeadUp(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(); } }

  客户端类:也就是我们的Activity,在 Activity 中,我们直接将 Context 传入,代理类会帮我们实例化合适的被代理对象。

[code]new NotifyProxy(NotifyActivity.this).send();

  在这个实例中,我们通过代理模式 ,使用一个代理类来针对不同的运行时系统版本,实例化不同的 Notificaition 的子类,而在客户端中 简单地调用代理类的send方法就可以。

静态代理模式总结  代理模式通过代理类对外部提供统一的接口,在代理类中实现对被代理类的附加操作,从而可以在不影响外部调用的情况下实现系统的拓展,我觉得代理模式可能在一个程序项目的开发初期运用不到,而在项目成型而又有了新的变化、升级等,可以考虑用代理模式来实现,这样可以不需要修改原有的代码。

动态代理模式  其实上文所讲述的内容只是代理模式的一部分,代理模式还有更为强大的动态代理模式。以下是这 2 个的区别:

静态代理模式:在我们的代码运行前,代理类的class编译文件就已经存在了

动态代理模式:在 code 阶段并不存在被代理类,而且并不知道要代理哪个对象,利用 Java 的反射机制在运行期动态地生成代理者的对象,代理谁将会在代码执行阶段决定。

动态代理模式的实现  Java 已经为我们提供了一个便捷的动态代理接口 InvocationHandler ,我们重写其调用方法 invoke。以前面 我们的代理律师的例子为例,看看具体的操作是怎么样的

[code]public class DynamicProxy implements InvocationHandler{ private Object object;// 被代理类的类引用 public DynamicProxy(Object object) { this.object = object; } @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { beforeDefend(); //调用被代理类对象的方法 Object result = method.invoke(object, args); afterDefend(); return result; } private void beforeDefend(){ System.out.print("我是原告律师,以下是我方辩词"); } private void afterDefend(){ System.out.print("辩护完毕"); } }

  解释一下这个 invoke 方法,我们通过 invoke 方法来调用具体的被代理方法,也就是真实的方法,如果对反射机制了解的话, method.invoke(object,args) 这句代码应该很好理解,object 是被代理类,method 是被代理类的方法,args 是方法的参数。

  我们仅仅是实现了 InvocationHandler 的接口,那么接下来该做什么呢?怎么实现动态生成代理者对象呢?Java 的 java.lang.reflect 包下 还有一个 Proxy 类,它有个静态方法 newProxyInstance(),我们使用这个方法生成。以前面 我们的代理律师的例子为例,

[code]public class Client { public static void main(String[] args) { //被代理类 IDefender accuser = new Accuser(); accuser.defend(); DynamicProxy proxy = new DynamicProxy(accuser); ClassLoader loader = accuser.getClass().getClassLoader(); IDefender proxyIDefender = (IDefender) Proxy.newProxyInstance(loader, new Class[]{IDefender.class}, proxy); proxyIDefender.defend(); } }

  这个客户端的输出结果,和之前是一样的,可以发现,我们将之前代理类的工作,转换到 InvocationHandler 的 invoke() 方法去执行,不再需要关心到底需要代理谁。

动态代理在 Retrofit 框架中的运用  Retrofit 是 Android 上流行的 Http Client请求库先看以下一段代码

[code]interface GitHubService { @GET("/repos/{owner}/{repo}/contributors") List<Contributor> repoContributors( @Path("owner") String owner, @Path("repo") String repo); }

[code]Retrofit retrofit = new Retrofit.Builder() .baseUrl("https://api.github.com") .build(); //代理模式的运用 GitHubService service = retrofit.create(GitHubService.class);

[code]Call

  本文关键词:设计模式解析,由笔耕文化传播整理发布。



本文编号:236203

资料下载
论文发表

本文链接:https://www.wllwen.com/wenshubaike/mishujinen/236203.html


Copyright(c)文论论文网All Rights Reserved | 网站地图 |

版权申明:资料由用户6dd0d***提供,本站仅收录摘要或目录,作者需要删除请E-mail邮箱bigeng88@qq.com