代理设计模式
代理模式简介
1、代理模式(Proxy Pattern),是程序设计中的一种设计模式。
2、所谓的代理者是指一个类别可以作为其它东西的接口。代理者可以作任何东西的接口: 网上连接、存储器中的大对象、文件或其它昂贵或无法复制的资源。【百度词条】
3、为某个对象提供一个代理,以控制对这个对象的访问。 代理类和委托类有共同的父类或父接口,
这样在任何使用委托类对象的地方都可以用代理对象替代。代理类负责请求的预处理、过滤、将请
求分派给委托类处理、以及委托类执行完请求后的后续处理。 【百度】
4、我的个人理解:所谓代理模式,就是指一个对象可以完成另一个对象的功能,但是这个对象可以在完成功能的过程中有其他的想法。
比如:淘宝商家就是商品厂家的代理,厂家就是生产商品并且出售的,淘宝商家就是他的一个代理,可以将商品卖出,并且按照自己的(价格)出售
【个人简单理解】
实现代理模式的要求
1、代理类需要和目标类实现相同的接口。
2、代理类中需要有目标类,不然怎么实现目标的功能,并且进行加强呢
3、增强功能:在原有的功能之上进行功能的增强
4、访问控制:代理类不让你直接访问目标类,例如:商家不让你直接访问厂家
静态代理的实现步骤
1、创建接口,出售商品
package test.service;
public interface SellGoods {
/**
* 定义销售的规范
* @param amount 购买的商品的数量
* @return 返回总价格
*/
float sell(int amount);
}
2、创建商家,商家实现了出售商品的接口【就是目标类】
package test.service.Impl;
import test.service.SellGoods;
public class GoodsFactory implements SellGoods {
//定义商品单价
private static float onePrice = 20;
/**
* 这是商品厂家,定义了商品的出售单价
* @param amount 购买的商品的数量
* @return 总价格
*/
@Override
public float sell(int amount) {
float price = amount * onePrice;
return price;
}
}
3、创建代理类,完成对目标类功能的加强
package test.service.proxy;
import test.service.Impl.GoodsFactory;
import test.service.SellGoods;
/**
* 这是一个代理类
*/
public class TaoBao implements SellGoods {
//目标类
private SellGoods sellGoods = new GoodsFactory();
/**
* 这是代理类中的那个增强方法
* @param amount 购买的商品的数量
* @return 总价格
*/
@Override
public float sell(int amount) {
/*
1、定义单价是厂家原价+15元
2、调用目标类方法完成商品的购买。
3、增强功能,一个是增加价格,一个是购买数量大于10反馈优惠券
*/
if (amount >= 10){
System.out.println("模拟反馈优惠券!");
}
float allPrice = 0;
float price = sellGoods.sell(amount);
allPrice = price + amount*15;
return allPrice;
}
}
4、测试
package mytest.service.proxy;
public class Test01 {
public static void main(String[] args) {
TaoBao taoBao = new TaoBao();
float sell = taoBao.sell(100);
System.out.println("价格:"+sell);
}
}
运行结果
动态代理实现步骤
1、定义接口
package com.java设计模式.结构型.动态代理设计模式.Factory;
public interface SellUSB {
//销售USB
float sell(int amount);
}
2、定义目标类,也就是接口实现类
package com.java设计模式.结构型.动态代理设计模式.Factory;
public class SellUSBFactory implements SellUSB {
// 销售USB
@Override
public float sell(int amount) {
System.out.println("厂家开始准备货物");
float price = 80.0f;
return amount * price;
}
}
3、使用JDK动态代理完成代理类的功能增强
package com.java设计模式.结构型.动态代理设计模式.proxy;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
public class FactoryUSBInvocationHandlerImpl implements InvocationHandler {
private Object target;
public FactoryUSBInvocationHandlerImpl(Object target) {
this.target = target;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
Object price = method.invoke(target, args);
//参数,购买的数量
int amount = (int) args[0];
if (price != null){
float temp = (float) price;
price = temp + 25f*amount;
}
System.out.println("赠送您5元优惠券");
return price;
}
}
4、使用反射机制完成动态代理类创建
package com.java设计模式.结构型.动态代理设计模式.Test;
import com.java设计模式.结构型.动态代理设计模式.Factory.SellUSB;
import com.java设计模式.结构型.动态代理设计模式.proxy.FactoryUSBInvocationHandlerImpl;
import com.java设计模式.结构型.动态代理设计模式.proxy.TaoBaoproxy;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Proxy;
public class UserToShopUSB {
public static void main(String[] args) throws Throwable {
Class c = Class.forName("com.java设计模式.结构型.动态代理设计模式.Factory.SellUSBFactory");
Object obj = c.newInstance();
InvocationHandler handler = new FactoryUSBInvocationHandlerImpl(obj);
SellUSB proxy = (SellUSB) Proxy.newProxyInstance(obj.getClass().getClassLoader(),
c.getInterfaces(), handler);
float sell = proxy.sell(1);
handler = new TaoBaoproxy(obj);
proxy = (SellUSB) Proxy.newProxyInstance(obj.getClass().getClassLoader(),
c.getInterfaces(), handler);
sell = proxy.sell(100);
System.out.println(sell);
}
}
运行结果
5、JDK动态代理完成代理类创建分析
1、JDK动态代理使用的是反射机制创建代理对象
2、使用InvocationHandler接口完成代理类功能的增强
3、管理InvocationHandler实现类的方法分析
public Object invoke(Object proxy, Method method, Object[] args)
proxy:代理对象
method:代理对象访问的方法
args:传递参数
通过invoke()方法完成目标方法的调用
扩展
1、java框架的底层是基于动态代理实现的
2、实现动态代理的其他方式有CGlib第三方工具库
动态代理源码分析
1、相关包:
- java.lang.reflect.Proxy
- java.lang.reflect.InvocationHandler
2、Proxy中的重要静态方法
-
static InvocationHandler getInvocationHandler(Object proxy)
根据当前代理对象,获取调用处理器对象。
-
static class getProxyClass(ClassLoader loader, class… interfaces)
该方法用于获取关联于指定类装载器和一组接口的动态代理类的类对象 -
static boolean isProxyClass(class cl)
该方法用于判断指定类对象是否是一个动态代理类 -
【重点】static Object newProxyInstance(ClassLoader loader, Class[] interfaces, InvocationHandler h)
该方法用于为指定类装载器、一组接口及调用处理器生成动态代理类实例
3、执行流程
1、创建InvocationHandler实现类,这个方法就类似于我们上面静态代理类的普通方法,目的就是在这个方法中增强目标类(委托类)的功能。这个实现类的重写方法有三个参数
-
proxy:代理对象【调用方法的那个代理对象,比如:proxy.doSome(),就是proxy】
-
method:代理对象访问的方法【比如:proxy.doSome(),就是doSome方法】
-
args:传递参数【比如:proxy.doSome(name,age),参数就是name和age】
在调用处理器中需要有目标类对象的实例,目的是调用需要增强的方法。使用的方法是: method.invoke(target, args); target就是目标类实例
2、创建代理类对象,使用的是Proxy的静态方法
-
newProxyInstance(obj.getClass().getClassLoader(),c.getInterfaces(), handler)
需要三个参数
-
ClassLoader loader【类加载器】
proxy代理类对象没有通过编译生成.class文件。因此需要在类加载夹断,通过类加载器将class字节码文件加载到JVM虚拟机中。并定义其为类对象,该类才能被使用。
-
Class<?>[] interfaces
通过 Proxy 为包括 Interface 接口在内的一组接口动态创建代理类的类对象
-
InvocationHandler h
用来增强功能的处理器对象。
4、底层原理简单分析
1、已经创建好了代理对象proxyObj
2、如果使用代理对象调用方法:proxyObj.doSome(a,b);
3、底层会直接调动InvocationHandler实现类的invoke方法,将方法名传递给method,将proxyObj代理对象传递给proxy。底层使用的是反射机制,通过method.getName() 可以获取方法名,通过反射机制的invoke方法执行对象的目标类对象方法。实现目标类功能,并且增强功能等。