您的位置:首页 > 编程语言 > Java开发

23种设计模式07---代理模式

2017-04-02 14:36 253 查看

代理模式

代理模式(Proxy):为其他对象提供一种代理以控制对这个对象的访问。

代理模式说白了就是“真实对象”的代表,在访问对象时引入一定程度的间接性,因为这种间接性可以附加多种用途。

一、静态代理模式

在这实现代码之前,先讲一个简单的生活故事,我们都知道我们周边有很多公司有房屋买卖或租赁的业务,

比如链家(LianJia),但链家本身是不存在任何实际房屋资产的,他所售卖租赁的房屋均需要房屋产权所有人(HomeMaster)提供,才得以实现公司的房源需求;同时公司要的卖房租房业务均需要公司员工(Seller)来实现,但员工要实现该方法,必须经过公司授权以及动用公司的业务资源渠道才可以完成任务。故事讲到这里,我们应该清楚这里的Seller其实就是代理模式中静态代理了,

1.1、抽象主题角色

是一个接口。该接口是对象和它的代理共用的接口。

/**
* 链家公司的业务为售房
*/
public interface LianJia {
public abstract void sellHouse();
}


1.2、真实主题角色

/**
* 房主将自己的房子放在链家的平台上出售
*/
public class HomeMaster implements LianJia{
@Override
public void sellHouse() {
System.out.println("我有房子要出售...");
}
}


1.3、代理角色

内部含有对**真实对象**RealSubject的引用,从而可以操作真实对象。(区别于装饰者模式,真实装饰者角色持有抽象构件的引用,只有在运行时,才知道真实构件角色,而代理者模式是在编译时
lianJia= new HomeMaster();
)

代理对象提供与真实对象相同的接口,以便在任何时刻都能代替真实对象。同时,代理对象可以在执行真实对象操作时,附加其他的操作,相当于对真实对象进行封装。

/**
* 链家的公司业务是由销售完成
* 业务的完成依赖于链家这个平台
*/
public class Seller implements LianJia{
//声明链家公司(可理解为必须证明该seller是链家的),
private LianJia lianJia;
public Seller( ) {
//在编译时期确定, 也就是销售人员在售出前已经知道房屋的所有人
lianJia= new HomeMaster();
}
@Override
public void sellHouse() {
//销售人员通过链家平台向顾客销售房屋
lianJia.sellHouse();
}
}


1.4、客户端

对客户而言,并不知道这是主题角色(房屋所有者), 一切由销售搞定

public class Test {
public static void main(String[] args) {
//房屋由销售代理售出,购房的客户并不止到所购买的房屋是谁的,只是通过中间代理人(销售人员)看房,签合同
Seller seller =  new Seller();
seller.sellHouse();
}
}


而装饰者不同, 整个流程对客户透明的,客户知道这个业务流程,知道具体构件的附件功能实现。

public class Test {
public static void main(String[] args) {
Component component = new ConcreateComponent();//老子在吃饭...

Decorator da = new ConcreteDectratorA();
Decorator db = new ConcreteDectratorB();
//具体构件的原有功能
component.eat();
System.out.println();
//第一次装饰
da.setComponent(component);
da.eat();
System.out.println();
//第二次装饰
db.setComponent(da);
db.eat();

}
}


二、动态代理模式

动态代理是指在运行时动态生成代理类。即,代理类的字节码将在运行时生成并载入当前代理的 ClassLoader。与静态处理类相比,动态类有诸多好处。

不需要为真实主题写一个形式上完全一样的封装类,假如主题接口中的方法很多,为每一个接口写一个代理方法也很麻烦。
如果接口有变动,则真实主题和代理类都要修改,不利于系统维护;

使用一些动态代理的生成方法甚至可以在运行时制定代理类的执行逻辑,从而大大提升系统的灵活性。

生成动态代理的方法有很多: JDK中自带动态代理, CGlib, javassist等。这些方法各有优缺点。本文主要探究JDK中的动态代理的使用和源码分析。

JDK中自带动态代理 是利用反射

//主题接口
public interface Subject {
public abstract void sayHello();
public abstract void sayGooble();
}
//真实主题角色
public class RealSubject implements Subject{

@Override
public void sayHello() {
System.out.println("hello girls");
}
@Override
public void sayGooble() {
System.out.println("see you later!");
}
}


动态代理类

实现
java.lang.reflect.InvocationHandler
接口, 通过
method.invoke(realSubject, args);
调用真实主题角色中的方法

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
public class DynamicProxy implements InvocationHandler {
//真实主题角色的引用
private RealSubject realSubject  = null;
public DynamicProxy() {}
@Override
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable {
if (realSubject == null) {
//在编译时确定真实主题角色
realSubject = new RealSubject();
}
method.invoke(realSubject, args);
return realSubject;
}
}


客户端使用反射中静态方法
Proxy.newProxyInstance

newInstance方法有三个参数, 分别表示类加载器, 一个希望该代理类实现的接口列表, 以及实现InvokeHandler接口的实例。 动态代理将每个方法的执行过程则交给了Invoke方法处理

JDK动态代理要求, 被代理的必须是个接口, 单纯的类则不行。JDK动态代理所生成的代理类都会继承Proxy类,同时代理类会实现所有你传入的接口列表。因此可以强制类型转换成接口类型。所以返回的结果被强制转化为接口Subject.

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  设计模式 java