設計模式-創建型模式(詳解)

創建型模式

單例模式

一個類只允許創建一個對象,稱為單例。

單例體現:配置類、連接池、全局計數器、id生成器、日志對象。

懶漢式
  1. (線程不安全) 單例:【不可用】

用到該單例對象的時候再創建。但存在很大問題,單線程下這段代碼沒有問題,但是在多線程下有很大問題。

public class LazyMan {private LazyMan(){};public static LazyMan lazyMan;   public static LazyMan getInstance(){if (lazyMan==null){lazyMan = new LazyMan();   //用到該單例對象的時候再創建,這里沒加鎖,如果多個線程進入,會并發產生多個實例}return lazyMan;}
}
  1. (線程安全)單例:【不推薦使用】

同步方法

缺點:效率低,每次getInstance時都要同步處理,存在性能問題,實際開發不推薦

public class LazyMan {private LazyMan(){};   //私有化構造函數,防止外部實例化public static LazyMan lazyMan;   public static synchroized LazyMan getInstance(){  //加鎖if (lazyMan==null){lazyMan = new LazyMan();   //用到該單例對象的時候再創建}return lazyMan;}
}

雙檢鎖(線程安全):【推薦使用】

  • 實例化代碼只用執行一次,后面再次訪問時,判斷if (singleton == null),不為空則直接return實例化對象。
  • 利用volatile關鍵字保證了可見性,利用雙重檢查機制減少了同步帶來的性能損耗。
public class Singleton {private static volatile Singleton instance;// 私有構造函數,防止外部實例化private Singleton() {}public static synchronized Singleton getInstance() {if (instance == null) {synchronized (Singleton.class) {if (instance == null) {instance = new Singleton();}}}return instance;}
}
餓漢式

(靜態常量)【可用】

類一旦加載就創建一個單例,保證在調用getInstance方法之前單例已經存在,即沒有延遲加載,這種餓漢式單例會造成空間浪費。

public class Hungry {private Hungry(){}private final static Hungry HUNGRY = new Hungry();    //在類內部就創建了一個靜態對象,并且get方法返回該對象public static Hungry getInstance(){return HUNGRY;}
}
//或者 靜態代碼塊形式
public class Hungry {static{private final static Hungry HUNGRY = new Hungry();    }     private Hungry(){}public static Hungry getInstance(){return HUNGRY;}
}Hungry in1=Hungry.getInstance()
Hungry in2=Hungry.getInstance()        //in1==in2
靜態內部類
  • (線程安全)單例:【推薦使用】
  • 不僅線程安全,還實現了延遲加載
public class Inner {private Inner(){}//直到調用 getInstance() 方法之前,Inner 實例都不會被創建,實現了延遲初始化public static Inner getInstance(){return InnerClass.INNER;}private static class InnerClass{          private static final Inner INNER = new Inner();  //靜態字段只會在類加載時被初始化一次,線程安全}
}
枚舉
  • (線程安全)【推薦使用】不僅線程安全,還能防止反序列化導致重新創建新的對象
class SingletonEnum{// 1、創建一個枚舉public enum CreateInstance{// 枚舉實例,底層變量定義是public static final,因此它在 JVM 中只會被初始化一次,并且是線程安全的INSTANCE;private SingletonEnum instance;// 保證不能在類外部通過new構造器來構造對象private CreateInstance() {instance = new SingletonEnum();System.out.println(Thread.currentThread().getName());}// 創建一個公共的方法,由實例調用返回單例類public SingletonEnum getInstance() {return instance;}}public static void main(string[] args){Singleton instance = CreateInstance.INSTANCE.getInstance();singleton instance2= CreateInstance.INSTANCE.getInstance();System.out.println(instance == instance2);  //輸出 true}
}

原型模式

通過拷貝來創建新的對象,而不是通過實例化一個類,減少創建對象的成本,適用于創建對象成本高,需要大量相似對象的情況。

  • Java 的 clone 僅是淺拷貝,默寫場景需要 使用深拷貝避免共享數據的導致錯亂
  • 在 Spring 中,將 Bean 的作用范圍設置為 prototype,這樣每次從容器中獲取 Bean 時,都會返回一個新的實例。

一個簡單的原型模式實現例子如下

先創建一個原型類:

public class Prototype implements Cloneable {     //一個原型類,只需要實現Cloneable接口,覆寫clone方法@Overridepublic Object clone() throws CloneNotSupportedException { Prototype proto = (Prototype) super.clone();		   //因為此處的重點是super.clone()這句話return proto;}
}
Prototype pro=new Prototype();
Prototype pro1=(Prototype)pro.clone(); //克隆 二者地址不同
//不管深淺,拷貝出來的對象的地址是不一樣的,只是若對象里面有引用,那么深淺拷貝會不一樣
@Data
public class Prototype implements Cloneable, Serializable {private static final long serialVersionUID = 1L;private String string;private SerializableObject obj;/* 淺拷貝 */public Object clone() throws CloneNotSupportedException {Prototype proto = (Prototype) super.clone();return proto;}/* 深拷貝 */public Object deepClone() throws IOException, ClassNotFoundException {/* 寫入當前對象的二進制流 */ByteArrayOutputStream bos = new ByteArrayOutputStream();ObjectOutputStream oos = new ObjectOutputStream(bos);oos.writeObject(this);/* 讀出二進制流產生的新對象 */ByteArrayInputStream bis = new ByteArrayInputStream(bos.toByteArray());ObjectInputStream ois = new ObjectInputStream(bis);return ois.readObject();}}
class SerializableObject implements Serializable {private static final long serialVersionUID = 1L;
}

工廠模式

簡單工廠

簡單工廠模式通過傳入的不同的參數來控制創建哪個具體產品。它的實現較為簡單,但不夠靈活,違反了開放封閉原則。

  • 抽象產品接口: 定義了產品的規范,描述了產品的主要特性和功能
  • 具體產品實現類: 實現或者繼承抽象產品的子類
  • 簡單工廠: 提供了創建產品的方法,調用者通過該方法來獲取產品。
// 產品接口
public interface Product {void use();
}
// 具體產品A
public class ConcreteProductA implements Product {@Overridepublic void use() {System.out.println("Using ConcreteProductA");}
}
// 具體產品B
public class ConcreteProductB implements Product {@Overridepublic void use() {System.out.println("Using ConcreteProductB");}
}// 簡單工廠類
public class SimpleFactory {public static Product createProduct(String type) {switch (type) {case "A":return new ConcreteProductA();case "B":return new ConcreteProductB();default:throw new IllegalArgumentException("Unknown product type");}}
}
// 客戶端代碼
public class Client {public static void main(String[] args) {Product productA = SimpleFactory.createProduct("A");productA.use(); // Output: Using ConcreteProductAProduct productB = SimpleFactory.createProduct("B");productB.use(); // Output: Using ConcreteProductB}
}
工廠方法

一個具體的工廠類負責生產一種產品

抽象工廠==>具體工廠

抽象產品==>具體產品(由具體工廠創建)

// 抽象產品
interface Product {void use();
}
// 具體產品A
class ConcreteProductA implements Product {public void use() {System.out.println("Using ConcreteProductA");}
}
// 具體產品B
class ConcreteProductB implements Product {public void use() {System.out.println("Using ConcreteProductB");}
}// 抽象工廠
interface Factory {Product createProduct();
}
// 具體工廠A
class ConcreteFactoryA implements Factory {public Product createProduct() {return new ConcreteProductA();}
}
// 具體工廠B
class ConcreteFactoryB implements Factory {public Product createProduct() {return new ConcreteProductB();}
}// 使用工廠方法創建產品
public class Client {public static void main(String[] args) {new ConcreteFactoryA().createProduct();new ConcreteFactoryB().createProduct() ;}
}
抽象工廠
  • 是工廠方法的一種變體,創建一系列相關或相互依賴對象的接口,即生產一系列產品
  • 給具體工廠類 添加一個工廠接口,使得工廠類可以多實現
// 抽象產品A
public interface ProductA {void use();
}
// 具體產品A1
public class ConcreteProductA1 implements ProductA {@Overridepublic void use() {System.out.println("Using ConcreteProductA1");}
}
// 具體產品A2
public class ConcreteProductA2 implements ProductA {@Overridepublic void use() {System.out.println("Using ConcreteProductA2");}
}// 抽象產品B
public interface ProductB {void eat();
}
// 具體產品B1
public class ConcreteProductB1 implements ProductB {@Overridepublic void eat() {System.out.println("Eating ConcreteProductB1");}
}
// 具體產品B2
public class ConcreteProductB2 implements ProductB {@Overridepublic void eat() {System.out.println("Eating ConcreteProductB2");}
}// 抽象工廠
public interface AbstractFactory {ProductA createProductA();ProductB createProductB();
}// 具體工廠1
public class ConcreteFactory1 implements AbstractFactory {@Overridepublic ProductA createProductA() {return new ConcreteProductA1();}@Overridepublic ProductB createProductB() {return new ConcreteProductB1();}
}// 具體工廠2
public class ConcreteFactory2 implements AbstractFactory {@Overridepublic ProductA createProductA() {return new ConcreteProductA2();}@Overridepublic ProductB createProductB() {return new ConcreteProductB2();}
}// 使用抽象工廠創建產品
public class Client {public static void main(String[] args) {AbstractFactory factory1 = new ConcreteFactory1();ProductA productA1 = factory1.createProductA();ProductB productB1 = factory1.createProductB();productA1.use();productB1.eat();AbstractFactory factory2 = new ConcreteFactory2();ProductA productA2 = factory2.createProductA();ProductB productB2 = factory2.createProductB();productA2.use();productB2.eat();}
}
建造者模式

建造者模式使用相同的代碼基礎構建不同類型的對象,通過將對象構建過程分解為多個較小的步驟來實現此目的,如StringBuilder

兩個主要組成部分:建造者和產品 建造者是負責構建產品的類,產品則是最終構建的對象

例如 hutool 內的 ExecutorBuilder 就提供了建造者模式創建線程池的方法

public ExecutorService buildTaskPool() {
return ExecutorBuilder.create().setCorePoolSize(10).setMaxPoolSize(20).setWorkQueue(new LinkedBlockingQueue<>(100)).setKeepAliveTime(3L, TimeUnit.SECONDS).setThreadFactory(new ThreadFactoryBuilder().setNamePrefix("task-pool-").build()).build();
}
public class Product {       //最終構建的對象,即產品private String partA;private String partB;private String partC;public void setPartA(String partA) {this.partA = partA;}public void setPartB(String partB) {this.partB = partB;} public void setPartC(String partC) {this.partC = partC;}// other product-related methods}public interface Builder {   //Builder接口或抽象類,定義了構建過程的關鍵步驟void buildPartA();void buildPartB();void buildPartC();Product getResult();
}public class ConcreteBuilder implements Builder {  //實現了Builder接口中定義的方法,以構建具體的Product對象private Product product = new Product();public void buildPartA() {product.setPartA("Part A");}public void buildPartB() {product.setPartB("Part B");}public void buildPartC() {product.setPartC("Part C");}    public Product getResult() {return product;} 
}public class Director {      //指導類,它負責使用Builder對象來構建最終的Product對象private Builder builder;public Director(Builder builder) {  //實現依賴倒置原則,依賴于抽象this.builder = builder; }public void construct() {   //確保Product對象按照指定的順序創建builder.buildPartA();builder.buildPartB();builder.buildPartC();}
}Builder builder = new ConcreteBuilder();   //創建建造者
Director director = new Director(builder);  //創建指導
director.construct();     
Product product = builder.getResult();
//這將構建一個Product對象,并將其存儲在product變量中。

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

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

相關文章

什么是BI?有哪些應用場景

BI&#xff08;Business Intelligence&#xff0c;商業智能&#xff09;是通過技術手段對海量業務數據進行采集、整合、分析和可視化的過程&#xff0c;旨在幫助企業從數據中獲取洞察&#xff0c;支持決策。其核心是通過工具&#xff08;如Quick BI&#xff09;將原始數據轉化為…

從零開始:使用Vite和Vue.js搭建一個空項目

進入node.js官網 https://nodejs.org/zh-cn 下載node.js 點擊進行安裝&#xff0c; 完成之后&#xff0c;按住shift鼠標右鍵&#xff0c;打開powershell窗口 輸入node -v &#xff0c;出現版本號就是成功了 node -v 接下來&#xff0c;打開設置&#xff0c;搜索開發者設置&…

Redis 核心數據類型及典型使用場景詳解

在日常開發中&#xff0c;Redis 不僅是緩存利器&#xff0c;更是一套高性能的數據結構服務。你是否真的了解 Redis 提供的五種核心數據類型&#xff1f;它們各自的底層結構和適用場景又有哪些差異&#xff1f;本篇博客將深入解析 Redis 的數據類型及其典型應用&#xff0c;助你…

threejs webVR獲取相機正前方向量

通常獲取相機正前方可以使用camera.getWorldDirection(new Vector3()) 函數來得到&#xff0c;但是在threejs0.139.2版本中進入VR后使用上面函數獲取的數據是固定不變的&#xff0c;不管是否旋轉了頭盔&#xff0c;經過一番研究發現必須使用renderer.xr.getCamera() 此函數獲取…

華為OD-2024年E卷-字符統計及重排[100分] -- python

問題描述&#xff1a; 給出一個僅包含字母的字符串&#xff0c;不包含空格&#xff0c;統計字符串中各個字母(區分大小寫)出現的次數&#xff0c;并按照字母出現次數從大到小的順序輸出各個字母及其出現次數。如果次數相同&#xff0c;按照自然順序進行排序&#xff0c;且小寫…

MCP(模型上下文協議)協議和Http協議對比

MCP&#xff08;Model Context Protocol&#xff0c;模型上下文協議&#xff09;和 HTTP&#xff08;HyperText Transfer Protocol&#xff0c;超文本傳輸協議&#xff09;是兩種定位完全不同的協議&#xff0c;主要區別如下&#xff1a; 1. 核心定位 HTTP 通用網絡通信協議&am…

C++打印乘法口訣表

int main()??&#xff1a; 這是C 程序的入口點。每個C 程序都必須有一個 main 函數&#xff0c;程序從這里開始執行。 ??外層 for 循環??&#xff1a; for (int i 1; i < 10; i) { int i 1&#xff1a;定義并初始化循環變量 i 為 1。這里的 i 代表乘法表中的行…

RoGBAG 與 MCAP

RoGBAG 和 MCAP 都是機器人領域常用的二進制數據格式&#xff0c;用于存儲傳感器數據、控制命令和狀態信息。兩者主要區別在于&#xff1a; RoGBAG&#xff1a;ROS 1/2 的標準日志格式&#xff0c;采用 LZF/LZ4 壓縮&#xff0c;適合中小型數據集 MCAP&#xff1a;新一代機器人…

Ubuntu 空間占用情況排查常用命令

查看當前目錄總大小及子目錄占用詳情 du -sh * | sort -hr ??du??&#xff1a;磁盤使用統計命令??-s??&#xff1a;顯示每個參數的總計&#xff08;不遞歸子目錄&#xff09;??-h??&#xff1a;以人類可讀格式&#xff08;KB/MB/GB&#xff09;顯示??*??&…

C語言編譯優化實戰與技巧

一.概述 1.C語言編譯優化介紹 C語言編譯優化是提升程序性能的核心手段&#xff0c;涉及從源代碼到機器碼的多層次轉換&#xff0c;下面從優化級別、常用技術、內存管理、指令調度等多個維度詳細介紹。 2.編譯器優化等級&#xff08;GCC/Clang&#xff09; 二.常用優化技術 1…

Seq2Seq理解

Seq2Seq理解 寫在前面&#xff1a;學習Seq2Seq由于前面底子沒打好導致理解起來非常困難&#xff0c;今天索性全部搞懂邏輯部分&#xff0c;后續我會把所學的一些算法全部以理解代碼的形式發布出來&#xff0c;課程代碼內容全部來自李沐老師的視頻&#xff0c;再次感謝&#xf…

旅游規劃智能體之ReAct Agent實戰

引言 本文將系統性地介紹如何運用ReAct框架構建旅游規劃智能體&#xff0c;通過LangChain的create_react_agent方法實現智能決策和多步驟任務處理。ReAct框架作為現代AI Agent開發的核心技術之一&#xff0c;為構建具備復雜推理能力的智能系統提供了重要的理論基礎和實踐指導。…

組合模式深度解析:Java設計模式實戰指南與樹形結構處理架構設計

組合模式深度解析&#xff1a;Java設計模式實戰指南與樹形結構處理架構設計 &#x1f31f; 嗨&#xff0c;我是IRpickstars&#xff01; &#x1f30c; 總有一行代碼&#xff0c;能點亮萬千星辰。 &#x1f50d; 在技術的宇宙中&#xff0c;我愿做永不停歇的探索者。 ? 用…

PHP設計模式實戰:領域驅動設計與六邊形架構

在前三篇關于電子商務系統、API服務和微服務架構的基礎上,我們將深入探討如何運用領域驅動設計(DDD)和六邊形架構(Hexagonal Architecture)構建更加清晰、可維護的業務系統。隨著業務復雜度增加,傳統的分層架構往往難以清晰地表達業務邏輯,而DDD提供了一套方法論來解決這一問…

為什么在1080p的屏幕下,通常觀看4K視頻要比1080p的視頻來的清晰?

一、分辨率與像素密度的底層邏輯 4K與1080p的像素差異 4K分辨率通常為38402160&#xff08;約830萬像素&#xff09;&#xff0c;而1080p為19201080&#xff08;約207萬像素&#xff09;&#xff0c;4K像素數量是1080p的4倍。當4K視頻在1080p屏幕上播放時&#xff0c;需要將4倍…

C++ Json-Rpc框架 項目邏輯設計

Server ? RpcServer&#xff1a;rpc功能模塊與?絡通信部分結合 RpcServer分為兩部分 1.提供函數調用服務的服務端 2.提供服務注冊的客戶端 對內提供好rpc服務的路由關系管理map<method,服務描述對象>&#xff0c;以及rpc請求消息的分發處理函數。給Dispatcher提供onRpc…

Agent開發相關工具

LangChain LangChain LangGraph LangGraph LangSmith GraphRAG RAGFlow what-is-graphrag Dify n8n vLLM Model Context Protocol AutoGen CodeMirror Milvus Chroma

進程管理(一)

一. 進程的基本信息 1.1 進程的概念、組成及信息 1.1.1 概念 進程的概念與程序相對&#xff0c;程序是靜態的而進程是動態的&#xff0c;一個程序執行多次會有多個不同的進程 1.1.2 組成 PCB&#xff08;程序控制塊&#xff09;&#xff1a; 是一種保存下列信息的數據結構&…

k8s 中 cpu 核數的理解

物理核還是邏輯核 在 Kubernetes&#xff08;k8s&#xff09;編排文件&#xff08;如 Pod 或 Deployment 的 YAML 文件&#xff09;中設置的 CPU 核數&#xff0c;針對的是邏輯核數&#xff08;Logical Cores&#xff09;&#xff0c;而非物理核數&#xff08;Physical Cores&…

arcpy數據分析自動化(2)

數據處理 在提取數據后&#xff0c;我們需要對字段進行標準化處理&#xff0c;例如統一土地利用類型的命名。 # 定義字段映射字典 field_mapping {"Residential": "居住用地","Commercial": "商業用地","Industrial": &q…