黑马程序员技术交流社区

标题: 【上海校区】设计模式-代理模式 [打印本页]

作者: 不二晨    时间: 2018-7-4 09:22
标题: 【上海校区】设计模式-代理模式

1、定义

Provide a surrogate or placeholder for another object to control access to it.

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

2、类图

3、角色

代理模式也叫委托模式,它是一项基本的设计技巧。许多其他的模式,如状态模式、策略模式、访问者模式本质上是在更特殊的场合采用了委托模式。代理模式可以提供非常好的访问控制。

Subject :抽象主题角色

抽象主题类可以是抽象类也可以是接口,是一个最普通的业务类型定义,无特殊要求。

RealSubject:具体主题角色

也叫做被委托角色、被代理角色。它才是冤大头,是业务逻辑的具体执行者。

Proxy:代理主题角色

也叫做委托类、代理类。它负责对真实角色的应用,把所有抽象主题类定义的方法限制委托给真实主题角色实现,并且在真实主题角色处理完毕前后做预处理和善后处理工作。

4、例子


使用:

输出:

5、优缺点

优点:

a、职责清晰。真实的角色就是实现实际的业务逻辑,不用关心其他非本职责的事务,通过后期的代理完成一件事务,附带的结果就是编程简洁清晰

b、高扩展性。具体主题角色是随时都会发生变化的,只要它实现了接口,甭管它如何变化,都逃不脱如来佛的手掌(接口),那我们的代理类完全就可以在不做任何修改的情况下使用。

c、智能化。动态代理可以体现。

6、扩展

设计模式中的代理分为“普通代理”和“强制代理”两种。

普通代理

他的要求就是客户端只能访问代理角色,而不能访问真实角色,也就是场景类不能再直接new一个对象了,他必须由代理来模拟场景。

我们需要修改两个实现类的构造函数即可。

RealSubject:

Proxy:

使用:

输出:

        运行结果完全相同。在该模式下,调用者只知代理而不用知道真实的角色RealSubject是谁,屏蔽了真实角色的变更对高层模块的影响,真实的主题角色想怎么修改就怎么修改,对高层次的模块没有任何的影响,只要你实现了接口所对应的方法,该模式非常适合对扩展性要求较高的场合。当然,在实际的项目中,一般都是通过约定来禁止new一个真实的角色,这也是一个非常好的方案。

强制代理

强制代理在设计模式汇总比较另类,一般的思维是通过代理找到真实的角色,但是强制代理确实要“强制”,比必须通过真实角色查找到代理,否则你不能访问,也就是通过真实角色管理代理角色。

改造如下:

ISubject:

RealSubjectProxy:

RealSubjectA:

运行:

输出:

7、代理个性化

一个类可以实现多个接口,完成不同任务的整合。也就是说代理类不仅仅可以实现主题接口,也可以实现其他接口完成不同的任务,而且代理的目的是在目标对象方法的基础上作增强,这种增强的本质通常就是对目标对象的方法进行拦截和过滤。

增加一个接口,IProxy:

RealSubjectProxy:

就只用修改这一个类,实现接口,其他了类不用变!

使用:

输出:

代理类不仅仅是可以有自己的运算方法,通常的情况下代理的职责并不一定单一,它可以组合其他的真实角色,也可以实现自己的职责。

代理类可以为真实角色预处理消息、过滤消息、消息转发、事后处理消息等功能。

当然一个代理类,可以代理多个真实角色,并且真实角色之间可以有耦合关系。


8、动态代理

什么是动态代理?

动态代理是在实现阶段不用关心代理谁,而在运行阶段才指定代理那个对象。面向横切面编程(AOP)的核心就是采用了动态代理机制。

接口和实现类很简单,定义需要实现的方法即可。

ISubject:

RealSubjectA:

定义一个动态代理类RealSubjectHI,实现InvocationHandler接口,构造方法传入需要代理的对象。

其中invoke方法是接口InvocationHandler定义必须实现的,它完成对真实方法的调用。我 们来详细讲解一下InvocationHandler接口,动态代理是根据被代理的接口生成所有的方法, 也就是说给定一个接口,动态代理会宣称“我已经实现该接口下的所有方法了”,那动态代理怎么才能实现被代理接口中的方法呢?默认情况下所有的方法返回值都是空的,是的,代理已经实现它了,但是没有任何的逻辑含义,那怎么办?好办,通过 InvocationHandler接口,所有方法都由该Handler来进行处理,即所有被代理的方法都由 InvocationHandler接管实际的处理任务。

调用:

输出:

注意:

我们既没有创建代理类,也没有实现ISubject接口,这就是动态代理。

如果我们想在一个方法调用后随即触发一些逻辑操作怎么办呢?简单,只需要改变动态代理Handler类,在invoke方法中添加一段的代码即可,请看:

调用方法并无变化:


输出:

很棒啊,有木有!这就是AOP编程。AOP编程没有使用什么新的技术,但是它对我们的设计、编码有非常大的影响,对于日志、事务、权限等都可以在系统设计阶段不用考虑,而在设计后通 过AOP的方式切过去。

很简单,两条独立发展的线路。动态代理实现代理的职责,业务逻辑Subject实现相关的 逻辑功能,两者之间没有必然的相互耦合的关系。通知Advice从另一个切面切入,最终在高层模块也就是Client进行耦合,完成逻辑的封装任务。

AOP及动态代理抽取

在这里插入了较多的AOP术语,如在什么地方(连接点)执行什么行为(通知)。我们 在这里实现了一个简单的横切面编程。

我们来看通知Advice,也就是我们要切入的类,接口和实现如代码清单如下:

因此我们抽象动态代理类:

在返回动态代理对象之前,执行我们要切入的类的方法。

执行变成了这样:

输出:

Proxy.newProxyInstance(classLoader, tClass, invocationHandler);该方法是重新生成了一个对象,为什么要重新生成?你要使用代理呀,注意 c.getInterfaces()这句话, 这是非常有意思的一句话,是说查找到该类的所有接口,然后实现 接口的所有方法。当然了,方法都是空的,由谁具体负责接管呢?是new MyInvocationHandler(_Obj)这个对象。 于是我们知道一个类的动态代理类是这样的一个类,由InvocationHandler的实现类实现所有的方法,由其invoke方法接管所有方法的实现。

我们注意到上面的动态代理类DynamicProxy是一个通用类,不具有业务意义,我们可以在再产生一个实现类简化代码。

调用 so easy:

输出:


【转载】原文地址:https://blog.csdn.net/Aminy123/article/details/80769246



作者: 吴琼老师    时间: 2018-7-5 16:53





欢迎光临 黑马程序员技术交流社区 (http://bbs.itheima.com/) 黑马程序员IT技术论坛 X3.2