設計模式-結構型模式(詳解)

適配器模式

將一個類的接口轉換成客戶端期望的另一個接口,解決接口不兼容問題。

適配器模式由四部分組成:

  1. 客戶端:即需要使用目標接口的類

  2. 目標接口

  3. 需要適配的類,也就是已經存在好的功能,但客戶端通過目標接口沒辦法使用這個類

  4. 適配器,會實現目標接口,然后耦合需要適配的類,調用類的功能

分為類適配器和對象適配器

// 目標接口
public interface Target {void request();
}
// 適配者類
public class Adaptee {public void specificRequest() {System.out.println("Adaptee's specificRequest");}
}
// 類適配器
public class Adapter extends Adaptee implements Target {@Overridepublic void request() {specificRequest();}
}// 客戶端代碼
public class Client {public static void main(String[] args) {Target target = new Adapter();target.request();  // Output: Adaptee's specificRequest}
}

對象適配器: 通過組合,讓適配器類持有現有類的實例,并實現目標接口**。對象適配器使用組合關系來實現接口的適配**,較為常用。

// 目標接口
public interface Target {void request();
}
// 適配者類
public class Adaptee {public void specificRequest() {System.out.println("Adaptee's specificRequest");}
}
// 對象適配器
public class Adapter implements Target {  //這里不再是和類適配器一樣繼承適配器,而是在類中裝配適配器對象private Adaptee adaptee;public Adapter(Adaptee adaptee) {this.adaptee = adaptee;}@Overridepublic void request() {adaptee.specificRequest();}
}// 客戶端代碼
public class Client {public static void main(String[] args) {Adaptee adaptee = new Adaptee();Target target = new Adapter(adaptee);target.request();  // Output: Adaptee's specificRequest}
}

Java 日志中的 slf4j 其實就是使用了適配器模式來統一不同日志框架接口,使得我們不需要修改代碼就可以替換不同的底層日志實現。

橋接模式

主要的作用是將抽象和實現解耦,使它們可以獨立地變化。

我們熟知的JDBC 就使用了橋接模式,JDBC定義了抽象的規范,不同的數據庫廠商遵循這些規范,但是它們各自又會有不同的實現。
在使用中,如果我們數據庫是 mysql,則傳入 com.mysql.jdbc.Driver 驅動實現類,如果要換成 oracle替換實現類為oracle.jdbc.driver.OracleDriver 即可,這就是典型的抽象與實現解耦。

代碼實例

實現形狀顏色解耦

  1. 實現化(Implementor):定義顏色接口

    public interface Color {void applyColor();
    }
    
  2. 具體實現化(Concrete Implementor):實現具體顏色

    public class RedColor implements Color {@Overridepublic void applyColor() { System.out.println("Applying red color");  //紅色}
    }public class BlueColor implements Color {   //藍色@Overridepublic void applyColor() {System.out.println("Applying blue color");}
    }
    
  3. 抽象化(Abstraction):定義形狀接口

    public abstract class Shape {protected Color color;public Shape(Color color) {this.color = color;}public abstract void draw();
    }
    
  4. 細化抽象化(Refined Abstraction):實現具體形狀

    public class Circle extends Shape {public Circle(Color color) {super(color);}@Overridepublic void draw() {System.out.print("Drawing a circle with ");color.applyColor();}
    }public class Rectangle extends Shape {public Rectangle(Color color) {super(color);}@Overridepublic void draw() {System.out.print("Drawing a rectangle with ");color.applyColor();}
    }
    
  5. 客戶端代碼

    public class Client {public static void main(String[] args) {// 創建紅色圓形Shape redCircle = new Circle(new RedColor());redCircle.draw();  // 輸出: Drawing a circle with Applying red color// 創建藍色矩形Shape blueRectangle = new Rectangle(new BlueColor());blueRectangle.draw();  // 輸出: Drawing a rectangle with Applying blue color}
    }
    

組合模式

將對象組合成樹狀結構以表示“整體——部分”的層次關系

以部門為示例,展示組織內的部門和人員信息

// 抽象組織
interface OrganizationComponent {  void showDetails();
}// 組織人員
class Employee implements OrganizationComponent {private String name;private String position;public Employee(String name, String position) {this.name = name;this.position = position;}@Overridepublic void showDetails() {System.out.println("Employee: " + name + ", Position: " + position);}
}// 組織部門
class Department implements OrganizationComponent {private String name;private List<OrganizationComponent> components = new ArrayList<>();public Department(String name) {this.name = name;}@Overridepublic void showDetails() {System.out.println("Department: " + name);for (OrganizationComponent component : components) {component.showDetails();}}public void add(OrganizationComponent component) { //往部門添加人員 或 部門components.add(component);}public void remove(OrganizationComponent component) {components.remove(component);}
}// 使用代碼
public class Client {public static void main(String[] args) {// 創建人員OrganizationComponent employee1 = new Employee("John Doe", "Developer");OrganizationComponent employee2 = new Employee("Jane Smith", "Designer");OrganizationComponent employee3 = new Employee("Emily Davis", "Manager");// 創建部門Department engineeringDepartment = new Department("Engineering Department");Department designDepartment = new Department("Design Department");Department headDepartment = new Department("Head Department");// 添加人員到部門engineeringDepartment.add(employee1);designDepartment.add(employee2);headDepartment.add(employee3);// 添加子部門到上級部門headDepartment.add(engineeringDepartment);headDepartment.add(designDepartment);// 顯示整個組織結構的詳情headDepartment.showDetails();// 輸出// Department: Head Department// Employee: Emily Davis, Position: Manager// Department: Engineering Department// Employee: John Doe, Position: Developer// Department: Design Department// Employee: Jane Smith, Position: Designer}
}

通過組合模式,提供統一的接口,簡化對層次結構的處理,使得使用方代碼更加簡潔與靈活。

裝飾器模式

主要作用是通過創建包裝類來實現功能的增強,而不是修改原始類

通過創建一個裝飾器類,該類實現了與原始對象相同的接口,并持有一個原始對象的引用。通過將原始對象傳遞給裝飾器

代理模式中,代理類附加的是跟原始類無關的功能,而在裝飾器模式中,裝飾器類附加的是跟原始類相關的增強功能。

最典型的裝飾器實現就是 Java 中的I/O類庫,示例代碼如下:

import java.io.*;
public class IOExample {public static void main(String[] args) throws IOException {File file = new File("test.txt");FileInputStream fis = new FileInputStream(file);  //讀取文件流BufferedInputStream bis = new BufferedInputStream(fis);  //fis被BufferedlnputStream 裝飾,提供了緩存的功能DataInputStream dis = new DataInputStream(bis); //被 DatalnputStream 裝飾,提供了按數據類型讀取的功能while (dis.available() > 0) {System.out.println(dis.readLine());}dis.close();}
}

文件流的代碼比較復雜,這里就不展示了,我們簡單看個多裝飾器疊加的代碼實現:

// 組件
interface Component {void operation();
}// 具體構件
class ConcreteComponent implements Component {@Overridepublic void operation() {System.out.println("ConcreteComponent operation");}
}// 裝飾器
abstract class Decorator implements Component {protected Component component;   public Decorator(Component component) {this.component = component;}@Overridepublic void operation() {component.operation();}
}
// 具體裝飾器 A
class ConcreteDecoratorA extends Decorator {public ConcreteDecoratorA(Component component) {super(component);}@Overridepublic void operation() {super.operation();addedBehavior();}private void addedBehavior() {System.out.println("ConcreteDecoratorA added behavior");}
}
// 具體裝飾器 B
class ConcreteDecoratorB extends Decorator {public ConcreteDecoratorB(Component component) {super(component);}@Overridepublic void operation() {super.operation();addedState();}private void addedState() {System.out.println("ConcreteDecoratorB added state");}
}// 客戶端代碼
public class Client {public static void main(String[] args) {Component component = new ConcreteComponent();Component decoratorA = new ConcreteDecoratorA(component);Component decoratorB = new ConcreteDecoratorB(decoratorA);decoratorB.operation();// Output:// ConcreteComponent operation// ConcreteDecoratorA added behavior// ConcreteDecoratorB added state}
}

外觀模式

也叫門面模式,提供了一個簡化的接口,用于訪問復雜系統中的一組接口。將復雜系統的功能封裝起來,讓客戶端可以更方便地使用系統功能而不需要了解其內部復雜結構。

舉個例子就清晰了。例如 A系統有 a、b、c三個接口,B需要分別調用 a、b、c三個接口,這樣比較麻煩,所以A將 a、b、c封裝成一個接口給B調用,對B來說使用起來就方便了,這就是外觀模式

class CPU {         //CPUpublic void start() {System.out.println("CPU 啟動");}public void shutdown() {System.out.println("CPU 關閉");}
}
class Memory {            //內存public void start() {System.out.println("內存啟動");}public void shutdown() {System.out.println("內存關閉");}
}class HardDrive {     //硬盤public void start() {System.out.println("硬盤啟動");}public void shutdown() {System.out.println("硬盤關閉");}}
class ComputerFacade {         //外觀類,封裝了計算機系統的一組復雜接口,包括 CPU、內存和硬盤的啟動和關閉private CPU cpu;private Memory memory;private HardDrive hardDrive;public ComputerFacade() {cpu = new CPU();memory = new Memory();hardDrive = new HardDrive();}public void start() {       //啟動計算機System.out.println("計算機啟動開始");cpu.start();memory.start();hardDrive.start();System.out.println("計算機啟動完成");}public void shutdown() {    //關閉計算機System.out.println("計算機關閉開始");cpu.shutdown();memory.shutdown();hardDrive.shutdown();System.out.println("計算機關閉完成");}
}
ComputerFacade computerFacade = new ComputerFacade();
computerFacade.start();
// 輸出:
// 計算機啟動開始
// CPU 啟動
// 內存啟動
// 硬盤啟動
// 計算機啟動完成computerFacade.shutdown();
// 輸出:
// 計算機關閉開始
// CPU 關閉
// 內存關閉
// 硬盤關閉
// 計算機關閉完成

享元模式

享元模式本質就是對象池,判斷是否存在,若存在則取,不存在則添加。

Integer的緩存(-128~127)采用了享元模式。

具體原理可看 Java基礎 29.什么是Java的Integer緩沖池?

示例:

假設我們要繪制棋盤上的棋子,棋子的種類有很多,但是每種棋子的形狀和顏色是固定的。我們可以使用享元模式來共享相同種類的棋子對象,從而減少對象的創建數量。

// 棋子接口
interface ChessPiece {void setColor(String color);void display(int x, int y);
}
// 具體棋子類
class ConcreteChessPiece implements ChessPiece {private String color;public ConcreteChessPiece(String color) {this.color = color;}@Overridepublic void setColor(String color) {this.color = color;}@Overridepublic void display(int x, int y) {System.out.println("Chess Piece color: " + color + ", position: (" + x + "," + y + ")");}
}
// 享元工廠類
class ChessPieceFactory {private Map<String, ChessPiece> chessPieces;public ChessPieceFactory() {this.chessPieces = new HashMap<>();    //用集合存chessPieces}public ChessPiece getChessPiece(String color) {  //返回單例ChessPiece chessPiece = chessPieces.get(color);if (chessPiece == null) {chessPiece = new ConcreteChessPiece(color);chessPieces.put(color, chessPiece);}return chessPiece;}
}
// 客戶端代碼
public class Client {public static void main(String[] args) {ChessPieceFactory chessPieceFactory = new ChessPieceFactory();ChessPiece blackPiece1 = chessPieceFactory.getChessPiece("black");  ChessPiece blackPiece2 = chessPieceFactory.getChessPiece("black");ChessPiece whitePiece1 = chessPieceFactory.getChessPiece("white");ChessPiece whitePiece2 = chessPieceFactory.getChessPiece("white");blackPiece1.display(1, 2);  // 輸出:Chess Piece color: black, position: (1,2)blackPiece2.display(3, 4);  // 輸出:Chess Piece color: black, position: (3,4)whitePiece1.display(5, 6);  // 輸出:Chess Piece color: white, position: (5,6)whitePiece2.display(7, 8);  // 輸出:Chess Piece color: white, position: (7,8)}
}

代理模式

作用:在不改變原始類的情況下,為其提供一個代理,以控制對這個對象的訪問

(代理模式和裝飾器模式很像,其主要不同是,前者是控制原對象的訪問,后者是為原對象增強已有類的功能)

核心是創建一個代理類,該類實現了與原始對象相同的接口,并持有一個原始對象的引用。在代理類的方法中,我們可以添加額外的功能,然后將請求轉發給原始對象進行處理。

// 圖片接口
interface Image {void display();
}
// 具體圖片類
class RealImage implements Image {private String filename;public RealImage(String filename) {this.filename = filename;loadImageFromDisk();}private void loadImageFromDisk() {System.out.println("Loading " + filename + " from disk.");}@Overridepublic void display() {System.out.println("Displaying " + filename);}
}
// 代理圖片類
class ProxyImage implements Image {private RealImage realImage;   //引入具體圖片類private String filename;		//實現了對原始圖片對象的控制,而不需要修改原始圖片類的代碼public ProxyImage(String filename) {this.filename = filename;}@Overridepublic void display() {if (realImage == null) {realImage = new RealImage(filename);}beforeDisplay();realImage.display();}private void beforeDisplay() {System.out.println("Before displaying " + filename + ", do some pre-processing.");}
}
// 客戶端代碼
public class Client {public static void main(String[] args) {Image image1 = new ProxyImage("image1.jpg");Image image2 = new ProxyImage("image2.jpg");image1.display();  // 輸出:Before displaying image1.jpg, do some pre-processing.//        Loading image1.jpg from disk.//        Displaying image1.jpgimage2.display();  // 輸出:Before displaying image2.jpg, do some pre-processing.//        Loading image2.jpg from disk.//        Displaying image2.jpg}
}

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

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

相關文章

銀河麒麟操作系統下載

產品試用申請國產操作系統、麒麟操作系統——麒麟軟件官方網站 下載頁面鏈接如上&#xff0c;申請試用即可。 申請試用填寫后提交&#xff0c;界面就變成了這樣&#xff0c;可以挑選適合自己的版本。 海思麒麟9006C版&#xff0c;如下&#xff1a; 本地下載&#xff1a;Kylin…

[CARLA系列--03]如何打包生成CARLA 0.9.15的非編輯版(地圖的加載與卸載)

前兩篇文章介紹了如何去安裝可編輯版的CARLA 0.9.15&#xff0c;這個完整的工程文件實在是太大了&#xff0c;大概消耗了100個G的磁盤空間&#xff0c;當在進行一個CARLA項目的時候&#xff0c;不利于在每個開發電腦都去安裝部署一套CARLA 0.9.15的源碼&#xff0c;所以把自己這…

【機器學習基礎】機器學習入門核心算法:樸素貝葉斯(Naive Bayes)

機器學習入門核心算法&#xff1a;樸素貝葉斯&#xff08;Naive Bayes&#xff09;&#xff09; 一、算法邏輯1.1 基本概念1.2 基本流程 二、算法原理與數學推導2.1 貝葉斯定理2.2 樸素貝葉斯分類器2.3 不同分布假設下的概率計算2.3.1 高斯樸素貝葉斯&#xff08;連續特征&…

云服務器系統盤滿了,但是其他正常,是否可能是被攻擊了

目錄 問題背景分析解決系統盤滿的問題解決結果 問題背景 今天登錄我的云服務器看了眼&#xff0c;發現系統盤滿了&#xff0c;但是其他正常 分析 1、首先要確認是否是被攻擊&#xff1a; top / htop (安裝&#xff1a;yum install htop 或 apt install htop)&#xff1a;…

雙因子COX 交互 共線性 -spss

SPSS 簡要界面操作步驟(針對雙因子 COX 分析) 1. 數據準備 變量格式:確保數據已整理為以下格式(示例): 時間變量(如 Time_to_Recurrence)結局變量(如 Recurrence:1=復發,0=未復發)預測變量(CSPG4_HSCORE、FAM49B_Status 二分類變量)協變量(如 Lesion_Size、Pat…

【MySQL】第12節|MySQL 8.0 主從復制原理分析與實戰(二)

一、組復制&#xff08;MGR&#xff09;核心概念 1. 定義與定位 目標&#xff1a;解決傳統主從復制的單點故障、數據不一致問題&#xff0c;提供高可用、高擴展的分布式數據庫方案。基于 GTID&#xff1a;依賴全局事務標識符&#xff08;GTID&#xff09;實現事務一致性&…

React 泛型組件:用TS來打造靈活的組件。

文章目錄 前言一、什么是泛型組件&#xff1f;二、為什么需要泛型組件&#xff1f;三、如何在 React 中定義泛型組件&#xff1f;基礎泛型組件示例使用泛型組件 四、泛型組件的高級用法帶默認類型的泛型組件多個泛型參數 五、泛型組件的實際應用場景數據展示組件表單組件狀態管…

如何手搓一個查詢天氣的mcp server

環境配置煩請移步上一篇博客 這里直接步入主題&#xff0c;天氣查詢的api用的是openweather&#xff0c;免費注冊就可以使用了 每天1000次內使用時免費的&#xff0c;大概的api 如下 https://api.openweathermap.org/data/2.5/weather?qBeijing,cn&APPID注冊后可以拿到一個…

深入解析計算機網絡核心協議:ARP、DHCP、DNS與HTTP

文章目錄 一、ARP&#xff08;地址解析協議&#xff09;1.1 定義與功能1.2 工作原理1.3 應用場景1.4 安全風險與防御 二、DHCP&#xff08;動態主機配置協議&#xff09;2.1 定義與功能2.2 工作原理2.3 應用場景2.4 優缺點與安全建議 三、DNS&#xff08;域名系統&#xff09;3…

《Java 單例模式:從類加載機制到高并發設計的深度技術剖析》

【作者簡介】“琢磨先生”--資深系統架構師、985高校計算機碩士&#xff0c;長期從事大中型軟件開發和技術研究&#xff0c;每天分享Java硬核知識和主流工程技術&#xff0c;歡迎點贊收藏&#xff01; 一、單例模式的核心概念與設計目標 在軟件開發中&#xff0c;我們經常會遇…

NL2SQL代表,Vanna

Vanna 核心功能、應用場景與技術特性詳解 一、核心功能 1. 自然語言轉SQL查詢 Vanna 允許用戶通過自然語言提問&#xff08;如“顯示2024年銷售額最高的產品”&#xff09;&#xff0c;自動生成符合數據庫規范的SQL查詢語句。其底層采用 RAG&#xff08;檢索增強生成&#xf…

【動態規劃】子數組系列(二)

&#x1f4dd;前言說明&#xff1a; 本專欄主要記錄本人的動態規劃算法學習以及LeetCode刷題記錄&#xff0c;按專題劃分每題主要記錄&#xff1a;&#xff08;1&#xff09;本人解法 本人屎山代碼&#xff1b;&#xff08;2&#xff09;優質解法 優質代碼&#xff1b;&…

68元開發板,開啟智能硬件新篇章——明遠智睿SSD2351深度解析

在智能硬件開發領域&#xff0c;開發板的選擇至關重要。它不僅關系到項目的開發效率&#xff0c;還直接影響到最終產品的性能與穩定性。而今天&#xff0c;我要為大家介紹的這款明遠智睿SSD2351開發板&#xff0c;僅需68元&#xff0c;卻擁有遠超同價位產品的性能與功能&#x…

篇章六 數據結構——鏈表(二)

目錄 1. LinkedList的模擬實現 1.1 雙向鏈表結構圖?編輯 1.2 三個簡單方法的實現 1.3 頭插法 1.4 尾插法 1.5 中間插入 1.6 刪除 key 1.7 刪除所有key 1.8 clear 2.LinkedList的使用 2.1 什么是LinkedList 5.2 LinkedList的使用 1.LinkedList的構造 2. LinkedList的…

刪除隊列中整數

給定一個長度為N的整數數列A_1,A_2,...,A_N&#xff0c;請重復以下操作K次。 每次選擇數列中最小的整數&#xff08;如果最小值不止一個&#xff0c;選擇最靠前的&#xff09;&#xff0c;將其刪除&#xff0c;并把與它相鄰的整數加上被刪除的數值。 請問K次操作后的序列是什…

[神經網絡]使用olivettiface數據集進行訓練并優化,觀察對比loss結果

結合歸一化和正則化來優化網絡模型結構&#xff0c;觀察對比loss結果 搭建的神經網絡&#xff0c;使用olivettiface數據集進行訓練&#xff0c;結合歸一化和正則化來優化網絡模型結構&#xff0c;觀察對比loss結果 from sklearn.datasets import fetch_olivetti_faces #倒入數…

算法分析·回溯法

回溯法 方法概述算法框架問題實例TSP 問題n皇后問題 回溯法效率分析 方法概述 回溯法是一個既帶有系統性又帶有跳躍性的搜索算法&#xff1b; **系統性&#xff1a;**它在包含問題的所有解的解空間樹中&#xff0c;按照深度優先的策略&#xff0c;從根結點出發搜索解空間樹。…

Golang分布式系統開發實踐指南

Golang分布式系統開發實踐指南 一、為什么選擇Golang&#xff1f; ?原生并發模型? Goroutine和Channel機制天然適合分布式系統的并發需求?高性能編譯? 靜態編譯生成二進制文件&#xff0c;部署簡單&#xff0c;內存占用低?豐富生態? Go Module管理、標準庫支持HTTP/2、…

基于stm32風速風向溫濕度和瓦斯檢測(仿真+代碼)

資料下載地址&#xff1a;基于stm32風速風向溫濕度和瓦斯檢測 一、項目功能 1.風速&#xff0c;風向&#xff0c;溫濕度&#xff0c;瓦斯&#xff0c;報警。 2.可以設置溫濕度&#xff0c;瓦斯&#xff0c;風速報警閾值。 3.數據上傳到云平臺。 二、仿真圖 三、程序 #inc…

桃黑黑反斗戰

1.編寫求解Hanoi漢諾塔的遞歸算法代碼&#xff0c;輸出移動過程&#xff0c;并統計總移動次數。 對不同規模的漢諾塔&#xff0c;給出測試的結果 #include <stdio.h> #include <time.h> int moveCount 0; void hanoi(int n,char source,char auxiliary,char targ…