設計模式之代理模式(proxy pattern)

alpha_panda發表於2019-05-31

代理模式的本質是一箇中介軟體,主要目的是解耦合服務提供者和使用者。使用者通過代理間接的訪問服務提供者,便於後者的封裝和控制。是一種結構性模式。

1.目的

為外部呼叫者提供一個訪問服務提供者的代理物件。

2.動機

限制對目標物件的直接訪問,降低耦合度。

3.優缺點

優點:

優點: 

  • 低耦合
  • 易擴充套件
  • 靈活度高

缺點:

  • 間接訪問可能會延遲請求相應
  • 增加工作量

4.分類

  • 靜態代理
  • 動態代理

  代理類本身的實現可能並不簡單,加上每一個需要代理的物件均均需要實現一個代理類,其工作量本身比較大,易出錯。

  所謂動態代理(DynamicProxy)是指在程式執行時動態的生成對目標物件的訪問介面。

  本文主要介紹前者,關於後者可以參考JDK自帶的動態代理。

5.主要用途

代理模式在以下場景比較適用:

     1、遠端代理。 2、虛代理。 3、保護代理。4、智慧指引代理。5、寫時複製(Copy-on-Write)代理。  6、快取代理。 7、防火牆代理。 8、同步化代理。

6.原理

下面是GoF介紹典型的代理模式UML類圖

Subject:

 定義RealSubject對外的介面,且這些介面必須被Proxy實現,這樣外部呼叫proxy的介面最終都被轉化為對realsubject的呼叫。

RealSubject:

 真正的目標物件。

Proxy:

 目標物件的代理,負責控制和管理目標物件,並間接地傳遞外部對目標物件的訪問。

  1. Remote Proxy: 對本地的請求以及引數進行序列化,向遠端物件傳送請求,並對響應結果進行反序列化,將最終結果反饋給呼叫者;
  2. Virtual Proxy: 當目標物件的建立開銷比較大的時候,可以使用延遲或者非同步的方式建立目標物件;
  3. Protection Proxy: 細化對目標物件訪問許可權的控制;

7.實現

 下面我們使用兩個例子來實際體驗一下代理模式的應用

網路代理

對於一些國內不能直接訪問的網站,合法的使用的網路代理可以實現對目標網站的訪問;

定義公共介面類Server:

public interface Server{
    void visit(String url);
}

  代理伺服器ProxyServer:

public class ProxyServer implements Server{
 
   private RealServer realServer;
 
   public ProxyServer(String serverName){
      this.realServer = new RealServer(serverName);
   }
 
   @Override
   public void visit(String url) {
      realServer.visit(url);
   }
}

  目標伺服器RealServer:

public class RealServer implements Server {
    private String serverName;
    public RealServer(String serverName) {
        this.serverName = serverName;
        System.out.println("This is " + serverName);
    }
    
    @Override
    public void visit(String url) {
        response(url);
    }
    
    private void response(String res) {
        System.out.println("This is response of " + res + " from server:" + serverName);
    }
}

 演示:

public class Demo {
    public static void main(String[] args) {
        Server server = new ProxyServer("www.google.com");
        server.visit("map.google.com");
    }
}

智慧指標引用計數

下面使用代理模式簡單的模擬指標引用計數問題

介面類Obj:

public interface Obj{
    void GetAttr();
    Obj copy();
    void delete();
}

  智慧指標類SmartPointer:

public class SmartPointer implements Obj{
 
   private RealObj realObj;
   private int counter = 1;
 
   public SmartPointer(String objType){
      this.realObj = new RealObj(objType);
   }
   
   @Override
   public void GetAttr() {
       if(counter > 0) {
           realObj.GetAttr();
       }
       System.out.println("Smart Ref: " + counter);
   }
       
    public Obj copy() {
        if(counter > 0) {
            counter += 1;
            return this;
        }
        System.out.println("Invalid Pointer!");
        return null;
    }
    
    public void delete() {
        if(counter > 0) {
            counter -= 1;
            if(0 == counter) {
                realObj = null;
            }
        }
        else {
            System.out.println("Invalid Pointer!");
        }
    }
}
View Code

 被引用物件類RealObj:

public class RealObj implements Obj {
    private String objType;
    public RealObj(String objType) {
        this.objType = objType;
        System.out.println("Create Obj: " + objType);
    }
    
    @Override
    public void GetAttr() {
        System.out.println("get attr of real obj " + objType);
    }

    @Override
    public Obj copy() {
        // TODO Auto-generated method stub
        return null;
    }

    @Override
    public void delete() {
        // TODO Auto-generated method stub
        
    }
}
View Code

 參考:

GoF《Design Patterns: Elements of Reusable Object-Oriented Software》

https://www.runoob.com/design-pattern/proxy-pattern.html

相關文章