欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

Java設(shè)計模式之創(chuàng)建者模式詳解

 更新時間:2023年08月18日 08:30:46   作者:劉婉晴  
這篇文章主要介紹了Java設(shè)計模式之創(chuàng)建者模式詳解,創(chuàng)建者模式,顧名思義,就是提供友好的創(chuàng)建對象的方式?,對象都是?new?出來的,但是在一些情況下,這種方式不是很友好,首先,它不夠直觀,需要的朋友可以參考下

前言

創(chuàng)建者模式,顧名思義,就是提供友好的創(chuàng)建對象的方式 ,對象都是 new 出來的,但是在一些情況下,這種方式不是很友好

首先,它不夠直觀,其次,在一些情況下,這樣創(chuàng)建的對象不滿足要求。

比如 : 當(dāng)我們需要創(chuàng)建單例的對象,那我們就不能每次用的時候就重新 new, 這樣很明顯是不合理的 。

一、工廠模式

引入工廠類的原因 : 是因為我們需要兩個或者兩個以上的工廠生產(chǎn)對象,假如我們就需要一個對象的工廠,那就沒必要引入工廠類了 。

1. 簡單工廠模式

就一個工廠,它具有不同的方法,生產(chǎn)出不同的產(chǎn)品 。

在這里插入圖片描述

2. 工廠模式

我們需要兩個及以上的工廠,所以抽象出一個工廠接口,其他工廠實現(xiàn)類實現(xiàn)這個抽象接口,重寫創(chuàng)建方法 。

在這里插入圖片描述

3. 抽象工廠模式

涉及到產(chǎn)品族問題 , 調(diào)用的時候先選擇工廠,再調(diào)用其方法,生成相應(yīng)的產(chǎn)品。

在這里插入圖片描述

工廠模式在 Spring 框架中的使用

Spring 框架通過反射機制實現(xiàn)工廠模式,從而降低了程序的耦合程度 。

具體實現(xiàn)思路為 : 讀取配置文件中相關(guān)值, 然后通過反射 Class.forName 得到該值對應(yīng)的類,再通過 newInstance() 獲取該類的實例返回 。

我們調(diào)用時只需要 : Factory.getXXX("我們定義在配置文件中的 Bean 名稱")

二、單例模式

1. 餓漢式實現(xiàn)

私有構(gòu)造方法 + 創(chuàng)建靜態(tài)實例

public class Singleton {
    // 私有構(gòu)造方法
    private Singleton() {};
    // 創(chuàng)建私有靜態(tài)實例
    private static Singleton instance = new Singleton();
    public static Singleton getInstance() {
        return instance;
    }
}

缺點 : 不想用 Singleton 實例時,它也生成了,因為是 static 的, 這個類被第一次使用時就會被生成 。

2. 飽漢式實現(xiàn) 雙重檢查機制原理

私有構(gòu)造方法 + volatile 修飾 + 雙重判空,加鎖

public class Singleton {
    // 私有構(gòu)造方法
    private Singleton() {}
    // valitale 修飾
    private static volatile Singleton instance = null;
    public static Singleton getInstance() {
    	// 雙重檢查是否為 null
        if (instance == null) {
            // 加鎖
            synchronized (Singleton.class) {
                if (instance == null) {
                    instance = new Singleton();
                }
            }
        }
        return instance;
    }
}

為什么要在實例化時加 synchronized 鎖, 不是已經(jīng)用 volatile 關(guān)鍵字修飾了嗎 ?

因為 volatile 只可以保證變量的可見性 和 防止實例化時指令重排 ,它不能保證操作的原子性 。我們要求只能有一個線程去實例化,不能一堆線程一起進去實例化 。

不是已經(jīng)有 synchronized 鎖了嗎,為什么還要 volatile 關(guān)鍵字修飾 ?

因為我們得保證 一個線程實例化 Singleton 后,其他線程可見,直接返回就行,所以我們需要 volatile 去保證 Singleton 在多個線程中的可見性 , 不被 JVM 緩存。

除此之外,它也通過防止對象創(chuàng)建時的指令重排,而使得線程安全 。

什么是指令重排 ? 創(chuàng)建對象時,先分配內(nèi)存空間,然后實例指向該空間地址,然后才初始化 。

正常情況應(yīng)該是, 分配內(nèi)存空間 — 初始化 — 指向該空間地址

如果不用 volatile 修飾, 發(fā)生指令重排時, 創(chuàng)建對象的線程只是指向了空間地址,但是還沒初始化,但是因為已經(jīng)指向地址了

下一個線程在第一重 null 檢查時,判斷為非 null,直接返回了,但是返回的實例還沒初始化 。這是線程不安全的,所以需要 volatile 。

3. 嵌套類實現(xiàn)

利用嵌套類可以 訪問外部類 的屬性和方法 。在嵌套類中實例化 Singleton 。

public class Singleton {
    private Singleton() {}
    // 利用嵌套類可以訪問外部類的屬性和方法
    private static class Holder {
        private static Singleton instance = new Singleton();
    }
    public static Singleton getInstance() {
        return Holder.instance;
    }
}

4. 枚舉實現(xiàn) *

public enum Singleton {
     INSTANCE;
}

據(jù)說被谷歌大佬作為實現(xiàn)單例的最佳實踐 —— 即簡單又安全

下面我們來一起簡單看一下枚舉為什么可以實現(xiàn)單例 ?

我們自定義的枚舉類 默認 繼承 Enum, Enum 的源碼如下 :

public abstract class Enum<E extends Enum<E>>
        implements Comparable<E>, Serializable {
    // 枚舉項的名字 , 程序員用 toString 方法而不是這個
    private final String name;
    public final String name() {
        return name;
    }
	// 程序員用不到的,給使用枚舉類型的 API 使用,比如  java.util.EnumSet
    private final int ordinal;
    public final int ordinal() {
        return ordinal;
    }
	// 程序員用不到的,給編譯器發(fā)出的代碼,告訴編譯器實例化這個枚舉類
    protected Enum(String name, int ordinal) {
        this.name = name;
        this.ordinal = ordinal;
    }
    public String toString() {
        return name;
    }
    public final boolean equals(Object other) {
        return this==other;
    }
    public final int hashCode() {
        return super.hashCode();
    }
	// 克隆枚舉類拋出異常,這保證了枚舉永遠不會被克隆,這對于保持它們的 "單例 "狀態(tài)是必要的。
    protected final Object clone() throws CloneNotSupportedException {
        throw new CloneNotSupportedException();
    }
    public final int compareTo(E o) {
        Enum<?> other = (Enum<?>)o;
        Enum<E> self = this;
        if (self.getClass() != other.getClass() && // optimization
            self.getDeclaringClass() != other.getDeclaringClass())
            throw new ClassCastException();
        return self.ordinal - other.ordinal;
    }
    @SuppressWarnings("unchecked")
    public final Class<E> getDeclaringClass() {
        Class<?> clazz = getClass();
        Class<?> zuper = clazz.getSuperclass();
        return (zuper == Enum.class) ? (Class<E>)clazz : (Class<E>)zuper;
    }
	// 返回這個枚舉常量的枚舉類型所對應(yīng)的Class對象
    public static <T extends Enum<T>> T valueOf(Class<T> enumType,
                                                String name) {
        T result = enumType.enumConstantDirectory().get(name);
        if (result != null)
            return result;
        if (name == null)
            throw new NullPointerException("Name is null");
        throw new IllegalArgumentException(
            "No enum constant " + enumType.getCanonicalName() + "." + name);
    }
    protected final void finalize() { }
    private void readObject(ObjectInputStream in) throws IOException,
        ClassNotFoundException {
        throw new InvalidObjectException("can't deserialize enum");
    }
    private void readObjectNoData() throws ObjectStreamException {
        throw new InvalidObjectException("can't deserialize enum");
    }
}

我們定義的枚舉類里面的每個枚舉項都是一個 Enum, 這個 Enum 都是 static final 類型的,也就是說不容許被修改,初次之外我們的自定義的枚舉類默認私有構(gòu)造方法(體現(xiàn)在編譯完之后),不能被程序員改成 public 的

我們再翻譯一下,翻譯成我覺得更好理解的

首先, 枚舉類里的枚舉項都是 枚舉類 Enum 的實例,枚舉幫我們自動處理了一些東西,簡化了代碼其幫我們進行的操作就是對每個枚舉項私有了構(gòu)造方法,然后實例定義成 static final 類型的,就是相當(dāng)于我們餓漢式的實現(xiàn)代碼,其幫我們封裝好了,就是其幫我們封裝好了餓漢式的實現(xiàn)代碼除此之外,我們枚舉類的實例只能有我們在枚舉類里的那幾個,對單例來說只有那一個,不容許再進行擴張實例 ,只能有那一個。

三、建造者模式

鏈式調(diào)用方法,實現(xiàn)對象的創(chuàng)建 。為什么優(yōu)于 new ?

首先,一個設(shè)計模式是最佳實踐是相對其使用場景說的。

建造者模式適用于要創(chuàng)建的對象非常復(fù)雜的情況,構(gòu)造者模式讓這個復(fù)雜類的裝配變得按部就班又直觀。

舉個栗子

MyBatis 中讀取配置文件構(gòu)建配置類,這個配置類超級大 。所以使用了建造者模式,把這個復(fù)雜類的構(gòu)建拆分成了好多 builder,根據(jù)傳入的參數(shù)的不同進行創(chuàng)建 。

四、原型模式

對于原型模式,首先我們需要記住的就是實現(xiàn) Cloneable 接口,并且重寫 clone 方法 。(注意深淺克隆的區(qū)別)

其實,按照我對原型模式的理解,就是新建了一個模板。然后,我們不斷去克隆這個模版,更改模版中的一些值。

到此這篇關(guān)于Java設(shè)計模式之創(chuàng)建者模式詳解的文章就介紹到這了,更多相關(guān)Java創(chuàng)建者模式內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • 詳解Maven安裝教程及是否安裝成功

    詳解Maven安裝教程及是否安裝成功

    這篇文章主要介紹了詳解Maven安裝教程及是否安裝成功,小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧
    2018-12-12
  • Java編程中的防轉(zhuǎn)義和轉(zhuǎn)義技巧匯總

    Java編程中的防轉(zhuǎn)義和轉(zhuǎn)義技巧匯總

    在編程過程中,我們常常需要處理特殊字符和特定上下文,以確保生成的內(nèi)容在正確的環(huán)境中能夠被解析和顯示,本文將介紹一些常見的防轉(zhuǎn)義或者轉(zhuǎn)義處理的編程技巧,需要的可以參考一下
    2023-07-07
  • SpringBoot使用Nacos動態(tài)配置數(shù)據(jù)源的方法

    SpringBoot使用Nacos動態(tài)配置數(shù)據(jù)源的方法

    這篇文章主要介紹了SpringBoot使用Nacos動態(tài)配置數(shù)據(jù)源的方法,本文給大家介紹的非常詳細,對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友可以參考下
    2021-03-03
  • Java線程安全狀態(tài)專題解析

    Java線程安全狀態(tài)專題解析

    線程安全是多線程編程時的計算機程序代碼中的一個概念。在擁有共享數(shù)據(jù)的多條線程并行執(zhí)行的程序中,線程安全的代碼會通過同步機制保證各個線程都可以正常且正確的執(zhí)行,不會出現(xiàn)數(shù)據(jù)污染等意外情況
    2022-03-03
  • springboot使用校驗框架validation校驗的示例

    springboot使用校驗框架validation校驗的示例

    這篇文章主要介紹了springboot使用校驗框架validation校驗的示例,小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧
    2018-02-02
  • Java?MyBatis實戰(zhàn)之QueryWrapper中and和or拼接技巧大全

    Java?MyBatis實戰(zhàn)之QueryWrapper中and和or拼接技巧大全

    在Java中QueryWrapper是MyBatis-Plus框架中的一個查詢構(gòu)造器,它提供了豐富的查詢方法,其中包括and和or方法,可以用于構(gòu)建復(fù)雜的查詢條件,這篇文章主要給大家介紹了關(guān)于Java?MyBatis實戰(zhàn)之QueryWrapper中and和or拼接技巧的相關(guān)資料,需要的朋友可以參考下
    2024-07-07
  • Spring?Data?JPA實現(xiàn)審計功能過程詳解

    Spring?Data?JPA實現(xiàn)審計功能過程詳解

    Spring?Data?JPA為跟蹤持久性層的變化提供了很好的支持。通過使用審核,我們可以存儲或記錄有關(guān)實體更改的信息,例如誰創(chuàng)建或更改了實體以及何時進行更改
    2023-02-02
  • Java中Validated、Valid 、Validator區(qū)別詳解

    Java中Validated、Valid 、Validator區(qū)別詳解

    本文主要介紹了Java中Validated、Valid 、Validator區(qū)別,有時候面試的時候會被問到,他們的區(qū)別你知道幾個,本文就來詳細的介紹一下
    2021-08-08
  • JAVA多線程編程實例詳解

    JAVA多線程編程實例詳解

    這篇文章主要介紹了JAVA多線程編程,結(jié)合實例形式總結(jié)分析了多線程、鎖、線程池等相關(guān)原理及使用技巧,需要的朋友可以參考下
    2019-09-09
  • java模擬斗地主發(fā)牌功能

    java模擬斗地主發(fā)牌功能

    這篇文章主要為大家詳細介紹了java模擬斗地主發(fā)牌,文中示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2020-10-10

最新評論