设计模式_代理模式

设计模式_代理模式

一、定义

​ 代理模式(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动态代理

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值