1. 代理模式
1.1 定义、优缺点、应用场景
定义:由于某些原因访问对象(购房者)不能或不想直接和目标对象(开发商)进行访问,需要通过代理(中介)来帮助完成
优点:
- 代理模式在客户端与目标对象之间起到一个中介作用和保护目标对象的作用
- 代理对象可以扩展目标对象的功能
- 代理模式能将客户端与目标对象分离,在一定程度上降低了系统的耦合度,增加了程序的可扩展性
缺点:
- 代理模式会造成系统设计中类的数量增加,增加了系统的复杂度
- 在客户端和目标对象之间增加一个代理对象,会造成请求处理速度变慢
- 真实主题每增加一个业务方法,代理主题也必须同步增加一个业务方法。可以使用动态代理方式解决
应用场景:
- 远程代理,这种方式通常是为了隐藏目标对象存在于不同地址空间的事实,方便客户端访问
- 虚拟代理,这种方式通常用于要创建的目标对象开销很大时,可以由代理先提供部分服务
- 安全代理,这种方式通常用于控制不同种类客户对真实对象的访问权限
- 智能指引,主要用于调用目标对象时,代理附加一些额外的处理功能
- 延迟加载,指为了提高系统的性能,延迟对目标的加载
1.2 模式的结构与实现(静态代理)
结构:
主要是通过定义一个继承抽象主题的代理,该代理包含真实主题,从而实现对真实主题的访问
- 抽象主题(Subject)类:通过接口或抽象类声明真实主题和代理对象实现的业务方法
- 真实主题(Real Subject)类:实现了抽象主题中的具体业务,是代理对象所代表的真实对象,是最终要引用的对象
- 代理(Proxy)类:提供了与真实主题相同的接口,其内部含有对真实主题的引用,它可以访问、控制或扩展真实主题的功能
根据代理的创建时期,代理模式分为静态代理和动态代理
- 静态:由程序员创建代理类再对其编译,在客户端访问前代理类的.class文件就已经存在了
- 动态:在程序运行时,运用反射机制动态创建而成
实现
public class ProxyTest {
public static void main(String[] args) {
HouseProxy houseProxy = new HouseProxy(new RealHouse());
houseProxy.buyHouse();
}
}
// 抽象主题:房子模型
interface House {
void buyHouse();
}
// 真实主题:真实的房子
class RealHouse implements House {
public void buyHouse() {
System.out.println("这是您买的一套毛坯江景房");
}
}
// 代理:房产中介。可以代理不同的House
class HouseProxy implements House {
private House realHouse;
public HouseProxy(House house) {
this.realHouse = house;
}
// 只能代理固定的业务,不能动态发展新的业务
public void buyHouse() {
preBuyHouse();
this.realHouse.buyHouse();
postBuyHouse();
}
// 买房前提供的服务
public void preBuyHouse() {
System.out.println("中介买房前提供的服务");
}
// 买房后提供的服务
public void postBuyHouse() {
System.out.println("中介买房后提供的服务");
}
}
运行程序,结果如下:
中介买房前提供的服务
这是您买的一套毛坯江景房
中介买房后提供的服务
1.3 动态代理模式
前面我们使用静态代理,发现真实主题每增加一个业务方法,代理主题也必须同步增加一个业务方法。现在我们使用动态代理方式解决
动态代理模式,是通过实现Java的java.lang.reflect.InvocationHandler这个接口,通过反射来对真实主题进行实例化,然后通过反射动态的执行方法。实现参考如下:
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
public class ProxyTest {
public static void main(String[] args) {
HouseRelatedProxy houseRelatedProxy = new HouseRelatedProxy();
HouseRelated houseRelated = houseRelatedProxy.getInstance(new RealHouseRelated());
houseRelated.buyHouse();
System.out.println("==================");
houseRelated.decorate();
}
}
// 抽象主题:房子相关模型
interface HouseRelated {
void buyHouse();
void decorate();
}
// 真实主题:真实的房子相关产品
class RealHouseRelated implements HouseRelated {
public void buyHouse() {
System.out.println("这是您买的一套毛坯江景房");
}
public void decorate() {
System.out.println("江景房已经给您装修好了");
}
}
// 代理:房产相关业务的中介。可以代理不同的House,后续还可以动态的发展新的业务,比如装修、代理家具
class HouseRelatedProxy implements InvocationHandler {
private HouseRelated houseRelated;
public HouseRelated getInstance(HouseRelated houseRelated) {
this.houseRelated = houseRelated;
Class<?> houseRelatedClass = this.houseRelated.getClass();
// 返回中介的一个代理实例(真实主题)。基于反射的原理
/*
三个参数含义:
1. classLoader:加载动态生成的类加载器
2. interfaces:目标对象实现的所有接口的class对象所组成的数组
3、invocationHandler:设置代理对象实现目标对象方法的过程,即代理类中如何重写InvocationHandler接口中的invoke抽象方法
*/
return (HouseRelated) Proxy.newProxyInstance(houseRelatedClass.getClassLoader(), houseRelatedClass.getInterfaces(), this);
}
// 在客户端调用代理实例(真实主题)的方法,会自动跳转到执行这个方法。基于反射的原理
// 可以动态发展新的业务
/*
三个参数含义:
1. proxy:代理对象
2. method:目标对象的方法
3. args:method所对应方法的参数
*/
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
preHouseRelated();
Object result = method.invoke(this.houseRelated, args);
postHouseRelated();
return result;
}
// 房产相关前提供的服务
public void preHouseRelated() {
System.out.println("房产相关前提供的服务");
}
// 房产相关后提供的服务
public void postHouseRelated() {
System.out.println("房产相关后提供的服务");
}
}
运行程序,结果如下:
房产相关前提供的服务
这是您买的一套毛坯江景房
房产相关后提供的服务
==================
房产相关前提供的服务
江景房已经给您装修好了
房产相关后提供的服务