1. 程式人生 > >模式的秘密-代理模式(1)-靜態代理

模式的秘密-代理模式(1)-靜態代理

設計模式 print div 靜態代理 pub eight 方法 random 對象

代理模式:

為其他對象提供一種代理以控制對這個對象的訪問,代理對象起到了中介作用,可以去掉功能服務或者額外的服務。

以火車站買票為例子:

火車票代售處是火車站的代理,代售處可能不止可以賣火車票,還可以賣飛機票,但是不支持火車票退票功能,因此代售處起到了中介作用,

可以去掉功能服務或者額外的服務。

常見代理模式:遠程代理,虛擬代理,保護代理,智能引用代理。

智能引用代理

兩種實現方式:靜態代理,動態代理。

靜態代理:代理和被代理對象在代理之前是確定的。他們都實現相同的接口或者繼承相同的抽象類。

靜態代理分繼承方式和聚合方式兩種實現

技術分享圖片

實例:

通過代理,實現汽車行駛的方法,同時記錄汽車的行駛時間。

普通不使用設計模式實現方式

第一步:行駛接口:

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)-靜態代理