一、代理模式的简介
1、代理模式的定义
代理模式是属于结构性模型,它为其他对象提供一种代理以控制对这种对象的访问。它是一个可以详细控制访问某个类(对象)的方法,在调用这个方法前作的前置处理。调用这个方法后做后置处理。
2、代理模式的分类
代理模式可分为两类,分别为静态代理和动态代理。其中,静态代理是需要静态定义代理类,是需要我们自己定义的。而动态代理是通过程序动态生成代理类,该代理类不是我们自己定义的,是由程序自动生成的。动态代理是可以代理多个目标对象,而静态代理则只能代理单一目标对象,且没有动态代理的效率高。
3、代理模式的作用
在某些情况下,一个对象不合适或者不能直接引用另一个对象,而代理对象可以在客户端和目标对象之间起到中介的作用。简单地说,代理模式就是多出来的一个代理类,替原来的对象进行一些操作。举个例子,租房的中介、明星的经纪人等等都是代理。之所以需要房屋中介,因为你对该地的地区房屋的信息掌握的不够全面,所以找个更加熟悉的房屋中介来做这些事,代理就是这个意思。下面的图是简单的关系图。
4、代理模式的优缺点
那使用代理模式的优缺点就显而易见了。其中优点是职责清晰、高扩展性,可以将功能划分的更加清晰,有助于后期维护。缺点就是对对象的请求速度会慢一些。
二、代理模式代码实现
1、静态代理模式
静态代理模式一般会有三个角色:
抽象角色:指代理角色(经纪人)和真实角色(明星)对外提供的公共方法,一般为一个接口
真实角色:需要实现抽象角色接口,定义了真实角色所要实现的业务逻辑,以便供代理角色调用。也就是真正的业务逻辑在此。
代理角色:需要实现抽象角色接口,是真实角色的代理,通过真实角色的业务逻辑方法来实现抽象方法,并可以附加自己的操作。
在代理模式中我们是将统一的流程控制都放到代理角色中处理的。下面是静态代理模式结构图
我们这里通过模拟明星的经纪人来阐述静态代理模式的作用。我们定义一个抽象角色接口(Star)、代理角色实现(ProxyStar)、真实角色实现(RealStar)。
抽象角色接口:提供了与明星合作的一系列流程
package proxy.staticProxy;
/* 抽象角色:提供代理角色和真实角色对外提供的公共方法*/ public interface Star { void confer();//面谈 void signContract();//签合同 void bookTicket();//订票 void playShow();//表演 void collectMoney();//收尾款 }
代理角色实现类:代理角色中代理了真实角色所需要的操作(表演)
package proxy.staticProxy;
/*代理角色(明星经纪人):*/ public class ProxyStar implements Star{ private Star star;//真实对象的引用(明星) /*@Override*/ public void confer() { System.out.println("ProxyStar.confer()"); } /*@Override*/ public void signContract() { System.out.println("ProxyStar.signContract()"); } /*@Override*/ public void bookTicket() { System.out.println("ProxyStar.bookTicket()"); } /*@Override*/ public void playShow() { star.playShow();//真实对象的操作(明星表演) } /*@Override*/ public void collectMoney() { System.out.println("ProxyStar.collectMoney()"); } public ProxyStar(Star star) {//通过构造器给真实角色赋值 this.star = star; } }
真实角色实现类:这里的真实角色中其实只做了一个唱歌的操作,这是真实角色真正的业务逻辑部分
package proxy.staticProxy; /* 真实角色(明星艺人):*/public class RealStar implements Star{ /*@Override*/ public void confer() { System.out.println("RealStar.confer()"); } /*@Override*/ public void signContract() { System.out.println("RealStar.signContract()"); } /*@Override*/ public void bookTicket() { System.out.println("RealStar.bookTicket()"); } /*@Override*/ public void playShow() { System.out.println("周杰伦.playShow()");//真实角色的操作:真正的业务逻辑 } /*@Override*/ public void collectMoney() { System.out.println("RealStar.collectMoney()"); }
}
测试代理类:
public static void main(String[] args) { Star real = new RealStar(); Star proxy = new ProxyStar(real); proxy.confer(); proxy.signContract(); proxy.bookTicket(); proxy.palyShow();//真实对象的操作(明星表演) proxy.collectMoney(); }
输出结果为:
ProxyStar.confer()
ProxyStar.signContract()
ProxyStar.bookTicket()
周杰伦.playShow() //这里是真实角色的业务逻辑处理
ProxyStar.collectMoney()
2、动态代理模式
动态代理是不需要定义代理角色的,通过一个处理器来处理代理角色的业务逻辑。
抽象角色接口:提供了与明星合作的一系列流程
package proxy.staticProxy; /* 抽象角色:提供代理角色和真实角色对外提供的公共方法*/ public interface Star { void confer();//面谈 void signContract();//签合同 void bookTicket();//订票 void playShow();//表演 void collectMoney();//收尾款 }
真实角色实现类:这里的真实角色中其实只做了一个唱歌的操作,这是真实角色真正的业务逻辑部分
package proxy.staticProxy; /* 真实角色(明星艺人):*/ public class RealStar implements Star{ /*@Override*/ public void confer() { System.out.println("RealStar.confer()"); } /*@Override*/ public void signContract() { System.out.println("RealStar.signContract()"); } /*@Override*/ public void bookTicket() { System.out.println("RealStar.bookTicket()"); } /*@Override*/ public void playShow() { System.out.println("周杰伦.playShow()");//真实角色的操作:真正的业务逻辑 } /*@Override*/ public void collectMoney() { System.out.println("RealStar.collectMoney()"); } }
代理角色的处理器:
package proxy.dynamicProxy; import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; /* 处理器 */ public class StarHandler implements InvocationHandler{ private Star realStar;//真实角色 /** * 所有的流程控制都在invoke方法中 * proxy:代理类 * method:正在调用的方法 * args:方法的参数 */ /*@Override*/ public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { Object object = null; System.out.println("真实角色调用之前的处理....."); if (method.getName().equals("playShow")) { object = method.invoke(realStar, args);//激活调用的方法 } System.out.println("真实角色调用之后的处理....."); return object; } /*通过构造器来初始化真实角色*/ public StarHandler(Star realStar) { super(); this.realStar = realStar; } }
测试代理模式:
public static void main(String[] args) { //真实角色 Star realStar = new RealStar(); //处理器 StarHandler handler = new StarHandler(realStar); //代理类 Star proxy = (Star) Proxy.newProxyInstance(ClassLoader.getSystemClassLoader(), new Class[]{Star.class}, handler); proxy.playShow();//调用代理类的唱歌方法:其实调用的是真实角色的表演方法
三、实例分析
-
引入代理模式后对系统架构和代码结构带来的好处:在某些情况下,一个对象不合适或者不能直接引用另一个对象,而代理对象可以在客户端和目标对象之间起到中介的作用,可以替原来的对象进行一些操作。并且他可以在在客户端与目标对象之间起到一个中介作用和保护目标对象的作用。并且扩展性很高,可以将功能划分的更加清晰,有助于后期维护。
-
其中用到的多态机制和模块抽象封装的方法:代理角色实现类和真是角色实现类传递都实现了角色抽象接口Star。并单独封装成不同的类,这就可以在客户端与目标对象之间起到一个中介作用和保护目标对象的作用。并且可以扩展,可以将功能划分的更加清晰,有助于后期维护。这也是引用模式的优势所在。
-
模块之间的耦合度:由于代理模式能将客户端与目标对象分离,在一定程度上降低了系统的耦合度。