AOP(Aspect Oriented Programming)並無創造或使用新的技術,其底層就是基於代理模式實現。所以咱們先來學習一下代理模式。java
代理模式,爲對象提供一種代理,以控制對這個對象的訪問。spring
代理模式也稱爲委託模式,通常有如下三個角色
設計模式
這裏咱們先按照基本概念中內容,完成一個簡單代理模式的基本實現。設想這樣一個場景:明星與經紀人。經紀人幫明星與外界洽談合做,簽定合同,計算佣金;明星完成演戲、唱歌等工做。
首先定義一個Actor.javaide
package com.leng.proxy; /** * @Classname Actor * @Date 2020/9/12 23:30 * @Autor lengxuezhang */ public interface Actor { /** * 演戲 */ public void act(); /** * 唱歌 */ public void sing(); }
藝人通常須要會唱歌和演戲。
接着分別實現明星類,實現Actor接口,並傳入姓名。函數
package com.leng.proxy; /** * @Classname Star * @Date 2020/9/12 23:32 * @Autor lengxuezhang */ public class Star implements Actor { private String name; public Star(String name) { this.name = name; } @Override public void act() { System.out.println(name + "在演戲"); } @Override public void sing() { System.out.println(name + "在唱歌"); } }
最後實現經紀人學習
package com.leng.proxy; /** * @Classname Agent * @Date 2020/9/12 23:36 * @Autor lengxuezhang */ public class Agent implements Actor { private Actor actor = null; // 要想實現經紀人代理明星,須要將被代理類對象傳遞給代理類 public Agent(Actor actor) { this.actor = actor; } @Override public void act() { this.before(); // 實際調用的是明星的act(),經紀人接活,但最後去演戲的確定是明星本身 actor.act(); this.after(); } @Override public void sing() { this.before(); actor.sing(); this.after(); } // 預處理方法 private void before() { System.out.println("談好價錢,簽好合同"); } // 後處理方法 private void after() { System.out.println("清算演出費,和明星分錢"); } }
客戶端調用Client.java:測試
package com.leng; import com.leng.proxy.Agent; import com.leng.proxy.Star; /** * @Classname Client * @Date 2020/9/12 2:40 * @Autor lengxuezhang */ public class Client { public static void main(String[] args) { Star star = new Star("劉德華"); Agent agent = new Agent(star); agent.act(); agent.sing(); } }
運行結果:this
談好價錢,簽好合同
劉德華在演戲
清算演出費,和明星分錢
談好價錢,簽好合同
劉德華在唱歌
清算演出費,和明星分錢設計
小結:代理
明星的工做通常比較忙,沒有時間和外界有太多溝通和接觸。導演想要找明星演戲,通常只能先去聯繫他的公司經紀人,是聯繫不到明星本人。「導演只能聯繫到經紀人,而不能聯繫明星」,這樣的模式就被稱爲「普通代理」。換句話說:普通代理模式下,客戶端只能訪問代理類,不能訪問被代理類。
上面的Client.java中,直接new了一個明星對象,這就算是直接訪問了被代理類,不能稱爲普通代理。那如何才能實現普通代理呢。關鍵是讓被代理類的建立只能由代理類來完成。修改代碼以下:
只須要修改構造函數
package com.leng.proxy; /** * @Classname Star * @Date 2020/9/12 23:32 * @Autor lengxuezhang */ public class Star implements Actor { private String name; public Star(Agent agent, String name) throws Exception { // 必須是經紀人才能建立明星 if(agent == null) { throw new Exception("非經紀人,不能創造明星"); } else { this.name = name; } } @Override public void act() { System.out.println(name + "在演戲"); } @Override public void sing() { System.out.println(name + "在唱歌"); } }
package com.leng.proxy; /** * @Classname Agent * @Date 2020/9/12 23:36 * @Autor lengxuezhang */ public class Agent implements Actor { private Actor actor = null; // 告訴agent,我須要聯繫哪個"明星" public Agent(String name) { try { this.actor = new Star(this, name); } catch (Exception e) { System.out.println("建立agent異常"); } } @Override public void act() { this.before(); actor.act(); this.after(); } @Override public void sing() { this.before(); actor.sing(); this.after(); } // 預處理方法 private void before() { System.out.println("談好價錢,簽好合同"); } // 後處理方法 private void after() { System.out.println("清算演出費,和明星分錢"); } }
客戶端類在使用時,也須要作修改,此時客戶端能夠不直接訪問Star
package com.leng; import com.leng.proxy.Agent; /** * @Classname Client * @Date 2020/9/12 2:40 * @Autor lengxuezhang */ public class Client { public static void main(String[] args) { Agent agent = new Agent("劉德華"); agent.act(); agent.sing(); } }
運行結果:
談好價錢,簽好合同
劉德華在演戲
清算演出費,和明星分錢
談好價錢,簽好合同
劉德華在唱歌
清算演出費,和明星分錢
能夠看到運行結果並無發生改變,但確實已經實現了只能以訪問代理類方式訪問非代理類。假如客戶端直接訪問代理類的話,是會拋出異常的。
普通代理模式的優勢:
先來看一個場景:
王晶想找華仔拍戲,兩人老相識了,因而王晶直接打電話問華仔:「華仔啊,有咩時間?搵你拍片喔"」。
華仔回覆:「你先找個人經紀人談一下吧,看一下個人工做安排」。
而後華仔給王晶本身經紀人的聯繫方式,王晶和經紀人談好以後,華仔就準備去拍王晶的電影了。
這個場景裏有個點,首先王晶其實是不能直接找華仔拍戲,即便有聯繫方式,華仔也不必定給你拍;其次是王晶必須與華仔指定的經紀人溝通具體的拍戲工做。
強制代理的要求是:
public interface Actor { ... public Actor getProxy(); }
明星類實現該方法,一方面要找到本身的代理,另外一方面其它的唱歌、演戲方法也須要檢查是不是本身指定的代理類訪問的。
package com.leng.proxy; /** * @Classname Star * @Date 2020/9/12 23:32 * @Autor lengxuezhang */ public class Star implements Actor { private String name; private Agent agent = null; public Star(String name) { this.name = name; } @Override public void act() { if (isProxy()) { System.out.println(name + "在演戲"); } else { System.out.println("請使用指定的代理訪問"); } } @Override public void sing() { if (isProxy()) { System.out.println(name + "在唱歌"); }else { System.out.println("請使用指定的代理訪問"); } } @Override public Actor getProxy() { this.agent = new Agent(this); return this.agent; } /** * 判斷是不是指定的代理 * @return */ private boolean isProxy() { if(agent == null) { return false; } return true; } }
經紀人類
package com.leng.proxy; /** * @Classname Agent * @Date 2020/9/12 23:36 * @Autor lengxuezhang */ public class Agent implements Actor { private Actor actor = null; // 告訴agent,我須要聯繫哪個"明星" public Agent(Actor actor) { this.actor = actor; } @Override public void act() { this.before(); actor.act(); this.after(); } @Override public void sing() { this.before(); actor.sing(); this.after(); } @Override public Actor getProxy() { //經紀人沒有本身的經紀人,因此就返回本身 return this; } // 預處理方法 private void before() { System.out.println("談好價錢,簽好合同"); } // 後處理方法 private void after() { System.out.println("清算演出費,和明星分錢"); } }
如今來測試一下,首先看看若是直接訪問被代理類,是否可行
public class Client { public static void main(String[] args) { Star star = new Star("劉德華"); star.act(); star.sing(); } }
運行結果:
請使用指定的代理訪問 請使用指定的代理訪問
顯然訪問失敗了。接下來嘗試一下若是經過代理類訪問呢
package com.leng; import com.leng.proxy.Actor; import com.leng.proxy.Agent; import com.leng.proxy.Star; /** * @Classname Client * @Date 2020/9/12 2:40 * @Autor lengxuezhang */ public class Client { public static void main(String[] args) { Actor star = new Star("劉德華"); Actor agent = new Agent(star); agent.act(); agent.sing(); } }
談好價錢,簽好合同
請使用指定的代理訪問
清算演出費,和明星分錢
談好價錢,簽好合同
請使用指定的代理訪問
清算演出費,和明星分錢
能夠看到中間業務邏輯部分仍是錯誤的。ok,那我就按照強制代理的規定來:
package com.leng; import com.leng.proxy.Actor; import com.leng.proxy.Star; /** * @Classname Client * @Date 2020/9/12 2:40 * @Autor lengxuezhang */ public class Client { public static void main(String[] args) { // 先定義一個明星 Actor star = new Star("劉德華"); // 由這個明星指定經紀人 Actor agent = star.getProxy(); agent.act(); agent.sing(); } }
談好價錢,簽好合同
劉德華在演戲
清算演出費,和明星分錢
談好價錢,簽好合同
劉德華在唱歌
清算演出費,和明星分錢
運行結果顯示成功。
小結:強制代理的核心就是經過被代理類指定的代理類,去訪問被代理類的方法。
本篇文章首先介紹了代理模式的基本概念和基本代碼實現。而後進行了一些擴展,介紹了普通代理和強制代理的概念和實現。下一篇將會詳細介紹動態代理的知識。
參考文獻 《設計模式之禪》