設計模式5——抽象工廠模式

寫文章的初心主要是用來幫助自己快速的回憶這個模式該怎么用,主要是下面的UML圖可以起到大作用,在你學習過一遍以后可能會遺忘,忘記了不要緊,只要看一眼UML圖就能想起來了。同時也請大家多多指教。

抽象工廠模式(Abstract Factory)

是一種創建型模式。

目錄

一、概述

二、優點

三、舉例


一、概述

1、提供一個創建一系列相關或相互依賴對象的接口,而無需指定它們具體的類。
2、和工廠方法模式不同的是,有多種類型的對象(產品)需要被實例化,同時工廠也被定義了多個不同產品創建的接口。

1.1、主要的角色分兩種,但從代碼(或技術)實現的角度看(為了充分使用面向對象語言的3大特性封裝、繼承、多態,還另外需要抽象類或接口)可能有4個:

  1. 工廠的抽象類或接口(單個) + 工廠的實現類(多個):控制創建哪些產品以及如何創建產品的類
  2. 產品的抽象類或接口(多個) + 產品實現類(多個):那些需要被創建(實例化)的類?

1.2、直觀的理解上這些角色之間的關系如下:

1.3、通過技術實現的角度看,對象之間關系的UML圖如下:

?

二、優點

  • 使得發起請求的對象和具體創建實例的過程分離

三、舉例

?假設一個部門系統升級,涉及到兩個表:部門表和用戶表。原先這兩表在數據庫A里,升級后新加了個數據庫B,也有部門表和用戶表。現在為了兼容性,A和B兩個庫,和庫里的兩個表(部門表和用戶表)都需要使用。數據庫如下:

3.1、為了實現對不同數據庫的不同表的訪問和連接,分析步驟:

1、分析上述問題:

  • 抓住上面關鍵:有兩個數據庫,每個數據庫又有兩個表;
  • 兩個數據庫是不同的,但庫里的兩個表是相同的,都是一個用戶表一個部門表;
  • 如果把兩個庫同名的表看成一樣,那么邏輯上訪問的就只有兩個表,所以為了實現訪問2個不同表,我們需要定義2個不同的接口,然后針對不同的數據庫,我們還又需要設計不同實現類;
  • 我們發現這樣下來會設計很多類,那么在真正使用時需要創建很多不同對象的實例,會比較麻煩,此時就嘗試用抽象工廠模式,將使用和創建分離開來。

2、針對問題的設計要素:

產品的抽象類或接口(多個) + 產品實現類(多個)

  • 一個訪問用戶表抽象類或接口;
  • 一個訪問部門表抽象類或接口;
  • 針對 訪問數據庫A里的用戶表 和 訪問數據庫B里的用戶表 的實現類各一個;
  • 針對 訪問數據庫A里的部門表 和 訪問數據庫B里的部門表 的實現類各一個;

工廠的抽象類或接口(單個) + 工廠的實現類(多個)

  • 一個用來創建連接數據庫工廠的抽象類或接口;
  • 一個用來創建訪問數據庫A的實例對象的工廠;
  • 一個用來創建訪問數據庫B的實例對象的工廠。

?(注:先挖個坑,有時候可能不確定應該抽象哪個,那就無腦將那個相對不容易變化的和容易變化的分別抽象出來再進行分析就行。但實際上我相關經驗很少,我也不知道怎么樣才算更好,像本例是將訪問用戶表和訪問部門表抽象出來當接口,但感覺反著來抽象出數據庫A和數據庫B當接口也一樣。具體怎么樣的抽象更好我目前也是菜鳥還不知道該怎么回答,等我以后知道答案了一定會填這個坑的。

不過說這么多,也請大家放心向下看,本例我有借鑒一些教材書,這樣子是沒有問題的。之所以加了這個注,是想到可能有人會想問這個問題,為什么要這樣定義,所以才在此說明。)

?3.2、對象之間的關系用UML圖表示如下:

?

3.3、Java實現代碼如下(建議你在本地試一下,加深印象):

用戶bean(舉例就默認為空了,也不會影響到本例運行):

public class User {//用戶表里的屬性和字段
}

部門bean(舉例就默認為空了,也不會影響到本例運行):

public class Department {//部門表里的屬性和字段
}

訪問用戶表接口:

public interface IUser {public void insertUser(User user);//添加public User selectUserById(int id);//查找
}

?訪問部門表接口:

public interface IDepartment {public void insertDepartment(Department department);//添加public Department selectDepartmentById(int id);//查找
}

用來訪問數據庫A里的用戶表的類:

public class DatabaseAUser implements IUser{@Overridepublic void insertUser(User user) {System.out.println("向數據庫A里的User表中增加一條數據");}@Overridepublic User selectUserById(int id) {System.out.println("根據id查詢數據庫A里的User表中一條數據");return null;}
}

用來訪問數據庫B里的用戶表的類:

public class DatabaseBUser implements IUser{@Overridepublic void insertUser(User user) {System.out.println("向數據庫B里的User表中增加一條數據");}@Overridepublic User selectUserById(int id) {System.out.println("根據id查詢數據庫B里的User表中一條數據");return null;}
}

用來訪問數據庫A里的部門表的類:

public class DatabaseADepartment implements IDepartment {@Overridepublic void insertDepartment(Department department) {System.out.println("向數據庫A里的Department表中增加一條數據");}@Overridepublic Department selectDepartmentById(int id) {System.out.println("根據id查詢數據庫A里的Department表中一條數據");return null;}
}

用來訪問數據庫B里的部門表的類:

public class DatabaseBDepartment implements IDepartment {@Overridepublic void insertDepartment(Department department) {System.out.println("向數據庫B里的Department表中增加一條數據");}@Overridepublic Department selectDepartmentById(int id) {System.out.println("根據id查詢數據庫B里的Department表中一條數據");return null;}
}

?工廠接口:

public interface IFactory {public IUser createUserConnect();//創建User表的訪問連接實例public IDepartment createDepartmentConnect();//創建Department表的訪問連接實例
}

創建數據庫A的訪問實例的工廠:

public class DatabaseAFactory implements IFactory {@Overridepublic IUser createUserConnect() {return new DatabaseAUser();}@Overridepublic IDepartment createDepartmentConnect() {return new DatabaseADepartment();}
}

創建數據庫B的訪問實例的工廠:

public class DatabaseBFactory implements IFactory {@Overridepublic IUser createUserConnect() {return new DatabaseBUser();}@Overridepublic IDepartment createDepartmentConnect() {return new DatabaseBDepartment();}
}

?主程序(發起請求的類):

public class Main {public static void main(String[] args) {User user = new User();Department department = new Department();IFactory factoryA = new DatabaseAFactory();//創建數據庫A連接實例的工廠IUser iUserA = factoryA.createUserConnect();iUserA.insertUser(user);//給數據庫A的用戶表增加數據iUserA.selectUserById(1);//查詢數據庫A的用戶表里的數據IDepartment iDepartmentA = factoryA.createDepartmentConnect();iDepartmentA.insertDepartment(department);//給數據庫A的部門表增加數據iDepartmentA.selectDepartmentById(1);//查詢數據庫A的部門表里的數據System.out.println("==========分界線==========");IFactory factoryB = new DatabaseBFactory();//創建數據庫B連接實例的工廠IUser iUserB = factoryB.createUserConnect();iUserB.insertUser(user);//給數據庫B的用戶表增加數據iUserB.selectUserById(1);//查詢數據庫B的用戶表里的數據IDepartment iDepartmentB = factoryB.createDepartmentConnect();iDepartmentB.insertDepartment(department);//給數據庫B的部門表增加數據iDepartmentB.selectDepartmentById(1);//查詢數據庫B的部門表里的數據}
}

在Java中還可以使用反射+配置文件進一步簡化設計,可以把工廠壓縮到只有一個,這里就不再舉例了,可以把上面的Java例子復制到你本地,運行main函數試一下加深理解。這些代碼都是我自己學習的時候根據一些教材手敲的,不存在bug可以直接運行。

如果覺得本文還不錯,就請點個贊吧!如果有建議,也請評論指教和討論!

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

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

相關文章

每日5題Day8 - LeetCode 36 - 40

每一步向前都是向自己的夢想更近一步,堅持不懈,勇往直前! 第一題:36. 有效的數獨 - 力扣(LeetCode) 題目要求我們進行判斷,我們不需要自己填寫,所以要一個標志位,來看當…

Rust:對 CUDA 的支持

主要歸功于Rust CUDA項目,該項目旨在將Rust語言推向高性能GPU計算的前沿。以下是關于Rust對CUDA支持的詳細解釋: Rust CUDA項目:這是一個開源項目,允許開發者在Rust中直接編譯到高度優化的PTX代碼,這是NVIDIA GPU上運…

Go源碼--sync庫(1)sync.Once和

簡介 這篇主要介紹 sync.Once、sync.WaitGroup和sync.Mutex sync.Once once 顧名思義 只執行一次 廢話不說 我們看源碼 英文介紹直接略過了 感興趣的建議讀一讀 獲益匪淺 其結構體如下 Once 是一個嚴格只執行一次的object type Once struct {// 建議看下源碼的注解&#xf…

首個“軟件供應鏈安全”國家標準正式發布!ToB企業震蕩,影響90%開發者

?近日,由開源網安深度參與編制的GB/T 43698-2024《網絡安全技術 軟件供應鏈安全要求》和GB/T 43848-2024《網絡安全技術 軟件產品開源代碼安全評價方法》兩項國家標準正式發布。 GB/T 43698-2024《網絡安全技術 軟件供應鏈安全要求》,是國內首個面向軟件…

Linux .eh_frame section以及libunwind

文章目錄 前言一、LSB二、The .eh_frame section2.1 簡介2.2 The Common Information Entry Format2.1.1 Augmentation String Format 2.3 The Frame Description Entry Format 三、The .eh_frame_hdr section四、libunwind五、基于Frame Pointer和基于unwind 形式的棧回溯比較…

雙向鏈表C++,C#,Java版,這些程序大多已經過測試,一直在用。

先C版吧&#xff0c;我最先用的是C#,后來是Java&#xff0c;后來改用C版的&#xff0c;因為現在一直在用C&#xff0c;單鏈 表一直沒寫上去&#xff0c;因為我很少用&#xff0c;用的是雙鏈表。 執行代碼例子1&#xff1a; int main() { _DList<_string> s…

9.STL中list的常見操作(圖文并茂)

目錄 1.list的介紹及使用 1.1.list的構造 1.2 list iterator的使用 1.3. list capacity 1.4.list modifiers 1.5.list的迭代器失效 1.list的介紹及使用 list介紹 &#xff0c;可以通過以下圖直觀的感受到 vector 和 list 的區別 Vector 插入代價高&#xff0c;但便于排…

力扣HOT100 - 72. 編輯距離

解題思路&#xff1a; 動態規劃 class Solution {public int minDistance(String word1, String word2) {int n1 word1.length();int n2 word2.length();int[][] dp new int[n1 1][n2 1];for (int j 1; j < n2; j) dp[0][j] dp[0][j - 1] 1;for (int i 1; i < …

Android Studio 使用MQTT協議開發應用時怎樣關閉MQTT連接

Android Studio 使用MQTT協議開發應用時怎樣關閉MQTT連接 Android Studio 使用MQTT協議開發應用時關閉MQTT連接 在使用mqtt開發的時候&#xff0c;有時候需要通過 返回 按鈕關閉界面或者Activity時&#xff0c;關閉當前頁面使用的mqtt連接&#xff0c;這里有兩種方式徹底銷毀…

《藝術大觀》知網藝術刊:可加急, 出刊上網快

《藝術大觀》 《藝術大觀》征文通知 《藝術大觀》期刊誠邀學者、藝術家和文化工作者積極投稿&#xff0c;共同探索藝術領域的前沿問題&#xff0c;促進學術交流和藝術創作的發展。我們歡迎各類藝術形式的研究與評論&#xff0c;包括但不限于繪畫、雕塑、音樂、舞蹈、戲劇、電…

共享IP和獨享IP之間的區別了解一下

在網絡環境中&#xff0c;代理服務器作為一種常見的工具&#xff0c;用于保護用戶隱私和拓寬網絡訪問范圍。在選擇代理服務器時&#xff0c;用戶經常會遇到共享IP和獨享IP兩種選擇。那么&#xff0c;這兩種代理方式有何區別呢&#xff1f;今天就為大家詳細解讀這個問題。 兩者…

【數據結構】排序詳解(希爾排序,快速排序,堆排序,插入排序,選擇排序,冒泡排序)

目錄 0. 前情提醒&#xff1a; 1. 插入排序 1.1 基本思想&#xff1a; 1.2 直接插入排序 實現步驟&#xff1a; 動圖演示&#xff1a; 特性總結&#xff1a; 代碼實現&#xff1a; 1.3 希爾排序&#xff08;縮小增量排序&#xff09; 基本思想&#xff1a; 步驟演示&…

AI大模型如何賦能智能座艙

AI 大模型如何賦能智能座艙 從上海車展上&#xff0c;我們看到由于智能座艙配置性價比較高&#xff0c;已經成為車企的核心競爭點之一&#xff0c;隨著座艙硬件規模化裝車&#xff0c;蔚小理、嵐圖、極狐等新勢力開始注重座艙多模態交互&#xff0c;通過集成語音/手勢/觸控打造…

Leetcode—2769. 找出最大的可達成數字【簡單】

2024每日刷題&#xff08;139&#xff09; Leetcode—2769. 找出最大的可達成數字 實現代碼 class Solution { public:int theMaximumAchievableX(int num, int t) {return num t * 2;} };運行結果 之后我會持續更新&#xff0c;如果喜歡我的文章&#xff0c;請記得一鍵三連…

【實戰】SpringBoot整合Websocket、Redis實現Websocket集群負載均衡

文章目錄 前言技術積累什么是Websocket什么是Redis發布訂閱Redis發布訂閱與消息隊列的區別 實戰演示SpringBoot整合WebsoketWebsoket集群負載均衡 實戰測試IDEA啟動兩臺服務端配置nginx負載均衡瀏覽器訪問模擬對話 前言 相信很多同學都用過websocket來實現服務端主動向客戶端推…

【知識蒸餾】deeplabv3 logit-based 知識蒸餾實戰,對剪枝的模型進行蒸餾訓練

本文將對【模型剪枝】基于DepGraph(依賴圖)完成復雜模型的一鍵剪枝 文章中剪枝的模型進行蒸餾訓練 一、邏輯蒸餾步驟 加載教師模型定義蒸餾loss計算蒸餾loss正常訓練 二、代碼 1、加載教師模型 教師模型使用未進行剪枝&#xff0c;并且已經訓練好的原始模型。 teacher_mod…

利用Python去除PDF水印

摘要 本文介紹了如何使用 Python 中的 PyMuPDF 和 OpenCV 庫來從 PDF 文件中移除水印&#xff0c;并將每個頁面保存為圖像文件的方法。我們將深入探討代碼背后的工作原理&#xff0c;并提供一個簡單的使用示例。 導言 簡介&#xff1a;水印在許多 PDF 文件中都很常見&#x…

全國數據庫管理系統設計賽-人大金倉內核實訓安排正式發布

作為數據庫領域國家隊&#xff0c;人大金倉積極響應國家戰略&#xff0c;通過賽題設計、內核技術支撐及賽前培訓等多方面&#xff0c;大力支持全國大學生計算機系統能力大賽-數據庫管理系統設計大賽成功舉辦。目前第二屆全國大賽正在火熱報名中&#xff0c;各種獎項等你來拿&am…

《web應用設計》第八次作業

我的小組長是姚若希&#xff0c;我們組課程設計的題目是&#xff1a;學生管理系統 &#xff0c;我認領的功能模塊是&#xff1a;課程管理 2.查詢并分頁

Html5 + Css3筆記詳細匯總大全

Html5 + Css3知識點Gitee地址 html5css3知識點: 尚硅谷—HTML5+CSS3知識點 介紹 屬性 屬性:在標簽中(開始標簽或自結束標簽)還可以設置屬性 屬性是一個名值對(x=y) 屬性用來設置標簽中的內容如何顯示 屬性和標簽名或其它屬性應該使用空格隔開 屬性名不能瞎寫,應該根據文…