設計模式之結構型模式(適配器、橋接、組合、享元、裝飾者、外觀、代理)

文章目錄

    • 一、結構型設計模式
    • 二、適配器模式
    • 三、橋接模式
    • 四、組合模式
    • 五、享元模式
    • 六、裝飾者模式
    • 七、外觀模式
    • 八、代理設計模式

一、結構型設計模式

這篇文章我們來講解下結構型設計模式,結構型設計模式,主要處理類或對象的組合關系,為如何設計類以形成更大的結構提供指南。

結構型設計模式包括:適配器模式(Adapter Pattern)、橋接模式(Bridge Pattern)、組合模式(Composite Pattern)、裝飾器模式(Decorator Pattern)、外觀模式(Facade Pattern)、享元模式(Flyweight Pattern)、代理模式(Proxy Pattern)

二、適配器模式

適配器模式(Adapter Pattern)是作為兩個不兼容的接口之間的橋梁。它結合了兩個獨立接口的功能。
優點:

  1. 可以讓任何兩個沒有關聯的類一起運行。
  2. 提高了類的復用。
  3. 增加了類的透明度。
  4. 靈活性好。

這種模式涉及到一個單一的類,該類負責加入獨立的或不兼容的接口功能。舉個真實的例子,在視頻播放器中,假設視頻播放器只能播放MP4格式的視頻,那現在又有個VLC格式的視頻,就不能播放了,那要如何解決這個問題?如果我們做個轉換器,將VLC格式的視頻轉換為MP4格式的視頻不就可以播放了嗎,那這個轉換器我們就可以采用適配器設計模式來設計。

下面使用程序演示下上面的例子:

  1. 定義視頻接口
public interface VideoInterFace {String getVideoPath();
}
  1. 定時Mp4格式視頻實例
public class Mp4Video implements VideoInterFace {@Overridepublic String getVideoPath() {return "Mp4視頻的路徑";}
}
  1. 定義VLC格式視頻實例
public class VlcVideo implements VideoInterFace{@Overridepublic String getVideoPath() {return "Vlc視頻的路徑";}
}
  1. 定義播放器,只接口Mp4格式的視頻
public class Player {private Mp4Video video;public Player(Mp4Video video) {this.video = video;}public void play() {System.out.println(StringFormatter.concat("播放視頻視頻地址:", video.getVideoPath()).getValue());}
}
  1. 需要播放VLC格式的視頻,定義Mp4的適配器,并接收VLC格式視頻,進行轉碼。
public class Mp4Adapter extends Mp4Video {private VlcVideo vlcVideo;public Mp4Adapter(VlcVideo vlcVideo) {this.vlcVideo = vlcVideo;}@Overridepublic String getVideoPath() {System.out.println(StringFormatter.concat("開始格式轉換,vlc地址:", vlcVideo.getVideoPath()).getValue());return "轉換后的Mp4路徑!";}
}
  1. 測試
public class demo {public static void main(String[] args) {Player player = new Player(new Mp4Video());player.play();VlcVideo vlcVideo = new VlcVideo();Player player1 = new Player(new Mp4Adapter(vlcVideo));player1.play();}
}

在這里插入圖片描述

從上面的例子可以看出,需要播放VLC格式,就需要寫一個目標適配器,這里是Mp4適配器,并繼承Mp4,使之有Mp4的特性,并在內部做相應的轉換即可,提高了系統的可擴展性。

三、橋接模式

橋接模式(Bridge)是用于把抽象化與實現化解耦,使得二者可以獨立變化。它通過提供抽象化和實現化之間的橋接結構,來實現二者的解耦
這種模式涉及到一個作為橋接的接口,使得實體類的功能獨立于接口實現類。這兩種類型的類可被結構化改變而互不影響。
優點:

  1. 抽象和實現的分離。
  2. 優秀的擴展能力。
  3. 實現細節對客戶透明。

舉個例子:繪畫不同顏色的各種圖像,畫不同的形狀和涂顏色,便是兩個不同的功能,但兩者又相互聯系,在畫完形狀后需要涂顏色,但顏色和形狀有使多種多樣的,此時就可以采用橋接設計模式,將兩者的抽象化與實現化解耦,形狀和顏色可以獨立變化

下面使用程序演示下上面的例子:

  1. 定義顏色的接口
public interface ColorApi {public void drawCircle();
}
  1. 定義不同顏色的實現,這里采用紅色和綠色
public class ReqColor implements ColorApi {@Overridepublic void drawCircle() {System.out.println("開始涂紅色!");}
}
public class GreenColor implements ColorApi {@Overridepublic void drawCircle() {System.out.println("開始涂綠色!");}
}
  1. 定義形狀的接口
public interface ShapeApi {//畫形狀void draw();//畫形狀并涂顏色void drawShapeAndsColor();
}
  1. 定義形狀的抽象模板,將共性的操作定義到抽象中
public abstract class ShapeAbstract implements ShapeApi {public ColorApi colorApi;public ShapeAbstract(ColorApi colorApi) {this.colorApi = colorApi;}@Overridepublic void drawShapeAndsColor() {draw();colorApi.drawCircle();}
}
  1. 定義圓形的實例
public class Circle extends ShapeAbstract {public Circle(ColorApi colorApi) {super(colorApi);}@Overridepublic void draw() {System.out.println("開始畫圓形!");}
}
  1. 定義矩形的實例
public class Rectangle extends ShapeAbstract {public Rectangle(ColorApi colorApi) {super(colorApi);}@Overridepublic void draw() {System.out.println("開始畫矩形");}
}
  1. 演示
public class demo {public static void main(String[] args) {ShapeApi shapeReq = new Circle(new ReqColor());shapeReq.drawShapeAndsColor();ShapeApi shapeGreen = new Circle(new GreenColor());shapeGreen.drawShapeAndsColor();ShapeApi rectangle = new Rectangle(new GreenColor());rectangle.drawShapeAndsColor();}
}

在這里插入圖片描述

上面可以看出,可以靈活的定義形狀和顏色的組合,并且他們兩個都可以獨立變化,添加新的形狀只需,建立新的類并實現形狀接口,添加顏色也是如此,極大的提高的系統的可擴展性和可維護型。

四、組合模式

組合模式(Composite Pattern),又叫部分整體模式,是用于把一組相似的對象當作一個單一的對象
組合模式依據樹形結構來組合對象,用來表示部分以及整體層次。它創建了對象組的樹形結構。
優點:

  1. 高層模塊調用簡單。
  2. 節點自由增加。

缺點:
在使用組合模式時,其葉子和樹枝的聲明都是實現類,而不是接口,違反了依賴倒置原則。

舉個例子:一個公司,從上到下分為,公司、部門、小組等,他們整個在一起才能稱為一個完整的公司,要表示做個公司的結構,就可以采用組合設計模式。

下面使用程序演示下上面的例子:

  1. 定義屬性類,用來表示不同層級的對象
@Data
public class Property {private String name;//下一層的子集private List<Property> next;public Property(String name) {this.name = name;next = new ArrayList<Property>();}public void add(Property e) {next.add(e);}public void remove(Property e) {next.remove(e);}public List<Property> getSubordinates(){return next;}
}
  1. 使用演示
public class demo {public static void main(String[] args) {Property company = new Property("公司");Property department = new Property("部門");Property group = new Property("小組");company.add(department);department.add(group);System.out.println(company);}
}

在這里插入圖片描述

上面就演示了一個公司的組合,通過company對象就可以獲得整個公司的各個部分的對象。組合設計模式主要適合于整體部分的場景。

五、享元模式

享元模式(Flyweight Pattern)主要用于減少創建對象的數量,以減少內存占用和提高性能。它提供了減少對象數量從而改善應用所需的對象結構的方式。
享元模式嘗試重用現有的同類對象,如果未找到匹配的對象,則創建新對象。他的優點是大大減少對象的創建,降低系統的內存,使效率提高,但也有可能造成內存的浪費。比如Spring的采用容器的方式存儲bean,使用時從容器中獲取。

還是拿畫不同顏色形狀的例子演示下享元設計模式的使用:

  1. 定義形狀的接口
public interface Shape {void draw();
}
  1. 定義圓形的實現,并接收一個顏色值:
public class Circle implements Shape {private String color;public Circle(String color) {this.color = color;}@Overridepublic void draw() {System.out.println(StringFormatter.concat("開始畫 ", color, " 色的圓 ").getValue());}
}
  1. 定義形狀對象獲取工廠,根據顏色值將對象存儲到HashMap中,后再根據顏色值取對象,達到復用的效果。
public class ShapeFactory {private static final HashMap<String, Shape> circleMap = new HashMap<>();public static Shape getCircle(String color) {if (!circleMap.containsKey(color)) {System.out.println(StringFormatter.concat(">> 創建", color, "顏色的圓 ").getValue());circleMap.put(color, new Circle(color));}return circleMap.get(color);}
}
  1. 使用
public class demo {private static final String colors[] ={"Red", "Green", "Blue", "White", "Black"};public static void main(String[] args) {for (int i = 0; i < 20; ++i) {Shape circle = ShapeFactory.getCircle(getRandomColor());circle.draw();}}private static String getRandomColor() {return colors[(int) (Math.random() * colors.length)];}
}

在這里插入圖片描述

上面可以看出,享元設計模式可以大大減少對象的創建,但也有可以造成內存的浪費,比如某個對象的使用頻率非常低,如果一直存在內存中就有點浪費空間了。

六、裝飾者模式

裝飾者模式(Decorator Pattern)允許向一個現有的對象添加新的功能,同時又不改變其結構。它是作為現有的類的一個包裝
裝飾類和被裝飾類可以獨立發展,不會相互耦合,裝飾者模式是繼承的一個替代模式,裝飾者模式可以動態擴展一個實現類的功能。

舉個例子:還是繪畫不同的形狀的例子,加入系統中有畫各種形狀的功能,但隨著功能后期的演化,需要畫出帶有邊框的各種形狀,那么此時就可以采用裝飾者設計模式來做增強。

下面使用程序演示下上面的例子:

  1. 定義形狀接口
public interface Shape {void draw();
}
  1. 定義圓形的實現
public class Circle implements Shape {@Overridepublic void draw() {System.out.println("開始畫圓形!");}
}
  1. 定義矩形的實現
public class Rectangle implements Shape {@Overridepublic void draw() {System.out.println("開始畫矩形!");}
}
  1. 定義裝飾器的抽象模板
public abstract class ShapeDecorator implements Shape {protected Shape decoratedShape;public ShapeDecorator(Shape decoratedShape){this.decoratedShape = decoratedShape;}@Overridepublic void draw(){decoratedShape.draw();}  
}
  1. 定義具體的邊框裝飾器
public class BorderShapeDecorator extends ShapeDecorator {public BorderShapeDecorator(Shape decoratedShape) {super(decoratedShape);     }@Overridepublic void draw() {decoratedShape.draw();         setRedBorder(decoratedShape);}private void setRedBorder(Shape decoratedShape){System.out.println("畫邊框!");}
}
  1. 演示
public class demo {public static void main(String[] args) {Shape circle = new Circle();circle.draw();Shape shape = new BorderShapeDecorator(new Circle());shape.draw();Shape shape1 = new BorderShapeDecorator(new Rectangle());shape1.draw();}
}

在這里插入圖片描述

上面可以看出再不改變原先類的基礎上,做了畫邊框的效果,對原有做增強,使用裝飾者設計模式,可以大大提高系統的可擴展性。

七、外觀模式

外觀模式(Facade Pattern)隱藏系統的復雜性,并向客戶端提供了一個客戶端可以訪問系統的接口。它向現有的系統添加一個接口,來隱藏系統的復雜性。
這種模式涉及到一個單一的類,該類提供了客戶端請求的簡化方法和對現有系統類方法的委托調用。
它的優點是可以減少系統相互依賴、提高靈活性、提高了安全性。但是它不符合開閉原則,如果要改東西很麻煩,繼承重寫都不合適。

舉個例子:畫各種圖形的例子,比如要畫圓形、矩形、三角形,每畫一種圖像都要拿到對應的抽象,并調用繪制方法,如果要畫的形狀過多,這么多的抽象就不好管理了,而如果使用外觀設計模式,提供一個統一的抽象,在這個抽象中就可以完成上面不同的繪制,這樣就方便了我們的管理。

下面使用程序演示下上面的例子:

  1. 定義形狀的接口
public interface Shape {void draw();
}
  1. 定義圓形的實例
public class Circle implements Shape {@Overridepublic void draw() {System.out.println("開始畫圓!");}
}
  1. 定義矩形的實例
public class Rectangle implements Shape {@Overridepublic void draw() {System.out.println("開始畫矩形!");}
}
  1. 定義三角形的實例
public class Triangle implements Shape {@Overridepublic void draw() {System.out.println("開始畫三角形!");}
}
  1. 定義一個外觀類,并調用上面的功能
public class ShapeFacade {private Shape circle;private Shape rectangle;private Shape square;public ShapeFacade() {circle = new Circle();rectangle = new Rectangle();square = new Triangle();}public void drawCircle(){circle.draw();}public void drawRectangle(){rectangle.draw();}public void drawSquare(){square.draw();}
}
  1. 演示
public class demo {public static void main(String[] args) {ShapeFacade shapeFacade = new ShapeFacade();shapeFacade.drawCircle();shapeFacade.drawRectangle();shapeFacade.drawSquare();}
}

在這里插入圖片描述
外觀設計模式還是比較容易理解的,就是把多個功能統一整個到一個對象中,由這個對象再去調用具體的類和方法。

八、代理設計模式

代理設計模式通過代理控制對象的訪問,可以詳細訪問某個對象的方法,在這個方法調用處理,或調用后處理。既(AOP微實現) 。

代理有分靜態代理動態代理

  • 靜態代理:在程序運行前就已經存在代理類的字節碼文件,代理類和委托類的關系在運行前就確定了。
  • 動態代理:是在使用時,動態的生成代理對象,他是在內存中構建代理對象的。

舉個例子,在做數據庫操作時,一般我們都會在事物中做SQL的操作,那就需要在操作前開啟事物,操作后如果成功就需要提交事物,如果代用代理設計模式,就可以將事物開啟提交邏輯放在代理類中,被代理的類,只需要關注業務邏輯即可。

下面以支付和事物為例演示下代理模式

采用靜態代理,實現上面例子:

  1. 定義支付接口
public interface PayInterFace {void pay();
}
  1. 定義微信支付實現
public class WxPay implements PayInterFace {@Overridepublic void pay() {System.out.println("支付中...");}
}
  1. 定義支付的代理類
public class PayProxy implements PayInterFace {private WxPay pay;public PayProxy(WxPay pay) {this.pay = pay;}@Overridepublic void pay() {System.out.println("事物開始!");pay.pay();System.out.println("提交事物!");}
}
  1. 演示
public class demo {public static void main(String[] args) {PayInterFace pay = new PayProxy(new WxPay());pay.pay();}
}

在這里插入圖片描述

上面的靜態代理,可以看出,我們需要對每個被代理對象設計一個代理類,如果代理的功能非常多,那就需要開發人員寫特別多的代理類,下面可以看下動態代理的使用。

采用動態代理,實現上面例子:
這里使用JDK自帶的動態代理來實現

  1. 再定義一個支付寶的支付實現
public class ZfbPay implements PayInterFace {@Overridepublic void pay() {System.out.println("支付寶支付中...");}
}
  1. 定義代理對象,采用jdk的 InvocationHandler 接口
public class PayProxy implements InvocationHandler {private Object object;public PayProxy(Object object) {this.object = object;}@Overridepublic Object invoke(Object proxy, Method method, Object[] args) throws Throwable {System.out.println("事物開始!");Object result = method.invoke(object, args);System.out.println("提交事物!");return result;}
}
  1. 演示
public class demo {public static void main(String[] args) {PayInterFace pay = (PayInterFace) Proxy.newProxyInstance(PayInterFace.class.getClassLoader(),new Class[]{PayInterFace.class},new PayProxy(new WxPay()));pay.pay();PayInterFace pay1 = (PayInterFace) Proxy.newProxyInstance(PayInterFace.class.getClassLoader(),new Class[]{PayInterFace.class},new PayProxy(new ZfbPay()));pay1.pay();}
}

在這里插入圖片描述

上面使用一個代理類,代理了多個對象,相對于靜態代理,是代碼更簡介,靈活性也更高。

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

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

相關文章

【已解決】ModuleNotFoundError: No module named ‘IPython‘

問題描述 Traceback (most recent call last): File "<stdin>", line 1, in <module> ModuleNotFoundError: No module named IPython 解決方法 pip install ipython 完結撒花 我并不想穿過荊棘去到黎明&#xff0c;我猜也沒有人會想

proftpd安全加固:禁用匿名登錄

其實&#xff0c;proftpd默認是禁止匿名登錄的。今天我們反其道&#xff0c;研究一下如何開啟匿名登錄。清楚了怎么破防&#xff0c;才能更好得防。 查看/etc/proftpd.conf 配置文件&#xff1a; # A basic anonymous configuration, with an upload directory # Enable this…

計算機設備管理器如何看內存,怎么查看電腦配置信息?3種方法,讓你掌握電腦全部信息!...

轉載&#xff1a;https://blog.csdn.net/weixin_35849957/article/details/118512756?spm1001.2014.3001.5502 原標題&#xff1a;怎么查看電腦配置信息&#xff1f;3種方法&#xff0c;讓你掌握電腦全部信息&#xff01; 電腦的配置決定了電腦性能高低以及運行速度。而電腦…

Emacs之Plantuml用于復雜UML類圖(Markdown用于簡單類圖)(一百三十二)

簡介&#xff1a; CSDN博客專家&#xff0c;專注Android/Linux系統&#xff0c;分享多mic語音方案、音視頻、編解碼等技術&#xff0c;與大家一起成長&#xff01; 優質專欄&#xff1a;Audio工程師進階系列【原創干貨持續更新中……】&#x1f680; 優質專欄&#xff1a;多媒…

python主流開發工具排名,python開發工具有哪些

本篇文章給大家談談python的開發工具軟件有哪些&#xff0c;以及python主流開發工具排名&#xff0c;希望對各位有所幫助&#xff0c;不要忘了收藏本站喔。 python中用到哪些軟件 一、Python代碼編輯器1、sublime Textsublime Text是一款非常流行的代碼編輯器&#xff0c;支持P…

STM32L051使用HAL庫操作實例(13)- 讀取IAQ-CORE-C傳感器實例

目錄 一、前言 二、傳感器參數 三、STM32CubeMX配置&#xff08;本文使用的STM32CubeMX版本為6.1.2&#xff09;例程使用模擬I2C進行數據讀取 1.MCU選型 2.使能時鐘 3.時鐘配置 4.GPIO口配置 四、配置STM32CubeMX生成工程文件 五、點擊GENERATE CODE生成工程文件 六、…

Kubersphere應用【二】Docker安裝

一、Docker安裝 1.下載Docker安裝包 【地址】Index of linux/static/stable/x86_64/ 2.上傳至服務器 # 解壓文件 tar -xvf docker-20.10.10.tgz# 將docker 目錄中的所有文件復制至/usr/bin/目錄下 cp docker/* /usr/bin 3.配置docker.service文件 vim /usr/lib/systemd/sy…

arm平臺編譯so文件回顧

提示&#xff1a;文章寫完后&#xff0c;目錄可以自動生成&#xff0c;如何生成可參考右邊的幫助文檔 文章目錄 前言一、幾個點二、回顧過程 1.上來就執行Makefile2.編譯第三方開源庫.a文件 2.1 build.sh腳本2.2 Makefile3.最終編譯三、其它知識點總結 前言 提示&#xff1a;這…

MSSQL存儲過程的功能和用法(簡明扼要)

官方文檔 存儲過程&#xff08;數據庫引擎&#xff09; - SQL Server | Microsoft Learn Transact-SQL 參考&#xff08;數據庫引擎&#xff09; - SQL Server | Microsoft Learn 定義 存儲過程可以用編程語言的方法來類比&#xff0c;有輸入輸出。區別是其使用SQL表達業務…

spring 單元測試 Junit

我是南城余&#xff01;阿里云開發者平臺專家博士證書獲得者&#xff01; 歡迎關注我的博客&#xff01;一同成長&#xff01; 一名從事運維開發的worker&#xff0c;記錄分享學習。 專注于AI&#xff0c;運維開發&#xff0c;windows Linux 系統領域的分享&#xff01; 本…

解決打印機超出字節之使用PHP拆分字符串并保留分隔符

在開發過程中&#xff0c;我們經常需要將一個長字符串拆分成多個片段&#xff0c;并且保留原始字符串中的分隔符。在本篇教程中&#xff0c;我們將使用PHP編寫一個函數來實現這個功能。 首先&#xff0c;讓我們來看一下我們要解決的問題。假設我們有一個長字符串&#xff0c;我…

pywinrm 解析輸出為 dict 格式 字典格式

s winrm.Session(host, auth(username, password))task_folder \RPA\\ # 運行 schtasks 命令來列出任務計劃程序 command schtasks /query /fo csv # command fschtasks /query /fo csv /tn {task_folder} # command fschtasks /query /fo csv /tn "{task_folder}\\…

mapbox使用v3版本,v2的樣式切換不同時間段

創建DayAndNight.js /*** 使用方式* const dayNight new DayAndNight({ map: map // map 地圖對象}) * 修改類型* dayNight.setConfigProperty(value)*/ class DayAndNight {constructor (sdMap) {this.map sdMap.mapthis.initStyle()}// 初始化時添加必要樣式initStyle () {…

刪除計算機用戶時拒絕訪問權限,c盤為什么拒絕訪問 刪除c盤文件需要管理員權限怎么辦...

轉載&#xff1a;??????刪除計算機用戶時拒絕訪問權限,c盤為什么拒絕訪問 刪除c盤文件需要管理員權限怎么辦...-CSDN博客 c盤是電腦中的關鍵位置&#xff0c;存儲著很多系統重要文件&#xff0c;如果電腦出問題一般就是c盤中的文件異常&#xff0c;近日有小伙伴出現這樣…

前端知識筆記(四十一)———nodejs發起http或https請求

http請求 const express require(express) const http require(http)const app express()const loginConfig (token) > {return {hostname: api.test.com,port: 80,path: /test?access_token${token},method: GET} }app.get(/login, (req, res) > {const options …

c++通過serial庫進行上下位機通信

?編輯 風紊 現役大學牲&#xff0c;半退休robomaster視覺隊員 寫在前面 本文章主要介紹的是如何通過開源的serial庫和虛擬串口實現上位機和下位機通信。 需求 假設下位機有這樣一個數據報發送給上位機 struct DataRecv {char start s;TeamColor color TeamColor::Blu…

Premiere Pro 2024 新功能有哪些?視頻剪輯軟件PR2024更新內容及問題修復

PR軟件“基于文本的編輯”中的填充詞檢測與批量刪除功能 “基于文本的編輯”可讓您檢測“呃”和“嗯”填充詞并批量刪除它們&#xff0c;從而使您的轉錄文本更加準確。就像處理停頓一樣&#xff0c;您可以單擊填充詞并將其從序列轉錄文本中刪除。填充詞與語言無關&#xff0c;…

STM32CubeIDE(CUBE-MX hal庫)----RTC時鐘,時鐘實時顯示

系列文章目錄 STM32CubeIDE(CUBE-MX hal庫)----初嘗點亮小燈 STM32CubeIDE(CUBE-MX hal庫)----按鍵控制 STM32CubeIDE(CUBE-MX hal庫)----串口通信 STM32CubeIDE(CUBE-MX hal庫)----定時器 STM32CubeIDE(CUBE-MX hal庫)----藍牙模塊HC-05&#xff08;詳細配置&#xff09; 前言…

【無標題】安裝環境

這里寫目錄標題 清華鏡像加速 安裝cuda11.3 PyTorch 1.10.1https://pytorch.org/get-started/previous-versions/[如果沒有可以點Previous pyTorch Versions&#xff0c;這里面有更多的更早的版本](https://pytorch.org/get-started/locally/) 復制非空文件夾cp: -r not specif…

傳染病傳播速度

題干 R0值是基本傳染數的簡稱&#xff0c;指的是在沒有采取任何干預措施的情況下&#xff0c;平均每位感染者在傳染期內使易感者個體致病的數量。數字越大說明傳播能力越強&#xff0c;控制難度越大。一個人傳染的人的數量可以用冪運算來計算。假設奧密克戎的R0為10&#xff0…