设计模式——代理模式

介绍

这种类型的设计模式属于结构型模式。
意图:为其他对象提供一种代理的方式控制被代理对象。
主要解决:在直接访问对象时带来的问题,比如说:要访问的对象在远程的机器上。
例如:1. 猪八戒去找高翠兰结果是孙悟空变的,可以这样理解:把高翠兰的外貌抽象出来,高翠兰本人和孙悟空都实现了这个接口,猪八戒访问高翠兰的时候看不出来这个是孙悟空,所以说孙悟空是高翠兰代理类。 2. spring aop。
代理模式分为两类:静态代理、动态代理。

实现

图解

这里写图片描述

通过代理实现简单的登录登出功能

静态代理
//公共接口,目标对象和代理都来实现 
interface ILogin{
    void login();
    void logout();
}
//目标接口
class RealLogin implements ILogin{
    public void login(){  
        try {  
            Thread.sleep(3200);  
        } catch (InterruptedException e) {
            e.printStackTrace();  
        }  
        System.out.println("登录系统.....");  
    }
    public void logout(){  
        try {  
            Thread.sleep(2200);  
        } catch (InterruptedException e) {  
            e.printStackTrace();  
        }  
        System.out.println("退出系统....");  
    }  
}
//代理对象,代理目标对象Reallogin    
class ProxyLogin implements ILogin{
    //此类中包含了目标对象  
    private RealLogin target;  
    //构造方法  
    public ProxyLogin (RealLogin target){  
        this.target = target;  
    }  
    @Override  
    public void login() {  
        //开始时间
        long begin = System.currentTimeMillis();  
        target.login();  
        //结束时间  
        long end = System.currentTimeMillis();  
        System.out.println("耗费时长"+(end-begin)+"毫秒");  
    }  
    @Override  
    public void logout() {  
        long begin = System.currentTimeMillis();  
        target.logout();  
        long end = System.currentTimeMillis();  
        System.out.println("耗费时长"+(end-begin)+"毫秒");  
    }  
}  
public class Client {
    // 不使用建造者模式,创建和表示在一块,没有分离
    public static void main(String[] args) {
        ProxyLogin p = new ProxyLogin(new RealLogin());
        //获取登录时长
        p.login();
    }
}

通过代理模式,非常简单的实现了对登录登出时间的捕获,但是,假如客户突然要求我们对所有的类方法的时间进行捕获,那该怎么办呢?总不能每一个类,都写一个代理类吧。这样势必会造成类爆炸,怎么办呢?

动态代理

通过反射机制,利用JDK提供的Proxy类,在程序运行的时候在内存中根据目标对象来创建代理对象,避免了类爆炸的出现。代理方法只写一此,使代码得到了复用。

//公共接口,目标对象和代理都来实现 
interface ILogin {
    void login();

    void logout();
}
// 目标对象,实现公共接口,达到登录登出的功能
class RealLogin implements ILogin {
    public void login() {
        try {
            Thread.sleep(3200);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("登录系统.....");
    }
    public void logout() {
        try {
            Thread.sleep(2200);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("退出系统....");
    }
}
// 代理对象,代理目标对象Reallogin
class ProxyLogin implements ILogin {
    // 此类中包含了目标对象
    private RealLogin target;
    // 构造方法
    public ProxyLogin(RealLogin target) {
        this.target = target;
    }
    @Override
    public void login() {
        // 开始时间
        long begin = System.currentTimeMillis();
        target.login();
        // 结束时间
        long end = System.currentTimeMillis();
        System.out.println("耗费时长" + (end - begin) + "毫秒");
    }
    @Override
    public void logout() {
        long begin = System.currentTimeMillis();
        target.logout();
        long end = System.currentTimeMillis();
        System.out.println("耗费时长" + (end - begin) + "毫秒");
    }
}
// 此类需要实现InvocationHandler接口
class TimerInvocationHandler implements InvocationHandler {
    // 目标对象,通过反射机制获得
    private Object target;
    // 构造方法
    public TimerInvocationHandler(Object target) {
        this.target = target;
    }
    //Object proxy:代理对象的引用,proxy变量中保存代理对象的内存地址(这个参数很少用) 
    //Method method:目标对象的目标方法 
    //Object[] args:目标对象的目标方法执行的时候所需要实参
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        // 开始时间
        long begin = System.currentTimeMillis();
        // 执行目标对象中的方法
        Object retValue = method.invoke(target, args);
        // 结束时间
        long end = System.currentTimeMillis();
        // 计算时间
        System.out.println("耗费时长" + (end - begin) + "毫秒");
        return retValue;
    }
}
public class Client {
    public static void main(String[] args) {
        // 创建目标对象
        ILogin target = new RealLogin();
        // 这里的类装载器主要是用来装载在内存中生成的那个临时的字节码,代理类的类装载器需要和目标类的类装载器一致
        ClassLoader loader = target.getClass().getClassLoader();
        // 代理类和目标类必须实现"同一些"接口。(一个类可以同时实现多个接口)
        Class[] interfaces = new Class[] { ProxyLogin.class };
        // 当代理对象调用代理方法的时候,"注册"在调用处理器中的invoke方法会自动调用。
        InvocationHandler handler = new TimerInvocationHandler(target);
        // 创建代理对象:通过JDK内置的动态代理类java.lang.reflect.Proxy完成代理对象的动态创建
        ILogin proxy = (ILogin) Proxy.newProxyInstance(loader, interfaces, handler);
        // 通过执行代理对象的代理方法去执行目标对象的目标方法
        proxy.login();
        proxy.logout();
    }
}
总结

抽象角色:通过接口或抽象类声明真实角色实现的业务方法。
代理角色:实现抽象角色,是真实角色的代理,通过真实角色的业务逻辑方法来实现抽象方法,并可以附加自己的操作。
真实角色:实现抽象角色,定义真实角色所要实现的业务逻辑,供代理角色调用。

【好处】
(1) 职责清晰
真实的角色就是实现实际的业务逻辑,不用关心其他非本职责的事务,通过后期的代理完成一件完成事务,附带的结果就是编程简洁清晰。
(2) 代理对象可以在客户端和目标对象之间起到中介的作用,这样起到了中介的作用和保护了目标对象的作用。
(3) 高扩展性

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值