代理模式中存在代理者和被代理者,代理者和被代理者都具備相同的功能,而且代理者執行功能時會附加一些額外的操做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返回的也是接口的代理實例!!