我的设计模式笔记-代理模式

代理模式

静态代理

在这里插入图片描述

静态代理的模式有点点像适配器模式,但是适配器是实现用户端接口,而静态代理则是相反,它是去实现服务提供者(第三方库)的接口(ServiceInterface),实现相同的接口意味者代理(Proxy)和服务实现类(Service)有相同的方法,因此代理可以在方法中引用服务实现类中的相同方法,并在此基础上扩充自己的功能。这就相当于代理更像是服务实现类的扩充,符合开闭原则。

//服务接口
public interface Bank {

    void getMoney(int money);

}

//服务
public class ATM implements Bank {
    @Override
    public void getMoney(int money) {
        System.out.println("取钱:" + money + "元");
    }
}

//代理
public class BankProxy implements  Bank{
    private Bank bank;
	
    //聚合接口实现类
    public BankProxy(Bank bank) {
        this.bank = bank;
    }
    
    //方案2
    public BankProxy() {
        this.bank = new ATM();
    }

    //实现相同的方法
    @Override
    public void getMoney(int money) {
        System.out.print("银行代理:");
        bank.getMoney(money);	//PS:这里需要自己调用,有隐患
        System.out.println("扣除手续费:" + Float.valueOf(money) * 0.001 + "元");
    }
}

//客户端
public class Client {
    public static void main(String[] args) {
        //附近找不到ATM,附近有便利店。便利店也是从ATM中取得钱。
        
        //这里有点像是桥接模式(同一个接口算桥接吗?)
        Bank proxy = new BankProxy(new ATM());
        
        //也可以直接在代理类的构造方法直接初始化bank(方案2)
        //Bank proxy = new BankProxy();
        proxy.getMoney(10000);
    }
}

通过上面的代码不难理解静态代理,但是静态代理有不足的地方。静态代理之所以是静态,是因为它的代理方法是直接写在代理类中的,需要人手动去调用实现类的方法(代码中有注释)。如果开发人员编程时不调用对应实现类的方法呢?如果方法名很相似,写错了呢?人是不可信的,所以就引出了动态代理,不需要认为去核对实现类和代理类的方法是否一致。

动态代理

动态代理是在内存中创建代理类的。动态代理能够使我们不写代理类,直接得到代理Class对象,然后根据它创建代理实例。动态代理的两种类型:JDK代理Cglib代理

JDK动态代理

JDK提供了java.lang.reflect.InvocationHandler接口和 java.lang.reflect.Proxy类,这两个类相互配合即可使用JDK动态代理。(代理目标需要有接口,没有接口则使用Cglib进行动态代理)

//接口方法
public interface Bank {
    void getMoney(int money);
}

//代理目标类
public class ATM implements Bank {
    @Override
    public void getMoney(int money) {
        System.out.println("取钱:" + money + "元");
    }
}

//代理类工厂:负责创建不同目标类的代理类
public class ProxyFactory{
 
    private Object obj;

    /**
     * 在工厂的构造方法中传入:目标类实例
     * @param obj
     */
    public ProxyFactory(Object obj) {
        this.obj = obj;
    }

    //工厂类创建关于Bank的代理实例
    public Object newBankProxyInstance(){
        //使用Proxy的newProxyInstance方法
        //参数:目标类启动器、目标类接口、代理方法的处理
        return Proxy.newProxyInstance(
            obj.getClass().getClassLoader(), 
            obj.getClass().getInterfaces(), 
            new InvocationHandler() {
            	//重写invoke方法,只要代理对象调用目标类的方法就会触发如下代码
                @Override
                public Object invoke(Object proxy, 
                                     Method method, 
                                     Object[] args) throws Throwable {
                    System.out.println("代理类:" + proxy.getClass()
                                       + " 方法:" + method.getName()
                                       + " 参数:" + args.toString());
                    Object result = method.invoke(obj, args);
                    System.out.println("代理结束了");
                    return result;
                }
        });
    }
}

public class Client {

    public static void main(String[] args) {
        Bank atm = new ATM();
        //给工厂传入需要代理的接口类
        ProxyFactory factory = new ProxyFactory(atm);
        //使用工厂类创建一个代理对象
        Bank bank = (Bank)factory.newBankProxyInstance();
        //使用代理对象调用方法,会触发代理后的方法。
        bank.getMoney(1000);
    }
}
Cglib动态代理

使用Cglib进行代理,代理目标可以不需要实现接口。

PS:代理的类不能是final

在这里插入图片描述

代码如下

//代理目标类
public class ATM{
    public void getMoney(int money) {
        System.out.println("取钱:" + money + "元");
    }
}

//代理类工厂
public class ProxyFactory {

    private Object target;

    public ProxyFactory(Object obj) {
        this.target = obj;
    }

    public Object newProxyInstance(){
        Enhancer enhancer = new Enhancer();
        //设置父类
        enhancer.setSuperclass(target.getClass());
        //设置回调函数
        enhancer.setCallback(new MethodInterceptor() {
            @Override
            public Object intercept(Object obj, 
                                    Method method, 
                                    Object[] args, 
                                    MethodProxy proxy) throws Throwable {
                System.out.println("before method run...");
                Object result = method.invoke(target, args);
                System.out.println("after method run...");
                return result;
            }
        });
        //创建对象:代理对象
        return enhancer.create();
    }

}

//客户端调用
public class Client {
    public static void main(String[] args) {
        //代理目标对象
        ATM atm = new ATM();
        //传入目标对象
        ProxyFactory factory = new ProxyFactory(atm);
        //新建代理实例
        ATM atmProxy = (ATM) factory.newProxyInstance();
        //使用代理实例调用方法
        atmProxy.getMoney(1000);
    }
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值