当前位置 博文首页 > 韩超的博客 (hanchao5272):设计模式-代理模式-以购房中介为例
超级链接: Java常用设计模式的实例学习系列-绪论
参考:《HeadFirst设计模式》
代理模式是一种结构型
模式。
代理模式:为其他对象提供一个代理以控制对这个对象的访问。
本文以购房中介
为场景来学习代理模式
:
房子最终属于房主,首先我们先定义房主接口和房主类。
被代理对象:接口:IHouseOwner
/**
* <p>房主接口</P>
*
* @author hanchao
*/
public interface IHouseOwner {
/**
* 房屋交易
*/
void tradeHouse();
}
被代理对象:类:HouseOwner
/**
* <p>房主</P>
*
* @author hanchao
*/
@Slf4j
public class HouseOwner implements IHouseOwner {
/**
* 房屋交易
*/
@Override
public void tradeHouse() {
log.info("房屋交易");
}
}
/**
* <p>购房者</P>
*
* @author hanchao
*/
@Slf4j
public class HouseBuyer {
/**
* 直接找房主购房
*/
public void buyHouseDirectly() {
log.info("购房者花费大量时间用于筛选房屋...最终选定了一间房。");
new HouseOwner().tradeHouse();
log.info("购房者与房主签订售房合同。");
}
}
直接买房是在太麻烦了,因为购房者花费大量时间用于筛选房屋,在决定买房之后,购房者还需与房主签订一系列的售房合同。
为了省事省心,购房者决定通过售房中介进行买房。
这种方式,通过定义售房中介,直接代理房主类
进行售房。
/**
* <p>房屋中介:静态代理-代理对象是类</P>
*
* @author hanchao
*/
@Slf4j
public class HouseAgentByStaticForClass {
/**
* 被代理的对象:房主
*/
private HouseOwner owner;
public HouseAgentByStaticForClass(HouseOwner owner) {
this.owner = owner;
}
/**
* 房屋交易
*/
public void sellHouse() {
//前置操作
log.info("中介替购房者完成筛选房屋...最终选定了一间房。");
//售房
owner.tradeHouse();
//后置操作
log.info("中介替购房者完成与房主签订的售房合同。");
}
}
下面是通过中介买房的流程。
/**
* <p>购房者</P>
*
* @author hanchao
*/
@Slf4j
public class HouseBuyer {
/**
* 找中介买房:静态代理-代理对象:类
*/
public void buyHouseByStaticProxyForClass() {
//被代理对象:房主类
HouseOwner owner = new HouseOwner();
//代理对象
HouseAgentByStaticForClass houseAgent = new HouseAgentByStaticForClass(owner);
//买房
houseAgent.sellHouse();
}
}
这种方式,通过定义售房中介,直接代理房主接口
进行售房。
/**
* <p>房屋中介:静态代理-代理对象是接口</P>
*
* @author hanchao
*/
@Slf4j
public class HouseAgentByStaticForInterface implements IHouseOwner {
/**
* 被代理的对象:房主
*/
private IHouseOwner owner;
public HouseAgentByStaticForInterface(IHouseOwner owner) {
this.owner = owner;
}
/**
* 房屋交易
*/
@Override
public void tradeHouse() {
//前置操作
log.info("中介替购房者完成筛选房屋...最终选定了一间房。");
//售房
owner.tradeHouse();
//后置操作
log.info("中介替购房者完成与房主签订的售房合同。");
}
}
下面是通过中介买房的流程。
/**
* <p>购房者</P>
*
* @author hanchao
*/
@Slf4j
public class HouseBuyer {
/**
* 找中介买房:静态代理-代理对象:接口
*/
public void buyHouseByStaticProxyForInterface() {
//被代理对象:房主接口
IHouseOwner iHouseOwner = new HouseOwner();
//定义代理对象
IHouseOwner houseAgent = new HouseAgentByStaticForInterface(iHouseOwner);
//买房
houseAgent.tradeHouse();
}
}
可维护性差:
自定义调用处理器:实现InvocationHandler:HouseAgentByDynamicForJdk
/**
* <p>动态代理:房屋中介</P>
*
* @author hanchao
*/
@Slf4j
public class HouseAgentByDynamicForJdk implements InvocationHandler {
/**
* 被代理的对象:房主
*/
private IHouseOwner owner;
public HouseAgentByDynamicForJdk(IHouseOwner owner) {
this.owner = owner;
}
/**
* 对售房进行代理
*
* @param proxy 代理对象实例
* @param method 被代理的方法
* @param args 参数
* @return 返回值
*/
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
//前置操作
log.info("中介替购房者完成筛选房屋...最终选定了一间房。");
//售房
Object result = method.invoke(owner, args);
//后置操作
log.info("中介替购房者完成与房主签订的售房合同。");
return result;
}
}
JDK动态代理实现步骤:
/**
* <p>购房者</P>
*
* @author hanchao
*/
@Slf4j
public class HouseBuyer {
/**
* 找中介买房:JDK动态代理-代理对象:接口
*/
public void buyHouseByDynamicProxyForJdk() {
//被代理的对象:房主接口
IHouseOwner owner = new HouseOwner();
//被代理对象的接口加载器
ClassLoader classLoader = IHouseOwner.class.getClassLoader();
//被代理的接口的类型
Class[] classes = {IHouseOwner.class};
//代理时的调用处理器:房租中介
InvocationHandler proxyHandler = new HouseAgentByDynamicForJdk(owner);
//代理对象
IHouseOwner proxy = (IHouseOwner) Proxy.newProxyInstance(classLoader, classes, proxyHandler);
//代理售房
proxy.tradeHouse();
}
}
JDK通过java.lang.reflect.Proxy
类能够实现动态代理,其主要流程如下:
InvocationHandler
接口,自定义自己需要的调用处理器:invocationHandler
。classLoader
。clazz[]
。java.lang.reflect.Proxy
的静态方法newProxyInstance()
,以invocationHandler
、classLoader
和clazz[]
为参数,生成代理对象。**注意:**根据上述流程,可以确定JDK动态代理针对的是接口
,而非类
。
如何实现对类的动态代理呢?这就需要CGLib了。
自定义方法解释器:实现MethodInterceptor:HouseAgentByDynamicForJdk
/**
* <p></P>
*
* @author hanchao
*/
@Slf4j
public class HouseAgentByDynamicForCglib implements MethodInterceptor {
/**
* 被代理的对象:房主
*/
private HouseOwner owner;
public HouseAgentByDynamicForCglib(HouseOwner owner) {
this.owner = owner;
}
/**
* 对售房进行代理
*
* @param obj 代理对象实例
* @param method 被代理的方法
* @param args 参数
* @param methodProxy 方法代理
* @return 返回值
*/
@Override
public Object intercept(Object obj, Method method, Object[] args, MethodProxy methodProxy) throws InvocationTargetException, IllegalAccessException {
//前置操作
log.info("中介替购房者完成筛选房屋...最终选定了一间房。");
//售房
Object result = method.invoke(owner, args);
//后置操作
log.info("中介替购房者完成与房主签订的售房合同。");
return result;
}
}
CGLIB动态代理实现步骤:
/**
* <p>购房者</P>
*
* @author hanchao
*/
@Slf4j
public class HouseBuyer {
/**
* 找中介买房:CGLIB动态代理-代理对象:类
*/
public void buyHouseByDynamicProxyForCglib() {
//被代理的对象:房主
HouseOwner owner = new HouseOwner();
//CGLIB增强的代理类
Enhancer enhancer = new Enhancer();
//被代理对象的类型
enhancer.setSuperclass(HouseOwner.class);
//定义代理时的方法解释器
MethodInterceptor methodInterceptor = new HouseAgentByDynamicForCglib(owner);
//以回调方式设置代理行为
enhancer.setCallback(methodInterceptor);
//创建代理对象
HouseOwner roomowner = (HouseOwner) enhancer.create();
//代理售房
roomowner.tradeHouse();
}
}
JDK通过org.springframework.cglib.proxy.Enhancer
类能够实现动态代理,其主要流程如下:
MethodInterceptor
接口,自定义自己需要的方法解释器:methodInterceptor
。enhancer
。enhancer
设置被代理对象的类型:clazz
。methodInterceptor
为参数,为enhancer
设置回调方法。Enhancer#create()
方法创建代理对象。注意:CGLIB动态代理针对的是类
。
使用CGLIB可以直接引用其依赖,也可以使用springframework
的内置CGLIB。
CGLib采用了非常底层的字节码技术,其原理是通过字节码技术为一个类创建子类,并在子类中采用方法拦截的技术拦截所有父类方法的调用,顺势织入横切逻辑。
Interceptor
。AOP
。最后以UML类图来总结本文的售房中介
场景以及代理模式
。