設計模式——結構型模式

結構型模式描述如何將類或對象按某種布局組成更大的結構。它分為類結構型模式和對象結構型模式,前者采用繼承機制來組織接口和類,后者釆用組合或聚合來組合對象。

由于組合關系或聚合關系比繼承關系耦合度低,滿足“合成復用原則”,所以對象結構型模式比類結構型模式具有更大的靈活性。

結構型模式分為以下 7 種:

  • 代理模式
  • 適配器模式
  • 裝飾者模式
  • 橋接模式
  • 外觀模式
  • 組合模式
  • 享元模式

5.1 代理模式

5.1.1 概述

由于某些原因需要給某對象提供一個代理以控制對該對象的訪問。這時,訪問對象不適合或者不能直接引用目標對象,代理對象作為訪問對象和目標對象之間的中介

Java中的代理按照代理類生成時機不同又分為靜態代理和動態代理。靜態代理代理類在編譯期就生成,而動態代理代理類則是在Java運行時動態生成。動態代理又有JDK代理和CGLib代理兩種。

5.1.2 結構

代理(Proxy)模式分為三種角色:

  • 抽象主題(Subject)類: 通過接口或抽象類聲明真實主題和代理對象實現的業務方法。(規范)
  • 真實主題(Real Subject)類: 實現了抽象主題中的具體業務,是代理對象所代表的真實對象,是最終要引用的對象。
  • 代理(Proxy)類 : 提供了與真實主題相同的接口,其內部含有對真實主題的引用,它可以訪問、控制或擴展真實主題的功能。

5.1.3 靜態代理

如果要買火車票的話,需要去火車站買票,坐車到火車站,排隊等一系列的操作,顯然比較麻煩。而火車站在多個地方都有代售點,我們去代售點買票就方便很多了。這個例子其實就是典型的代理模式,火車站是目標對象,代售點是代理對象。類圖如下:

代理類需要對火車站買票方法進行聚合

代碼如下:

//賣票接口
interface SellTickets {void sell();
}
//火車站  火車站具有賣票功能,所以需要實現SellTickets接口
class TrainStation implements SellTickets {public void sell() {System.out.println("火車站賣票");}
}
//代售點
class ProxyPoint implements SellTickets {private TrainStation station = new TrainStation();public void sell() {System.out.println("代理點收取一些服務費用");station.sell();}
}
//測試類
public class Client {public static void main(String[] args) {ProxyPoint pp = new ProxyPoint();pp.sell();}
}

從上面代碼中可以看出測試類直接訪問的是ProxyPoint類對象,也就是說ProxyPoint作為訪問對象和目標對象的中介。同時也對sell方法進行了增強(代理點收取一些服務費用)

代理點收取一些服務費用
火車站賣票

5.1.4 JDK動態代理

接下來我們使用動態代理實現上面案例,先說說JDK提供的動態代理。Java中提供了一個動態代理類Proxy,Proxy并不是我們上述所說的代理對象的類,而是提供了一個創建代理對象的靜態方法(newProxyInstance方法)來獲取代理對象

代碼如下:

nterface SellTickets {void sell();
}//火車站  火車站具有賣票功能,所以需要實現SellTickets接口
class TrainStation implements SellTickets {public void sell() {System.out.println("火車站賣票");}
}//獲取代理對象的工廠類
class ProxyFactory {private TrainStation station = new TrainStation();public SellTickets getProxyObject() {//使用Proxy獲取代理對象/*newProxyInstance()方法參數說明:ClassLoader loader : 類加載器,用于加載代理類,使用真實對象的類加載器即可Class<?>[] interfaces : 真實對象所實現的接口,代理模式真實對象和代理對象實現相同的接口InvocationHandler h : 代理對象的調用處理程序*/SellTickets sellTickets = (SellTickets) Proxy.newProxyInstance(station.getClass().getClassLoader(),station.getClass().getInterfaces(),new InvocationHandler() {/*InvocationHandler中invoke方法參數說明:proxy : 代理對象method : 對應于在代理對象上調用的接口方法的 Method 實例args : 代理對象調用接口方法時傳遞的實際參數*/public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {System.out.println("代理點收取一些服務費用(JDK動態代理方式)");//執行真實對象Object result = method.invoke(station, args);return result;}});return sellTickets;}
}//測試類
public class Client {public static void main(String[] args) {//獲取代理對象ProxyFactory factory = new ProxyFactory();SellTickets proxyObject = factory.getProxyObject();proxyObject.sell();}
}
代理點收取一些服務費用(JDK動態代理方式)
火車站賣票

使用了動態代理,我們思考下面問題:

  • ProxyFactory是代理類嗎?

    ProxyFactory不是代理模式中所說的代理類,是提供的一個工廠來獲取代理對象。而代理類是程序在運行過程中動態的在內存中生成的類。通過阿里巴巴開源的 Java 診斷工具(Arthas【阿爾薩斯】)查看代理類的結構:

    package com.sun.proxy;
    ?
    import com.itheima.proxy.dynamic.jdk.SellTickets;
    import java.lang.reflect.InvocationHandler;
    import java.lang.reflect.Method;
    import java.lang.reflect.Proxy;
    import java.lang.reflect.UndeclaredThrowableException;
    ?
    public final class $Proxy0 extends Proxy implements SellTickets {private static Method m1;private static Method m2;private static Method m3;private static Method m0;
    ?public $Proxy0(InvocationHandler invocationHandler) {super(invocationHandler);}
    ?static {try {m1 = Class.forName("java.lang.Object").getMethod("equals", Class.forName("java.lang.Object"));m2 = Class.forName("java.lang.Object").getMethod("toString", new Class[0]);m3 = Class.forName("com.itheima.proxy.dynamic.jdk.SellTickets").getMethod("sell", new Class[0]);m0 = Class.forName("java.lang.Object").getMethod("hashCode", new Class[0]);return;}catch (NoSuchMethodException noSuchMethodException) {throw new NoSuchMethodError(noSuchMethodException.getMessage());}catch (ClassNotFoundException classNotFoundException) {throw new NoClassDefFoundError(classNotFoundException.getMessage());}}
    ?public final boolean equals(Object object) {try {return (Boolean)this.h.invoke(this, m1, new Object[]{object});}catch (Error | RuntimeException throwable) {throw throwable;}catch (Throwable throwable) {throw new UndeclaredThrowableException(throwable);}}
    ?public final String toString() {try {return (String)this.h.invoke(this, m2, null);}catch (Error | RuntimeException throwable) {throw throwable;}catch (Throwable throwable) {throw new UndeclaredThrowableException(throwable);}}
    ?public final int hashCode() {try {return (Integer)this.h.invoke(this, m0, null);}catch (Error | RuntimeException throwable) {throw throwable;}catch (Throwable throwable) {throw new UndeclaredThrowableException(throwable);}}
    ?public final void sell() {try {this.h.invoke(this, m3, null);return;}catch (Error | RuntimeException throwable) {throw throwable;}catch (Throwable throwable) {throw new UndeclaredThrowableException(throwable);}}
    }

    從上面的類中,我們可以看到以下幾個信息:

    • 代理類($Proxy0)實現了SellTickets。這也就印證了我們之前說的真實類和代理類實現同樣的接口。
    • 代理類($Proxy0)將我們提供了的匿名內部類對象傳遞給了父類。
  • 動態代理的執行流程是什么樣?

    下面是摘取的重點代碼:

    //程序運行過程中動態生成的代理類
    public final class $Proxy0 extends Proxy implements SellTickets {private static Method m3;
    ?public $Proxy0(InvocationHandler invocationHandler) {super(invocationHandler);}
    ?static {m3 = Class.forName("com.itheima.proxy.dynamic.jdk.SellTickets").getMethod("sell", new Class[0]);}
    ?public final void sell() {

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/162274.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/162274.shtml
英文地址,請注明出處:http://en.pswp.cn/news/162274.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

機器學習算法(1)——簡單線性回歸

一、說明 在在這篇文章中&#xff0c;我們將學習我們的第一個機器學習算法&#xff0c;稱為簡單線性回歸。這是一個重要的算法&#xff0c;因為當您可能正在學習第一個神經網絡&#xff08;稱為人工神經網絡&#xff09;時&#xff0c;在此算法中學習的技術也適用于深度學習。我…

畢業設計ASP.NET 1400動漫公司網站【程序源碼+文檔+調試運行】

摘要 本系統將實現一個動漫公司網站&#xff0c;包括前臺用戶模塊和后臺管理員模塊。前臺用戶模塊主要包括最新動漫、注冊登錄、公司簡介、公司新聞、動漫中心、聯系我們和會員中心等功能。后臺管理員模塊包括用戶管理、公司簡介管理、公司新聞管理、動漫類別管理、動漫管理、…

加工車間污水處理設備有哪些

在加工車間中&#xff0c;污水處理設備是至關重要的一部分。它們的功能是將污水進行處理&#xff0c;確保其達到符合環保標準的水質要求。以下是一些常見的加工車間污水處理設備&#xff1a; 1.初級沉淀池&#xff1a;初級沉淀池是最基本的污水處理設備之一。它通過重力作用將…

阿里云服務器ECS產品知識及購買和使用常見問題及答案匯總

本文總結了阿里云用戶在購買和使用阿里云服務器中的一些常見的問題&#xff0c;包括什么是云服務器ECS&#xff0c;特性與優勢&#xff0c;應用場景&#xff0c;基本概念&#xff0c;使用限制等眾多問題&#xff0c;讓您全方位了解阿里云服務器&#xff0c;并根據自己的需求選擇…

Qt pro常用宏

RC_ICONS IStudio.icoCONFIG no_debug_release # 不會生成debug 和 release 文件目錄 DESTDIR $$PWD/../bin # 指定編譯最終文件的生成路徑 OBJECTS_DIR $$PWD/temp/obj # obj中間文件存放路徑 MOC_DIR $$PWD/temp/moc # moc中間文件…

百戰python01-初識python_turtle繪圖

文章目錄 簡介練習1.簡易的進度條學習使用turtle在屏幕上繪制圖形注:需要對python有基本了解,可查看本作者python基礎專欄,有任何問題歡迎私信或評論(本專欄每章內容都將不定期進行內容擴充與更新) 簡介 python簡介及方向+pycharm安裝使用請轉 練習 注:嘗試練習。了解…

Windows系統中curl和wget命令下載說明

前言 當需要在命令行中發送 HTTP 請求時&#xff0c;常用的工具有 curl 和 wget。它們可以幫助你下載文件&#xff0c;發送 POST 或 GET 請求&#xff0c;以及檢查網頁內容等。 curl: curl 是一個功能強大的命令行工具&#xff0c;支持多種協議&#xff08;例如 HTTP、HTTPS、…

常見樹種(貴州省):010任豆、漆樹、椿樹、伯樂樹、欒樹、楸樹、橡膠樹、鹽膚木、吳茱萸、黃柏

摘要&#xff1a;本專欄樹種介紹圖片來源于PPBC中國植物圖像庫&#xff08;下附網址&#xff09;&#xff0c;本文整理僅做交流學習使用&#xff0c;同時便于查找&#xff0c;如有侵權請聯系刪除。 圖片網址&#xff1a;PPBC中國植物圖像庫——最大的植物分類圖片庫 一、任豆 …

趨勢解讀:TikTok獨創的社交語言是如何演變的

在數字時代的浪潮中&#xff0c;社交媒體平臺成為人們傳遞信息、表達創意和建立社交聯系的重要場所。而在這眾多社交平臺中&#xff0c;TikTok以其獨特的社交語言和創新的內容形式&#xff0c;迅速吸引了全球數以億計的用戶。本文將深入探討TikTok的社交語言是如何獨創并演變的…

中年人怎么發展?持續發展?

現在ai這么火&#xff0c;就像當年的xxx&#xff0c;如果沒有抓住&#xff0c;會xxx嗎&#xff1f; 為了ai&#xff0c;多學學python也是也是好的啊。 在學習之余&#xff0c;還是想做做自媒體的。不求馬上賺到錢。我的想法是&#xff0c;現在每天下班回家都是刷刷抖音&#…

win10戴爾電腦安裝操作系統遇到的問題MBR分區表只能安裝GPT磁盤

首先按F2啟動boot管理界面 調整啟動盤的啟動順序&#xff0c;這里啟動U盤為第一順序。 第一步 選擇安裝程序的磁盤 第二步 轉換磁盤為GPT磁盤 一般出現 磁盤0和1&#xff0c;說明存在兩個盤 &#xff0c;這里兩個盤不是說的是C盤和D盤的問題&#xff0c;而是在物理上實際存在…

easyExcel實現分批導入,動態表頭分批導出,以及導出表格樣式設置

<dependency><groupId>com.alibaba</groupId><artifactId>easyexcel</artifactId><version>2.2.6</version></dependency> 一&#xff0c;分批導入 1.首先配置表格頭映射類 Getter Setter EqualsAndHashCode public class …

YOLOV5標注訓練自己的數據全流程教程

概述 yolo在目標檢測領域是非常有代表性的模型&#xff0c;它速度快識別效果也很精準&#xff0c;是實時檢測模型中應用最廣泛的。yolo的原理和代碼是很容易獲得的&#xff0c;且有各式各樣的教程&#xff0c;但是模型怎么使用的教程相對比較少。本文講解如何使用yolov5模型訓…

Linux運行jmeter報錯java.sql.SQLException:Cannot create PoolableConnectionFactory

在性能測試過程中遇見1個問題&#xff0c;終于解決了&#xff0c;具體問題如下。 問題 在windows電腦寫jmeter腳本連接數據庫連接成功 然后把該腳本放到Linux服務器上面&#xff0c;并把jmeter mysql驅動放到服務器上面&#xff0c;修改jmeter的mysql驅動路徑信息 注意&…

第十三章 : Spring Boot 日志記錄脫敏

第十三章 : Spring Boot 日志記錄脫敏 前言 本章重點:介紹secure-ext-spring-boot-starter 如何引入以及敏感數據脫敏,打印日志過程中自動脫敏,且支持手機號、郵箱、身份證號、住址、中文名、座機號、銀行卡、自定義等多種類型的脫敏。 基于Spring boot 2.3.2.RELEASE 背景…

【快速解決】實驗一:模擬實現進程的創建《操作系統上機》實驗報告

目錄 實驗要求 正文開始 ?編輯 難點講解 結語 實驗要求 實驗一&#xff1a;進程的創建 一、實驗項目類型&#xff1a;設計型 二、實驗目的和要求 加深對進程概念的理解&#xff0c;熟悉PCB的組織&#xff0c;深入了解創建進程的一般過程&#xff0c;掌握用隊列組織進程的…

數據庫系統之常用數據庫你用過幾個?

MySQL 開發廠商&#xff1a;AB公司——>Sun公司——>甲骨文公司 最新版本&#xff1a;5.7.43、8.0.34 發行方式: 社區版&#xff08;MySQL Community Server&#xff09; 免費&#xff0c;MySQL不提供任何技術支持 商業版&#xff08;MySQL Enterprise Edition&#xff0…

LLVM學習筆記(62)

4.4.3.3.2. 指令處理的設置 4.4.3.3.2.1. 目標機器相關設置 除了基類以外&#xff0c;X86TargetLowering構造函數本身也是一個龐然大物&#xff0c;我們必須要分段來看。V7.0做了不小的改動&#xff0c;改進了代碼的結構&#xff0c;修改了一些指令的設置。 100 X86Targ…

加班做報表被嘲低效!快用大數據分析工具

做數據分析報表很耗時間&#xff0c;因為不僅要解決多業務系統數據質量標準不一問題&#xff0c;還需要進行大量的公式計算、報表設計與制作。但那是以前&#xff0c;在大數據分析工具強勢崛起的當下&#xff0c;這些工作都能交給大數據分析工具來做了。以前是花90%的時間做報表…

9.Docker的虛懸鏡像-Dangling Image

1.虛懸鏡像的概念 虛懸鏡像 (Dangling Image) 指的是倉庫名 (鏡像名) 和標簽 TAG 都是 的鏡像。 2.構建本地虛懸鏡像 這里我以unbuntu為例來說明。 2.1 編寫Dockerfile文件 FROM ubuntu:22.042.2 根據Dockerfile文件構建虛懸鏡像 docker build .上面這段命令&#xff0c…