设计模式_代理模式
一、定义
代理模式(Proxy Pattrn)是指对其他对象提供一种代理,以控制对这个对象的访问,属于结构型设计模式。在某些情况下,一个对象不适合或不能直接引用另一个对象,而代理对象可以在客户端和目标对象之间起到中介的作用。
官方说明:Provide surrogate or placeholder for anothor object to control access to it.
代理模式中的角色:
- Subject(主体)
Subject角色定义了使proxy和realsubject角色之间具有一致性的接口。这个接口提供了一个使用的好处,就是client不必却分它使用的是代理对象还是真实对象。
对应实例中Printable角色 - Proxy(代理人)
Proxy角色会尽量处理来自Client角色的请求。只有当自己不能处理的时候,就交给工作交给真实对象。代理对象只有在有必要时才会生成真实的对象。
实例中对应的是PrinterProxy对象。 - RealSubject(真实对象)
就是实际完成工作的对象,对应实例中的Printer对象。
二、应用场景
生活中的售房/租房中介,售票黄牛,婚介,经纪人,快递,非侵入式日志监听等,都是代理模式的体现。使用代理模式主要有两个目的:
①保护目标对象;
②增强目标对象(增强目标对象,实际上就是在源代码逻辑前后增加一些处理代码,而调用者无感知)。
三、静态代理
话不多说,直接coding
举个栗子:我们线上买票基本都是在12306买票,但是有时候会在类如某猪、某程等抢票APP上下单抢票,这时候他们就是代理,代替我们抢票,不用盯着官方是否放票。
public interface ITicket {
boolean buyTickets();
}
//Ash:one people
class Ash implements ITicket {
@Override
public boolean buyTickets() {
System.out.println("在12306抢票...");
return true;
}
}
class Proxy implements ITicket {
private Ash ash;
public Proxy(Ash ash) {
this.ash = ash;
}
@Override
public boolean buyTickets() {
before();
boolean isBuyOK = ash.buyTickets();
if(!isBuyOK) return false;
after();
return isBuyOK;
}
private void before() {
System.out.println("在某猪下单去**的车票...");
}
private void after() {
System.out.println("购买成功!");
}
}
//测试
class StaticProxyTest {
public static void main(String[] args) {
Proxy proxy = new Proxy(new Ash());
proxy.buyTickets();
}
}
运行结果:
在某猪下单去**的车票...
调用12306接口开始买票...
购买成功!
静态代理比较好理解,这里就举一个栗子。不再赘述。
四、动态代理
动态代理和静态代理的基本思路是一致的,只不过动态代理的功能更强大一些,业务的扩展性更强。某猪、某程这些抢票软件不可能只能给Ash抢票,也可以给Edith、Anne其他人抢票,这样更符合实际业务。
4.1 JDK动态代理
interface ITicket {
boolean buyTickets();
}
class People implements ITicket {
@Override
public boolean buyTickets() {
System.out.println("在12306抢票...");
return true;
}
}
class TicketProxy implements InvocationHandler {
private ITicket ticket;
public ITicket getInstance(ITicket ticket){
this.ticket = ticket;
Class clazz = ticket.getClass();
return (ITicket) Proxy.newProxyInstance(clazz.getClassLoader(), clazz.getInterfaces(), this);
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
before();
Object result = method.invoke(this.ticket, args);
after();
return result;
}
private void before() {
System.out.println("在某猪下单去**的车票...");
}
private void after() {
System.out.println("还有余票,购买成功!");
}
}
运行结果:
在某猪下单去**的车票...
在12306抢票...
还有余票,购买成功!
这样无论是谁,都可以抢票。类似的还有很多业务场景,数据源的动态切换,spring aop都有使用到动态代理模式。
4.2 GClib动态代理
interface ITicket {
boolean buyTickets();
}
class People implements ITicket {
@Override
public boolean buyTickets() {
System.out.println("在12306抢票...");
return true;
}
}
class TicketProxy implements MethodInterceptor {
public Object getInstance(Class<?> clazz){
Enhancer enhancer = new Enhancer();
enhancer.setSuperclass(clazz);
enhancer.setCallback(this);
return enhancer.create();
}
@Override
public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
before();
Object result = methodProxy.invokeSuper(o, objects);
after();
return result;
}
private void before() {
System.out.println("在某猪下单去**的车票...");
}
private void after() {
System.out.println("还有余票,购买成功!");
}
}
下面我们来分析下JDK代理的实现原理:
在使用Proxy工具newProxyInstance的时候,会在内存中动态生成一个&Proxy0的类,加载到JVM中来执行,在invoke中调用的类其实就是这个&Proxy0
…
2020年4月3日 23点16分 先睡了
五、手写实现JDK动态代理
说完原理,我们来自己实现JDK动态代理