設計模式之代理模式(Proxy)(2)

来源:https://www.cnblogs.com/CIreland/archive/2018/07/29/9385827.html
-Advertisement-
Play Games

代理模式是為其他對象提供一種代理以控制對這個對象的訪問。在某些情況下,一個對象不適合或者不能直接引用另一個對象,而代理對象可以在客戶端和目標對象之間起到中介的作用,其特征是代理類與委托類有同樣的介面。 動機: 在軟體設計中,使用代理模式的意圖也很多,比如因為安全原因需要屏蔽客戶端直接訪問真實對象,或 ...


代理模式是為其他對象提供一種代理以控制對這個對象的訪問。在某些情況下,一個對象不適合或者不能直接引用另一個對象,而代理對象可以在客戶端和目標對象之間起到中介的作用,其特征是代理類與委托類有同樣的介面。

動機:

在軟體設計中,使用代理模式的意圖也很多,比如因為安全原因需要屏蔽客戶端直接訪問真實對象,或者在遠程調用中需要使用代理類處理遠程方法調用的技術細節 (如 RMI),也可能為了提升系統性能,通過控制來延遲對象的創建和實例化,直到真正需要使用該對象才進行創建和實例化。

由於一些對象創建和實例化需要占用大量系統資源,但我們並不能確定用戶一定會調用該對象,所以通過延遲對象實例化來減緩系統資源的消耗。例如文檔編輯器如word,我們可以在裡面插入鏈接、圖片等,但是並不是我們每次打開word時都有創建和實例化這些對象,特別是實例化圖片對象很消耗資源,並不需要實例化所有圖片。當我們在查看word時,只是看到其中的一部分,所以沒有必要實例化所以資源,當我們看下一頁時再實例化也不遲。

類型:結構類模式

類圖:

代理模式類圖

圖1 代理模式類圖

代理模式角色:

1) 主題介面:定義代理類和真實主題的公共對外方法,也是代理類代理真實主題的方法;

2) 真實主題:真正實現業務邏輯的類;

3) 代理類:用來代理和封裝真實主題;

4) Main:客戶端,使用代理類和主題介面完成一些工作。

優點:

  •  對客戶端來說,隱藏了真實對象的細節及複雜性。
  •  將代理對象與真正被調用的對象分離,在一定程度上降低了系統的耦合度。
  •  在客戶端和目標對象之間起到一個中介作用,這樣可以起到保護目標對象的作用,也可以對目標對象調用之前進行其他操作。
  •  遠程代理使得客戶端可以訪問在遠程機器上的對象,遠程機器可能具有更好的性能與處理速度,可以快速響應並處理客戶端請求。
  •  虛擬代理通過使用一個小對象來代表一個大對象,可以減少系統資源的消耗,對系統進行優化並提高運行速度。
  •  安全代理可以控制對真實對象的使用許可權。

缺點:

  •  在客戶端和目標對象增加一個代理對象,會造成請求處理速度變慢。
  •  增加了系統的複雜度。

適用場景

1) 遠程代理:也就是為一個對象在不同的地址空間提供局部代表,這樣可以隱藏一個對象存在於不同地址空間的事實。比如說 WebService,當我們在應用程式的項目中加入一個 Web 引用,引用一個 WebService,此時會在項目中聲稱一個 WebReference 的文件夾和一些文件,這個就是起代理作用的,這樣可以讓那個客戶端程式調用代理解決遠程訪問的問題。還有.NET的WCF的遠程代理。

2) 虛擬代理:是根據需要創建開銷很大的對象,通過它來存放實例化需要很長時間的真實對象。這樣就可以達到性能的最優化,比如打開一個網頁,這個網頁裡面包含了大量的文字和圖片,但我們可以很快看到文字,但是圖片卻是一張一張地下載後才能看到,那些未打開的圖片框,就是通過虛擬代理來替換了真實的圖片,此時代理存儲了真實圖片的路徑和尺寸。

3) 安全代理:用來控制真實對象訪問時的許可權。一般用於對象應該有不同的訪問許可權的時候。

4) 指針引用:是指當調用真實的對象時,代理處理另外一些事。比如計算真實對象的引用次數,這樣當該對象沒有引用時,可以自動釋放它,或當第一次引用一個持久對象時,將它裝入記憶體,或是在訪問一個實際對象前,檢查是否已經釋放它,以確保其他對象不能改變它。這些都是通過代理在訪問一個對象時附加一些內務處理。

5) 智能指引:當調用真實對象時,代理提供一些額外的操作。如將對象被操作的次數記錄起來等。

6) 延遲載入,用代理模式實現延遲載入的一個經典應用就在 Hibernate 框架裡面。當 Hibernate 載入實體 bean 時,並不會一次性將資料庫所有的數據都裝載。預設情況下,它會採取延遲載入的機制,以提高系統的性能。Hibernate 中的延遲載入主要分為屬性的延遲載入和關聯表的延時載入兩類。實現原理是使用代理攔截原有的 getter 方法,在真正使用對象數據時才去資料庫或者其他第三方組件載入實際的數據,從而提升系統性能。

7) 緩衝代理:為某一個目標操作提供臨時的存儲空間,以便更多客戶端共用此結果。

8) 防火牆代理:保護目標不讓惡意用戶接近。

9) 同步化代理:使幾個用戶能同時使用一個對象而沒有衝突。

代理模式分類

1. 靜態代理(靜態定義代理類,自己靜態定義的代理類)

1)優點

可以做到在不修改目標對象的功能前提下,對目標功能擴展。

2)缺點

因為代理對象需要與目標對象實現一樣的介面,所以會有很多代理類,類太多。同時,一旦介面增加方法,目標對象與代理對象都要維護。

3)靜態代理模式角色:

  •  抽象角色:指代理角色和真實角色對外提供的公共方法,一般為一個介面。
  •  真實角色:需要實現抽象角色介面,定義了真實角色所要實現的業務邏輯,以便供代理角色調用,真正的業務邏輯在此。
  •  代理角色:需要實現抽象角色介面,是真實角色的代理,通過真實角色的業務邏輯方法來實現抽象方法,並可以附加自己的操作。將統一的流程式控制制都放到代理角色中處理。

代碼實現:

JAVA

//介面
public interface IClient {
    void appeal();//談判
}
/**
 * 介面實現
 * 目標對象
 */
public class Client implements IClient {
    public void appeal()
    {
        System.out.println("委托人談判");
        
    }
}
/**
 * 代理對象,靜態代理
 */
public class ClientProxy implements IClient {
    private Client client;
    public ClientProxy(Client client)
    {
        this.client=client;        
    }
    public void appeal()
    {
        System.out.println("代理談判開始!");
        client.appeal();
        System.out.println("代理談判結束!");
    }
}
public class AppTest {
    public static void main(String[] args) {
        // TODO Auto-generated method stub
        //目標對象
        Client target = new Client();
        //代理對象,把目標對象傳給代理對象,建立代理關係
        ClientProxy proxy = new ClientProxy(target);
        proxy.appeal();//執行的是代理的方法
    }
}

輸出結果:

clip_image003

C#

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace proxyDemo
{ // 客戶端調用
    class Program
    {
        static void Main(string[] args)
        {
            // 創建一個代理對象併發出請求
            Person proxy = new Friend();
            proxy.Appeal();
            Console.Read();
        }
    }    
    // 抽象主題角色
    public abstract class Person
    {
        public abstract void Appeal();
    }
    //真實主題角色:委托人
    public class Client : Person
    {
        public override void Appeal()
        {
            Console.WriteLine("委托人談判中……");
        }
    }
    // 代理角色:律師
    public class Friend : Person
    {
        // 引用真實主題實例
        Client client;
        public override void Appeal()
        {
            Console.WriteLine("律師代理談判……");
            if (client == null)
            {
                client = new Client();
            }
            this.PreAppeal();
            // 調用真實主題方法
            client.Appeal();
            this.PostAppeal();
        }
        public void PreAppeal()
        {
            Console.WriteLine("談判開始~");
        }
        public void PostAppeal()
        {
            Console.WriteLine("談判結束!");
        }
    }
}
View Code

 

輸出結果:

clip_image004

2. 動態代理(通過程式動態生成代理類,該代理類不是自己定義的。而是由程式自動生成)

特點:

  •  代理對象不需要實現介面
  •  代理對象的生成,是利用JDK的API,動態的在記憶體中構建代理對象(需要我們指定創建代理對象/目標對象實現的介面的類型)
  •  動態代理也叫做:JDK代理,介面代理

基本原理:

通過掃描被代理類的所有 public 方法,並且自動生成一個從被代理類繼承的類,然後在這個生成的類中 override 這些 public 方法。這裡說的自動生成,並不是生成源代碼,而是直接使用中間語言(Intermedial Language)直接在記憶體中生成。這樣在速度上和源碼編譯而成的中間語言相近,可以利用 Reflection Emit API 來直接生成中間語言。

代碼實現:

JAVA

public interface IClient {
    void appeal();//談判
}
/**
 * 介面實現
 * 目標對象
 */
public class Client implements IClient {
    public void appeal()
    {
        System.out.println("委托人談判");
    }
}
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
/**
 * 處理器
 */
public class ClientHandler implements InvocationHandler{
    private IClient client;//真實角色
    /**
     * 所有的流程式控制制都在invoke方法中
     * proxy:代理類
     * method:正在調用的方法
     * args:方法的參數
     */
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        Object object = null;
        System.out.println("律師動態調用之前的處理.....");
                     if (method.getName().equals("appeal")) {
            object = method.invoke(client, args);//激活調用的方法   
        }
        System.out.println("律師動態調用之後的處理.....");
        return object;
    }
    //通過構造器來初始化真實角色
    public ClientHandler(IClient client) {
        super();
        this.client = client;
    }
}
import java.lang.reflect.Proxy;
public class MainTest {
    public static void main(String[] args) {
                // TODO Auto-generated method stub
                 // 目標對象
        IClient target = new Client();
        // 【原始的類型 class cn.itcast.b_dynamic.UserDao】
        System.out.println(target.getClass());
      //處理器
        ClientHandler handler = new ClientHandler(target);
        // 給目標對象,創建代理對象
        IClient proxy = (IClient) Proxy.newProxyInstance(ClassLoader.getSystemClassLoader(), new Class[]{IClient.class}, handler);
        // class $Proxy0   記憶體中動態生成的代理對象
        System.out.println(proxy.getClass());
        // 執行方法   【代理對象】
        proxy.appeal();
    }
}
View Code

輸出結果:

clip_image005


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • webpack4.x css壓縮,optimize-css-assets-webpack-plugin mini-css-extract-plugin ...
  • 1、 JavaScript(弱類型語言):是一種描述性語言,也是一種基於對象(Object)和事件驅動(Event Driven)的,並具有安全性能的腳本語言。 特點:1、主要用來在HTML頁面中添加交互行為。 2、是一種腳本語言,語法和Java類似。 3、一般用於編寫客戶端的腳本。 4、是一種解釋 ...
  • 因為項目有可能用到, 所以學習了一下,做此筆記,圖截自慕課網,侵刪。 一、基本圖形 1、矩形 x,y定義矩形的左上角坐標; width,height定義矩形的長度和寬度; rx,ry定義矩形的圓角半徑長度,這裡註意,如果rx給值了ry沒給值,ry沿用rx的值,反之同理; 2、圓形 cx與cy定義圓心 ...
  • 在移動端使用時間選擇器的時候,選擇了一個時間轉換為時間戳,谷歌瀏覽器以及安卓手機使用 new Dare( 選擇的時間 ).getTime() 都能夠拿到時間戳, 但是在ios手機上會出現出現NAN 查閱資料後發現是因為ios不能解析 2018-7-26 這種格式的時間字元串,只能解析 2018/7/ ...
  • 日常中工作中我並沒有對kafka接觸很多,但瞭解到很多的框架都和kafka有著緊密的關係。比如rockmetmq是參考了kafka的設計,neflix的緩存組件ehcache是用kafka做數據的同步。同時kafka在大數據方面通常和spark,hadoop,storm一起使用,所以我對kafka也 ...
  • 用歷史觀來看一種技術的演進,稱之為“技術血脈”。 十年前,靜兒做的是傳統軟體的項目,都是企業定製的項目,系統安裝在企業的機器上,通過硬體來做物理隔離。系統的安全訪問控制靠操作系統來保證。 在互聯網大潮中,B/S逐漸流行,對於這類從傳統軟體轉化來的項目,一般採用的是用戶名密碼登陸的鑒權方式。為了對用戶 ...
  • Python gRPC 概述: gRPC 是谷歌開源的一個rpc(遠程程式調用)框架,可以輕鬆實現跨語言,跨平臺編程,其採用gRPC協議(基於HTTP2)。 rpc: remote procedure call, 翻譯過來就是是遠程程式調用。具體來說,就是客戶端c1需要調用伺服器s1上的某個方法(函 ...
  • 一、前言 前後端分離開發是將項目開發工作前後端交互工作拆分,使前端開發人員能夠專註於頁面開發或APP 開發,後端開發人員專註與介面開發、業務邏輯開發。 此處開發後端項目,給前端或者APP 端提供介面。不涉及複雜的業務邏輯,通過簡單的增刪改查來演示後端開發項目。 環境介紹: 開發工具:IDEA JDK ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...