模式的秘密-代理模式(1)-靜態代理
代理模式:
為其他對象提供一種代理以控制對這個對象的訪問,代理對象起到了中介作用,可以去掉功能服務或者額外的服務。
以火車站買票為例子:
火車票代售處是火車站的代理,代售處可能不止可以賣火車票,還可以賣飛機票,但是不支持火車票退票功能,因此代售處起到了中介作用,
可以去掉功能服務或者額外的服務。
常見代理模式:遠程代理,虛擬代理,保護代理,智能引用代理。
智能引用代理
兩種實現方式:靜態代理,動態代理。
靜態代理:代理和被代理對象在代理之前是確定的。他們都實現相同的接口或者繼承相同的抽象類。
靜態代理分繼承方式和聚合方式兩種實現。
實例:
通過代理,實現汽車行駛的方法,同時記錄汽車的行駛時間。
普通不使用設計模式實現方式:
第一步:行駛接口:
package com.Proxy; public interface Moveable { void move(); }
第二步:實現汽車類:汽車類中實現行駛方法,裏面記錄行駛時間。
package com.Proxy; import java.util.Random; public class Car implements Moveable { @Override public void move() { long starttime=System.currentTimeMillis(); System.out.println("汽車開始形式...."); //實現開車 try { Thread.sleep(new Random().nextInt(1000)); System.out.println("汽車行駛中...."); } catch (InterruptedException e) { e.printStackTrace(); } long endtime=System.currentTimeMillis(); System.out.println("汽車結束行駛...汽車形式時間:"+(endtime-starttime)+"毫秒"); } }
第三步:測試:
package com.Proxy; public class Client { /* * 測試類 * */ public static void main(String[] args) { Car car=new Car(); car.move(); } }
運行結果:
汽車開始形式....
汽車行駛中....
汽車結束行駛...汽車形式時間:602毫秒
修改為靜態代理:
第一種靜態代理:以繼承的方式代理:
Car類修改為只有行駛方式:
package com.Proxy; import java.util.Random; public class Car implements Moveable { @Override public void move() { //實現開車 try { Thread.sleep(new Random().nextInt(1000)); System.out.println("汽車行駛中...."); } catch (InterruptedException e) { e.printStackTrace(); } } }
新建Car2類繼承Car類,通過super.方法()方式調用父類的方法,實現靜態代理。
同時在這個方法裏面實現記錄開車時間。
package com.Proxy; public class Car2 extends Car { @Override public void move() { long starttime=System.currentTimeMillis(); System.out.println("汽車開始形式...."); super.move(); long endtime=System.currentTimeMillis(); System.out.println("汽車結束行駛...汽車形式時間:"+(endtime-starttime)+"毫秒"); } }
測試:
package com.Proxy; public class Client { /* * 測試類 * */ public static void main(String[] args) { Moveable m=new Car2(); m.move(); } }
效果:
汽車開始形式....
汽車行駛中....
汽車結束行駛...汽車形式時間:497毫秒
第二種靜態代理:以聚合的方式實現代理:
聚合的方式其實就是在一個類中調用另一個類的對象,一般在構造方法裏面把另一個類的對象傳進來。
實現:
Car類和接口同上。
新建Car3繼承接口,同時在構造方法裏面把Car類對象傳進來。
package com.Proxy; /* * 以聚合方式代理:一個類中調用另一個類的對象 * */ public class Car3 implements Moveable{ private Car car; public Car3(Car car) { this.car=car; } @Override public void move() { long starttime=System.currentTimeMillis(); System.out.println("汽車開始形式...."); car.move(); long endtime=System.currentTimeMillis(); System.out.println("汽車結束行駛...汽車形式時間:"+(endtime-starttime)+"毫秒"); } }
測試:
package com.Proxy; public class Client { /* * 測試類 * */ public static void main(String[] args) { // 不使用代理方式 // Car car=new Car(); // car.move(); // //以繼承方式實現代理 // Moveable m=new Car2(); // m.move(); //以聚合方式實現代理 Car car=new Car(); Moveable m2=new Car3(car); m2.move(); } }
效果:
汽車開始形式....
汽車行駛中....
汽車結束行駛...汽車形式時間:200毫秒
繼承方式和聚合方式兩種比較:
如果此時代理類除了要實現汽車行駛方法,還可能需要實現其他功能的代理,比如權限管理,日誌處理。
1,對於繼承方式的代理來說:
如果我想先記錄汽車行駛時間,在記錄日誌,需要新建一個代理類。
假如此時我又想先記錄日誌,再記錄汽車行駛時間,此時又得新建一個代理類。
所以使用繼承方式不合適。
2,使用聚合方式就沒這個問題,代碼驗證:
這裏要實現兩種方式:即先記錄時間,再記錄日誌;和先記錄日誌,再記錄時間。
實現的方式就是,各個功能分別建立一個代理類,並且代理類的構造方法不僅能夠傳遞被代理類(Car),也能能夠把其他的代理類傳遞進來,
以此實現上述的兩種不同的實現方式。
代碼:
新建一個時間記錄代理類:
為了可以讓構造方法裏面的參數既可以是被代理的Car類,也可以是代理類。
package com.Proxy; //時間代理 public class CarTimeProxy implements Moveable{ private Moveable m; public CarTimeProxy(Moveable m) { this.m=m; } @Override public void move() { long starttime=System.currentTimeMillis(); System.out.println("汽車開始形式...."); m.move(); long endtime=System.currentTimeMillis(); System.out.println("汽車結束行駛...汽車形式時間:"+(endtime-starttime)+"毫秒"); } }
新建一個日誌記錄代理類:
package com.Proxy; //日誌代理 public class CarLogProxy implements Moveable{ private Moveable m; public CarLogProxy(Moveable m) { this.m=m; } @Override public void move() { System.out.println("日誌開始...."); m.move(); System.out.println("日誌結束...."); } }
新建測試類:測試類分別通過兩個代理類順序不同,把相關代理類傳遞給另一個代理類調用:
package com.Proxy; //聚合的代理模式,各個代理類直接可以互相傳遞,組合, public class Clien2 { public static void main(String[] args) { Car car=new Car(); // //先記錄日誌,再記錄時間 // CarTimeProxy ctp=new CarTimeProxy(car); // CarLogProxy clp=new CarLogProxy(ctp);//把時間代理傳進去,這時候日誌代理類代理了時間代理類 // clp.move(); //先記錄日誌,再記錄日誌,只需要調整一下代理類的順序 CarLogProxy clp2=new CarLogProxy(car); CarTimeProxy ctp2=new CarTimeProxy(clp2);//把時間代理傳進去,這時候日誌代理類代理了時間代理類 ctp2.move(); } }
模式的秘密-代理模式(1)-靜態代理