代理模式中存在代理者和被代理者,代理者和被代理者都具备相同的功能,而且代理者执行功能时会附加一些额外的操做java
如:手机工厂和代理商都具备卖东西的功能,手机代理商除了帮工厂卖手机外,还能在卖手机前打广告推销,卖手机后还能够进行售后服务。编程
代理模式的优势:this
符合开闭原则,不用修改被代理者任何的代码,就能扩展新的功能编码
项目的扩展和维护比较方便代理
角色分析:调试
这里使用一个租房中介的案例:code
抽象角色(接口):租房对象
//租房 public interface Rent { void rent(); }
真实角色:房东blog
//房东 public class Host implements Rent{ public void rent() { System.out.println("房东要出租房"); } }
代理角色:中介所(一般包含附属的一些其余方法)继承
//代理类 public class Agent implements Rent{ //组合因为继承 private Host host; public void setHost(Host host) { this.host = host; } public void rent(){ host.rent(); this.sign(); this.fare(); } //签合同 public void sign(){ System.out.println("中介签合同"); } //中介费 public void fare(){ System.out.println("收取中介费"); } }
客户端访问代理角色:
public class Client { public static void main(String[] args) { Host host = new Host(); Agent agent = new Agent(); agent.setHost(host); agent.rent(); } }
静态代理模式的好处:
缺点:
静态代理只能适合一种业务,若是有新的业务,就必须建立新的接口和新的代理
每一个真实角色就会产生一个代理角色,代码量会翻倍;
AOP(面向切面编程)的实现原理就是代理模式:
1.对于切面织入的实现就是对业务接口建立了一个代理类,
2.代理类中组合了业务接口的实现类,
3.代理类在原先实现类的方法上添加了一些附属方法,
4.客户端访问时即能使用代理类的业务(包括初始业务以及拓展业务)。
这样就实现了对切面的织入,不须要改变原有代码而拓展了新的业务,符合开闭原则;
动态代理的实现基于反射机制
角色和静态代理相同
动态代理的代理类是动态生成的,而不是直接写好的
动态代理分为两大类:基于接口的动态代理;基于类的动态代理
须要了解两个类:
Proxy:代理
Proxy
提供了建立动态代理类和实例的静态方法,它也是由这些方法建立的全部动态代理类的超类。InvocationHandler接口:调用处理程序
InvocationHandler
是由代理实例的调用处理程序实现的接口。
每一个代理实例都有一个关联的调用处理程序。 当在代理实例上调用方法时,方法调用将被编码并分派到其调用处理程序的invoke
方法。
动态代理的特色:(在静态代理的基础上)
java代码实现
须要被代理的接口:
public interface UserService { void add(); void delete(); void update(); void query(); }
真实角色(实现类):
public class UserServiceImpl implements UserService { public void add() { System.out.println("add"); } public void delete() { System.out.println("delete"); } public void update() { System.out.println("update"); } public void query() { System.out.println("query"); } }
生成代理对象的调试处理类:
//这个类用于自动生成代理类 public class ProxyInvocationHandler implements InvocationHandler { //被代理的接口 private Object target; public void setUserService(UserService userService) { this.target = userService; } //生成获得代理类 public Object getProxy(){ return Proxy.newProxyInstance(this.getClass().getClassLoader(),target.getClass().getInterfaces(),this); } //处理代理实例,返回结果 public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { //经过反射获得调用的方法名 log(method.getName()); //调用方法 return method.invoke(target,args); } //代理类的一些附属方法 public void log(String s){ System.out.println("调用了"+s+"方法"); } }
客户端:
public class Client { public static void main(String[] args) { //真实类 UserServiceImpl userService = new UserServiceImpl(); //动态生成代理角色的处理类 ProxyInvocationHandler pih = new ProxyInvocationHandler(); //设置要代理的对象 pih.setUserService(userService); //生成代理实例 UserService proxy = (UserService) pih.getProxy(); // **当调用被代理角色的方法时,会经过反射机制调用代理类中的invoke方法 proxy.query(); } }
运行结果:
调用了query方法 query
重点:代理对象必须是接口,以及proxy返回的也是接口的代理实例!!