国产 无码 综合区,色欲AV无码国产永久播放,无码天堂亚洲国产AV,国产日韩欧美女同一区二区

設(shè)計模式--------創(chuàng)建型模式

這篇具有很好參考價值的文章主要介紹了設(shè)計模式--------創(chuàng)建型模式。希望對大家有所幫助。如果存在錯誤或未考慮完全的地方,請大家不吝賜教,您也可以點擊"舉報違法"按鈕提交疑問。

創(chuàng)建型模式

用于描述“怎樣創(chuàng)建對象”,它的主要特點是“將對象的創(chuàng)建與使用分離”。GoF(四人組)書中提供了單例、原型、工廠方法、抽象工廠、建造者等 5 種創(chuàng)建型模式。

1.單例設(shè)計模式

單例模式(Singleton Pattern)是 Java 中最簡單的設(shè)計模式之一。這種類型的設(shè)計模式屬于創(chuàng)建型模式,它提供了一種創(chuàng)建對象的最佳方式。

這種模式涉及到一個單一的類,該類負(fù)責(zé)創(chuàng)建自己的對象,同時確保只有單個對象被創(chuàng)建。這個類提供了一種訪問其唯一的對象的方式,可以直接訪問,不需要實例化該類的對象。

1.1 單例模式的結(jié)構(gòu)

單例模式的主要有以下角色:

  • 單例類。只能創(chuàng)建一個實例的類
  • 訪問類。使用單例類

1.2 單例模式的實現(xiàn)

單例設(shè)計模式分類兩種:

? 餓漢式:類加載就會導(dǎo)致該單實例對象被創(chuàng)建

? 懶漢式:類加載不會導(dǎo)致該單實例對象被創(chuàng)建,而是首次使用該對象時才會創(chuàng)建

1.2.1. 餓漢式-方式1(靜態(tài)變量方式)
/**
 * 餓漢式
 *      靜態(tài)變量創(chuàng)建類的對象
 */
public class Singleton {
    //私有構(gòu)造方法
    private Singleton() {}

    //在成員位置創(chuàng)建該類的對象
    private static Singleton instance = new Singleton();

    //對外提供靜態(tài)方法獲取該對象
    public static Singleton getInstance() {
        return instance;
    }
}

說明:

? 該方式在成員位置聲明Singleton類型的靜態(tài)變量,并創(chuàng)建Singleton類的對象instance。instance對象是隨著類的加載而創(chuàng)建的。如果該對象足夠大的話,而一直沒有使用就會造成內(nèi)存的浪費。

1.2.2. 餓漢式-方式2(靜態(tài)代碼塊方式)
/**
 * 餓漢式
 *      在靜態(tài)代碼塊中創(chuàng)建該類對象
 */
public class Singleton {

    //私有構(gòu)造方法
    private Singleton() {}

    //在成員位置創(chuàng)建該類的對象
    private static Singleton instance;

    static {
        instance = new Singleton();
    }

    //對外提供靜態(tài)方法獲取該對象
    public static Singleton getInstance() {
        return instance;
    }
}

說明:

? 該方式在成員位置聲明Singleton類型的靜態(tài)變量,而對象的創(chuàng)建是在靜態(tài)代碼塊中,也是對著類的加載而創(chuàng)建。所以和餓漢式的方式1基本上一樣,當(dāng)然該方式也存在內(nèi)存浪費問題。

1.2.3. 餓漢式-枚舉方式

枚舉類實現(xiàn)單例模式是極力推薦的單例實現(xiàn)模式,因為枚舉類型是線程安全的,并且只會裝載一次,設(shè)計者充分的利用了枚舉的這個特性來實現(xiàn)單例模式,枚舉的寫法非常簡單,而且枚舉類型是所用單例實現(xiàn)中唯一一種不會被破壞的單例實現(xiàn)模式。

/**
 * 枚舉方式
 */
public enum Singleton {
    INSTANCE;
}

說明:

? 枚舉方式屬于惡漢式方式。

1.2.4. 懶漢式-方式1(線程不安全)
/**
 * 懶漢式
 *  線程不安全
 */
public class Singleton {
    //私有構(gòu)造方法
    private Singleton() {}

    //在成員位置創(chuàng)建該類的對象
    private static Singleton instance;

    //對外提供靜態(tài)方法獲取該對象
    public static Singleton getInstance() {

        if(instance == null) {
            instance = new Singleton();
        }
        return instance;
    }
}

說明:

? 從上面代碼我們可以看出該方式在成員位置聲明Singleton類型的靜態(tài)變量,并沒有進行對象的賦值操作,那么什么時候賦值的呢?當(dāng)調(diào)用getInstance()方法獲取Singleton類的對象的時候才創(chuàng)建Singleton類的對象,這樣就實現(xiàn)了懶加載的效果。但是,如果是多線程環(huán)境,會出現(xiàn)線程安全問題。

1.2.5. 懶漢式-方式2(線程安全)
/**
 * 懶漢式
 *  線程安全
 */
public class Singleton {
    //私有構(gòu)造方法
    private Singleton() {}

    //在成員位置創(chuàng)建該類的對象
    private static Singleton instance;

    //對外提供靜態(tài)方法獲取該對象
    public static synchronized Singleton getInstance() {

        if(instance == null) {
            instance = new Singleton();
        }
        return instance;
    }
}

說明:

? 該方式也實現(xiàn)了懶加載效果,同時又解決了線程安全問題。但是在getInstance()方法上添加了synchronized關(guān)鍵字,導(dǎo)致該方法的執(zhí)行效果特別低。從上面代碼我們可以看出,其實就是在初始化instance的時候才會出現(xiàn)線程安全問題,一旦初始化完成就不存在了。

1.2.6. 懶漢式-方式3(雙重檢查鎖)

再來討論一下懶漢模式中加鎖的問題,對于 getInstance() 方法來說,絕大部分的操作都是讀操作,讀操作是線程安全的,所以我們沒必讓每個線程必須持有鎖才能調(diào)用該方法,我們需要調(diào)整加鎖的時機。由此也產(chǎn)生了一種新的實現(xiàn)模式:雙重檢查鎖模式

/**
 * 雙重檢查方式
 */
public class Singleton { 

    //私有構(gòu)造方法
    private Singleton() {}

    private static Singleton instance;

   //對外提供靜態(tài)方法獲取該對象
    public static Singleton getInstance() {
		//第一次判斷,如果instance不為null,不進入搶鎖階段,直接返回實例
        if(instance == null) {
            synchronized (Singleton.class) {
                //搶到鎖之后再次判斷是否為null
                if(instance == null) {
                    instance = new Singleton();
                }
            }
        }
        return instance;
    }
}

雙重檢查鎖模式是一種非常好的單例實現(xiàn)模式,解決了單例、性能、線程安全問題,上面的雙重檢測鎖模式看上去完美無缺,其實是存在問題,在多線程的情況下,可能會出現(xiàn)空指針問題,出現(xiàn)問題的原因是JVM在實例化對象的時候會進行優(yōu)化和指令重排序操作。

要解決雙重檢查鎖模式帶來空指針異常的問題,只需要使用 volatile 關(guān)鍵字, volatile 關(guān)鍵字可以保證可見性和有序性。

/**
 * 雙重檢查方式
 */
public class Singleton {

    //私有構(gòu)造方法
    private Singleton() {}

    private static volatile Singleton instance;

   //對外提供靜態(tài)方法獲取該對象
    public static Singleton getInstance() {
		//第一次判斷,如果instance不為null,不進入搶鎖階段,直接返回實際
        if(instance == null) {
            synchronized (Singleton.class) {
                //搶到鎖之后再次判斷是否為空
                if(instance == null) {
                    instance = new Singleton();
                }
            }
        }
        return instance;
    }
}

小結(jié):

添加 volatile 關(guān)鍵字之后的雙重檢查鎖模式是一種比較好的單例實現(xiàn)模式,能夠保證在多線程的情況下線程安全也不會有性能問題。

1.2.7 懶漢式-方式4(靜態(tài)內(nèi)部類方式)

靜態(tài)內(nèi)部類單例模式中實例由內(nèi)部類創(chuàng)建,由于 JVM 在加載外部類的過程中, 是不會加載靜態(tài)內(nèi)部類的, 只有內(nèi)部類的屬性/方法被調(diào)用時才會被加載, 并初始化其靜態(tài)屬性。靜態(tài)屬性由于被 static 修飾,保證只被實例化一次,并且嚴(yán)格保證實例化順序。

/**
 * 靜態(tài)內(nèi)部類方式
 */
public class Singleton {

    //私有構(gòu)造方法
    private Singleton() {}

    private static class SingletonHolder {
        private static final Singleton INSTANCE = new Singleton();
    }

    //對外提供靜態(tài)方法獲取該對象
    public static Singleton getInstance() {
        return SingletonHolder.INSTANCE;
    }
}

說明:

? 第一次加載Singleton類時不會去初始化INSTANCE,只有第一次調(diào)用getInstance,虛擬機加載SingletonHolder

并初始化INSTANCE,這樣不僅能確保線程安全,也能保證 Singleton 類的唯一性。

小結(jié):

? 靜態(tài)內(nèi)部類單例模式是一種優(yōu)秀的單例模式,是開源項目中比較常用的一種單例模式。在沒有加任何鎖的情況下,保證了多線程下的安全,并且沒有任何性能影響和空間的浪費。

1.3 單例存在的問題

1.3.1 序列化破壞單例(枚舉方式除外)

序列化反序列化

Singleton類:

public class Singleton implements Serializable {

    //私有構(gòu)造方法
    private Singleton() {}

    private static class SingletonHolder {
        private static final Singleton INSTANCE = new Singleton();
    }

    //對外提供靜態(tài)方法獲取該對象
    public static Singleton getInstance() {
        return SingletonHolder.INSTANCE;
    }
}

Test類:

public class Test {
    public static void main(String[] args) throws Exception {
        //往文件中寫對象
        //writeObject2File();
        //從文件中讀取對象
        Singleton s1 = readObjectFromFile();
        Singleton s2 = readObjectFromFile();

        //判斷兩個反序列化后的對象是否是同一個對象
        System.out.println(s1 == s2);
    }

    private static Singleton readObjectFromFile() throws Exception {
        //創(chuàng)建對象輸入流對象
        ObjectInputStream ois = new ObjectInputStream(new FileInputStream("C:\\Users\\Think\\Desktop\\a.txt"));
        //第一個讀取Singleton對象
        Singleton instance = (Singleton) ois.readObject();

        return instance;
    }

    public static void writeObject2File() throws Exception {
        //獲取Singleton類的對象
        Singleton instance = Singleton.getInstance();
        //創(chuàng)建對象輸出流
        ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("C:\\Users\\Think\\Desktop\\a.txt"));
        //將instance對象寫出到文件中
        oos.writeObject(instance);
    }
}

上面代碼運行結(jié)果是false,表明序列化和反序列化已經(jīng)破壞了單例設(shè)計模式。

1.3.2 反射破壞單例

Singleton類:

public class Singleton {

    //私有構(gòu)造方法
    private Singleton() {}
    
    private static volatile Singleton instance;

    //對外提供靜態(tài)方法獲取該對象
    public static Singleton getInstance() {

        if(instance != null) {
            return instance;
        }

        synchronized (Singleton.class) {
            if(instance != null) {
                return instance;
            }
            instance = new Singleton();
            return instance;
        }
    }
}

Test類:

public class Test {
    public static void main(String[] args) throws Exception {
        //獲取Singleton類的字節(jié)碼對象
        Class clazz = Singleton.class;
        //獲取Singleton類的私有無參構(gòu)造方法對象
        Constructor constructor = clazz.getDeclaredConstructor();
        //取消訪問檢查
        constructor.setAccessible(true);

        //創(chuàng)建Singleton類的對象s1
        Singleton s1 = (Singleton) constructor.newInstance();
        //創(chuàng)建Singleton類的對象s2
        Singleton s2 = (Singleton) constructor.newInstance();

        //判斷通過反射創(chuàng)建的兩個Singleton對象是否是同一個對象
        System.out.println(s1 == s2);
    }
}

上面代碼運行結(jié)果是false,表明序列化和反序列化已經(jīng)破壞了單例設(shè)計模式

1.3.3 序列化、反序列方式破壞單例模式的解決方法

在Singleton類中添加readResolve()方法,在反序列化時被反射調(diào)用,如果定義了這個方法,就返回這個方法的值,如果沒有定義,則返回新new出來的對象。

Singleton類:

public class Singleton implements Serializable {

   //私有構(gòu)造方法
   private Singleton() {}

   private static class SingletonHolder {
       private static final Singleton INSTANCE = new Singleton();
   }

   //對外提供靜態(tài)方法獲取該對象
   public static Singleton getInstance() {
       return SingletonHolder.INSTANCE;
   }
   
   /**
    * 下面是為了解決序列化反序列化破解單例模式
    */
   private Object readResolve() {
       return SingletonHolder.INSTANCE;
   }
}

源碼解析:
ObjectInputStream類

public final Object readObject() throws IOException, ClassNotFoundException{
    ...
    // if nested read, passHandle contains handle of enclosing object
    int outerHandle = passHandle;
    try {
        Object obj = readObject0(false);//重點查看readObject0方法
    .....
}
    
private Object readObject0(boolean unshared) throws IOException {
	...
    try {
		switch (tc) {
			...
			case TC_OBJECT:
				return checkResolve(readOrdinaryObject(unshared));//重點查看readOrdinaryObject方法
			...
        }
    } finally {
        depth--;
        bin.setBlockDataMode(oldMode);
    }    
}
    
private Object readOrdinaryObject(boolean unshared) throws IOException {
	...
	//isInstantiable 返回true,執(zhí)行 desc.newInstance(),通過反射創(chuàng)建新的單例類,
    obj = desc.isInstantiable() ? desc.newInstance() : null; 
    ...
    // 在Singleton類中添加 readResolve 方法后 desc.hasReadResolveMethod() 方法執(zhí)行結(jié)果為true
    if (obj != null && handles.lookupException(passHandle) == null && desc.hasReadResolveMethod()) {
    	// 通過反射調(diào)用 Singleton 類中的 readResolve 方法,將返回值賦值給rep變量
    	// 這樣多次調(diào)用ObjectInputStream類中的readObject方法,繼而就會調(diào)用我們定義的readResolve方法,所以返回的是同一個對象。
    	Object rep = desc.invokeReadResolve(obj);
     	...
    }
    return obj;
}
1.3.4 反射方式破解單例的解決方法
public class Singleton {

    //私有構(gòu)造方法
    private Singleton() {
        /*
           反射破解單例模式需要添加的代碼
        */
        if(instance != null) {
            throw new RuntimeException();
        }
    }
    
    private static volatile Singleton instance;

    //對外提供靜態(tài)方法獲取該對象
    public static Singleton getInstance() {

        if(instance != null) {
            return instance;
        }

        synchronized (Singleton.class) {
            if(instance != null) {
                return instance;
            }
            instance = new Singleton();
            return instance;
        }
    }
}

說明:

? 這種方式比較好理解。當(dāng)通過反射方式調(diào)用構(gòu)造方法進行創(chuàng)建創(chuàng)建時,直接拋異常。不運行此中操作。

1.4 jdk源碼中用到單例的例子

Runtime類就是使用的單例設(shè)計模式。

public class Runtime {
    private static Runtime currentRuntime = new Runtime();

    /**
     * Returns the runtime object associated with the current Java application.
     * Most of the methods of class <code>Runtime</code> are instance
     * methods and must be invoked with respect to the current runtime object.
     *
     * @return  the <code>Runtime</code> object associated with the current
     *          Java application.
     */
    public static Runtime getRuntime() {
        return currentRuntime;
    }

    /** Don't let anyone else instantiate this class */
    private Runtime() {}
}

從上面源代碼中可以看出Runtime類使用的是惡漢式(靜態(tài)屬性)方式來實現(xiàn)單例模式的。

使用Runtime類中的方法

public class RuntimeDemo {
    public static void main(String[] args) throws IOException {
        //獲取Runtime類對象
        Runtime runtime = Runtime.getRuntime();

        //返回 Java 虛擬機中的內(nèi)存總量。
        System.out.println(runtime.totalMemory());
        //返回 Java 虛擬機試圖使用的最大內(nèi)存量。
        System.out.println(runtime.maxMemory());

        //創(chuàng)建一個新的進程執(zhí)行指定的字符串命令,返回進程對象
        Process process = runtime.exec("ipconfig");
        //獲取命令執(zhí)行后的結(jié)果,通過輸入流獲取
        InputStream inputStream = process.getInputStream();
        byte[] arr = new byte[1024 * 1024* 100];
        int b = inputStream.read(arr);
        System.out.println(new String(arr,0,b,"gbk"));
    }
}

2.工廠模式

在java中,萬物皆對象,這些對象都需要創(chuàng)建,如果創(chuàng)建的時候直接new該對象,就會對該對象耦合嚴(yán)重,假如我們要更換對象,所有new對象的地方都需要修改一遍,這顯然違背了軟件設(shè)計的開閉原則。如果我們使用工廠來生產(chǎn)對象,我們就只和工廠打交道就可以了,徹底和對象解耦,如果要更換對象,直接在工廠里更換該對象即可,達(dá)到了與對象解耦的目的;所以說,工廠模式最大的優(yōu)點就是:解耦。

需求:設(shè)計一個咖啡店點餐系統(tǒng)。

設(shè)計一個咖啡類(Coffee),并定義其兩個子類(美式咖啡【AmericanCoffee】和拿鐵咖啡【LatteCoffee】);再設(shè)計一個咖啡店類(CoffeeStore),咖啡店具有點咖啡的功能。
設(shè)計模式--------創(chuàng)建型模式,設(shè)計模式,單例模式
Coffee

public abstract class Coffee {

    public abstract String getName();

    //加糖
    public void addsugar() {
        System.out.println("加糖");
    }

    //加奶
    public void addMilk() {
        System.out.println("加奶");
    }
}

AmericanCoffee

public class AmericanCoffee extends Coffee {

    public String getName() {
        return "美式咖啡";
    }
}

LatteCoffee

public class LatteCoffee extends Coffee {

    public String getName() {
        return "拿鐵咖啡";
    }
}

CoffeeStore

public class CoffeeStore {

    public Coffee orderCoffee(String type) {
        //聲明Coffee類型的變量,根據(jù)不同類型創(chuàng)建不同的coffee子類對象
        Coffee coffee = null;
        if("american".equals(type)) {
            coffee = new AmericanCoffee();
        } else if("latte".equals(type)) {
            coffee = new LatteCoffee();
        } else {
            throw new RuntimeException("對不起,您所點的咖啡沒有");
        }
        //加配料
        coffee.addMilk();
        coffee.addsugar();

        return coffee;
    }
}

Client

public class Client {
    public static void main(String[] args) {
        //1,創(chuàng)建咖啡店類
        CoffeeStore store = new CoffeeStore();
        //2,點咖啡
        Coffee coffee = store.orderCoffee("american");

        System.out.println(coffee.getName());
    }
}

2.1 簡單工廠模式(不屬于GOF的23種經(jīng)典設(shè)計模式)

簡單工廠不是一種設(shè)計模式,反而比較像是一種編程習(xí)慣。
結(jié)構(gòu):

簡單工廠包含如下角色:

  • 抽象產(chǎn)品 :定義了產(chǎn)品的規(guī)范,描述了產(chǎn)品的主要特性和功能。
  • 具體產(chǎn)品 :實現(xiàn)或者繼承抽象產(chǎn)品的子類
  • 具體工廠 :提供了創(chuàng)建產(chǎn)品的方法,調(diào)用者通過該方法來獲取產(chǎn)品。
2.1.1 實現(xiàn)

設(shè)計模式--------創(chuàng)建型模式,設(shè)計模式,單例模式

public class SimpleCoffeeFactory {

    public Coffee createCoffee(String type) {
        Coffee coffee = null;
        if("americano".equals(type)) {
            coffee = new AmericanoCoffee();
        } else if("latte".equals(type)) {
            coffee = new LatteCoffee();
        }
        return coffee;
    }
}

工廠(factory)處理創(chuàng)建對象的細(xì)節(jié),一旦有了SimpleCoffeeFactory,CoffeeStore類中的orderCoffee()就變成此對象的客戶,后期如果需要Coffee對象直接從工廠中獲取即可。這樣也就解除了CoffeeStore和Coffee實現(xiàn)類的耦合,同時又產(chǎn)生了新的耦合,CoffeeStore對象和SimpleCoffeeFactory工廠對象的耦合,工廠對象和商品對象的耦合。

后期如果再加新品種的咖啡,我們勢必要需求修改SimpleCoffeeFactory的代碼,違反了開閉原則。工廠類的客戶端可能有很多,比如創(chuàng)建美團外賣等,這樣只需要修改工廠類的代碼,省去其他的修改操作。

2.1.2 優(yōu)缺點

優(yōu)點:

封裝了創(chuàng)建對象的過程,可以通過參數(shù)直接獲取對象。把對象的創(chuàng)建和業(yè)務(wù)邏輯層分開,這樣以后就避免了修改客戶代碼,如果要實現(xiàn)新產(chǎn)品直接修改工廠類,而不需要在原代碼中修改,這樣就降低了客戶代碼修改的可能性,更加容易擴展。

缺點:

增加新產(chǎn)品時還是需要修改工廠類的代碼,違背了“開閉原則”。

2.1.3 擴展

在開發(fā)中也有一部分人將工廠類中的創(chuàng)建對象的功能定義為靜態(tài)的,這個就是靜態(tài)工廠模式,它也不是23種設(shè)計模式中的。代碼如下:

public class SimpleCoffeeFactory {

    public static Coffee createCoffee(String type) {
        Coffee coffee = null;
        if("americano".equals(type)) {
            coffee = new AmericanoCoffee();
        } else if("latte".equals(type)) {
            coffee = new LatteCoffee();
        }
        return coffe;
    }
}

2.2 工廠方法模式

定義一個用于創(chuàng)建對象的接口,讓子類決定實例化哪個產(chǎn)品類對象。工廠方法使一個產(chǎn)品類的實例化延遲到其工廠的子類。
針對上例中的缺點,使用工廠方法模式就可以完美的解決,完全遵循開閉原則。

結(jié)構(gòu)
工廠方法模式的主要角色:

  • 抽象工廠(Abstract Factory):提供了創(chuàng)建產(chǎn)品的接口,調(diào)用者通過它訪問具體工廠的工廠方法來創(chuàng)建產(chǎn)品。
  • 具體工廠(ConcreteFactory):主要是實現(xiàn)抽象工廠中的抽象方法,完成具體產(chǎn)品的創(chuàng)建。
  • 抽象產(chǎn)品(Product):定義了產(chǎn)品的規(guī)范,描述了產(chǎn)品的主要特性和功能。
  • 具體產(chǎn)品(ConcreteProduct):實現(xiàn)了抽象產(chǎn)品角色所定義的接口,由具體工廠來創(chuàng)建,它同具體工廠之間一一對應(yīng)。
2.2.1 實現(xiàn)

設(shè)計模式--------創(chuàng)建型模式,設(shè)計模式,單例模式
抽象工廠:

public interface CoffeeFactory {

    Coffee createCoffee();
}

具體工廠

public class LatteCoffeeFactory implements CoffeeFactory {

    public Coffee createCoffee() {
        return new LatteCoffee();
    }
}

public class AmericanCoffeeFactory implements CoffeeFactory {

    public Coffee createCoffee() {
        return new AmericanCoffee();
    }
}

咖啡店類

public class CoffeeStore {

    private CoffeeFactory factory;

    public CoffeeStore(CoffeeFactory factory) {
        this.factory = factory;
    }

    public Coffee orderCoffee(String type) {
        Coffee coffee = factory.createCoffee();
        coffee.addMilk();
        coffee.addsugar();
        return coffee;
    }
}
2.2.2 優(yōu)缺點

優(yōu)點:

  • 用戶只需要知道具體工廠的名稱就可得到所要的產(chǎn)品,無須知道產(chǎn)品的具體創(chuàng)建過程;
  • 在系統(tǒng)增加新的產(chǎn)品時只需要添加具體產(chǎn)品類和對應(yīng)的具體工廠類,無須對原工廠進行任何修改,滿足開閉原則;

缺點:

  • 每增加一個產(chǎn)品就要增加一個具體產(chǎn)品類和一個對應(yīng)的具體工廠類,這增加了系統(tǒng)的復(fù)雜度。

2.3 抽象工廠模式(仔細(xì)看一下)

是一種為訪問類提供一個創(chuàng)建一組相關(guān)或相互依賴對象的接口,且訪問類無須指定所要產(chǎn)品的具體類就能得到同族的不同等級的產(chǎn)品的模式結(jié)構(gòu)。

抽象工廠模式是工廠方法模式的升級版本,工廠方法模式只生產(chǎn)一個等級的產(chǎn)品,而抽象工廠模式可生產(chǎn)多個等級的產(chǎn)品。

結(jié)構(gòu)
抽象工廠模式的主要角色如下:

  • 抽象工廠(Abstract Factory):提供了創(chuàng)建產(chǎn)品的接口,它包含多個創(chuàng)建產(chǎn)品的方法,可以創(chuàng)建多個不同等級的產(chǎn)品。
  • 具體工廠(Concrete Factory):主要是實現(xiàn)抽象工廠中的多個抽象方法,完成具體產(chǎn)品的創(chuàng)建。
  • 抽象產(chǎn)品(Product):定義了產(chǎn)品的規(guī)范,描述了產(chǎn)品的主要特性和功能,抽象工廠模式有多個抽象產(chǎn)品。
  • 具體產(chǎn)品(ConcreteProduct):實現(xiàn)了抽象產(chǎn)品角色所定義的接口,由具體工廠來創(chuàng)建,它 同具體工廠之間是多對一的關(guān)系。
2.3.1 實現(xiàn)

現(xiàn)咖啡店業(yè)務(wù)發(fā)生改變,不僅要生產(chǎn)咖啡還要生產(chǎn)甜點,如提拉米蘇、抹茶慕斯等,要是按照工廠方法模式,需要定義提拉米蘇類、抹茶慕斯類、提拉米蘇工廠、抹茶慕斯工廠、甜點工廠類,很容易發(fā)生類爆炸情況。其中拿鐵咖啡、美式咖啡是一個產(chǎn)品等級,都是咖啡;提拉米蘇、抹茶慕斯也是一個產(chǎn)品等級;拿鐵咖啡和提拉米蘇是同一產(chǎn)品族(也就是都屬于意大利風(fēng)味),美式咖啡和抹茶慕斯是同一產(chǎn)品族(也就是都屬于美式風(fēng)味)。
設(shè)計模式--------創(chuàng)建型模式,設(shè)計模式,單例模式
抽象工廠:

public interface DessertFactory {

    Coffee createCoffee();

    Dessert createDessert();
}

具體工廠:

//美式甜點工廠
public class AmericanDessertFactory implements DessertFactory {

    public Coffee createCoffee() {
        return new AmericanCoffee();
    }

    public Dessert createDessert() {
        return new MatchaMousse();
    }
}
//意大利風(fēng)味甜點工廠
public class ItalyDessertFactory implements DessertFactory {

    public Coffee createCoffee() {
        return new LatteCoffee();
    }

    public Dessert createDessert() {
        return new Tiramisu();
    }
}

如果要加同一個產(chǎn)品族的話,只需要再加一個對應(yīng)的工廠類即可,不需要修改其他的類。

2.3.2 優(yōu)缺點

優(yōu)點:

當(dāng)一個產(chǎn)品族中的多個對象被設(shè)計成一起工作時,它能保證客戶端始終只使用同一個產(chǎn)品族中的對象。

缺點:

當(dāng)產(chǎn)品族中需要增加一個新的產(chǎn)品時,所有的工廠類都需要進行修改。

2.3.3 使用場景
  • 當(dāng)需要創(chuàng)建的對象是一系列相互關(guān)聯(lián)或相互依賴的產(chǎn)品族時,如電器工廠中的電視機、洗衣機、空調(diào)等。

  • 系統(tǒng)中有多個產(chǎn)品族,但每次只使用其中的某一族產(chǎn)品。如有人只喜歡穿某一個品牌的衣服和鞋。

  • 系統(tǒng)中提供了產(chǎn)品的類庫,且所有產(chǎn)品的接口相同,客戶端不依賴產(chǎn)品實例的創(chuàng)建細(xì)節(jié)和內(nèi)部結(jié)構(gòu)。

如:輸入法換皮膚,一整套一起換。生成不同操作系統(tǒng)的程序。

2.4 模式擴展

簡單工廠+配置文件解除耦合

可以通過工廠模式+配置文件的方式解除工廠對象和產(chǎn)品對象的耦合。在工廠類中加載配置文件中的全類名,并創(chuàng)建對象進行存儲,客戶端如果需要對象,直接進行獲取即可。

第一步:定義配置文件

為了演示方便,我們使用properties文件作為配置文件,名稱為bean.properties

american=com.itheima.pattern.factory.config_factory.AmericanCoffee
latte=com.itheima.pattern.factory.config_factory.LatteCoffee

第二步:改進工廠類

public class CoffeeFactory {

    private static Map<String,Coffee> map = new HashMap();

    static {
        Properties p = new Properties();
        InputStream is = CoffeeFactory.class.getClassLoader().getResourceAsStream("bean.properties");
        try {
            p.load(is);
            //遍歷Properties集合對象
            Set<Object> keys = p.keySet();
            for (Object key : keys) {
                //根據(jù)鍵獲取值(全類名)
                String className = p.getProperty((String) key);
                //獲取字節(jié)碼對象
                Class clazz = Class.forName(className);
                Coffee obj = (Coffee) clazz.newInstance();
                map.put((String)key,obj);
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    public static Coffee createCoffee(String name) {

        return map.get(name);
    }
}

靜態(tài)成員變量用來存儲創(chuàng)建的對象(鍵存儲的是名稱,值存儲的是對應(yīng)的對象),而讀取配置文件以及創(chuàng)建對象寫在靜態(tài)代碼塊中,目的就是只需要執(zhí)行一次。

2.5 JDK源碼解析-Collection.iterator方法

public class Demo {
    public static void main(String[] args) {
        List<String> list = new ArrayList<>();
        list.add("令狐沖");
        list.add("風(fēng)清揚");
        list.add("任我行");

        //獲取迭代器對象
        Iterator<String> it = list.iterator();
        //使用迭代器遍歷
        while(it.hasNext()) {
            String ele = it.next();
            System.out.println(ele);
        }
    }
}

使用迭代器遍歷集合,獲取集合中的元素。而單列集合獲取迭代器的方法就使用到了工廠方法模式.
設(shè)計模式--------創(chuàng)建型模式,設(shè)計模式,單例模式
Collection接口是抽象工廠類,ArrayList是具體的工廠類;Iterator接口是抽象商品類,ArrayList類中的Iter內(nèi)部類是具體的商品類。在具體的工廠類中iterator()方法創(chuàng)建具體的商品類的對象。

另:

? 1,DateForamt類中的getInstance()方法使用的是工廠模式;

? 2,Calendar類中的getInstance()方法使用的是工廠模式;

3. 原型模式(克隆模式)

用一個已經(jīng)創(chuàng)建的實例作為原型,通過復(fù)制該原型對象來創(chuàng)建一個和原型對象相同的新對象。

結(jié)構(gòu)
原型模式包含如下角色:

  • 抽象原型類:規(guī)定了具體原型對象必須實現(xiàn)的的 clone() 方法。
  • 具體原型類:實現(xiàn)抽象原型類的 clone() 方法,它是可被復(fù)制的對象。
  • 訪問類:使用具體原型類中的 clone() 方法來復(fù)制新的對象。

使用場景

  • 對象的創(chuàng)建非常復(fù)雜,可以使用原型模式快捷的創(chuàng)建對象。
  • 性能和安全要求比較高。

3.1 實現(xiàn)

設(shè)計模式--------創(chuàng)建型模式,設(shè)計模式,單例模式
原型模式的克隆分為淺克隆和深克隆。

淺克?。簞?chuàng)建一個新對象,新對象的屬性和原來對象完全相同,對于非基本類型屬性,仍指向原有屬性所指向的對象的內(nèi)存地址。
深克?。簞?chuàng)建一個新對象,屬性中引用的其他對象也會被克隆,不再指向原有對象地址。

Java中的Object類中提供了 clone() 方法來實現(xiàn)淺克隆。 Cloneable 接口是上面的類圖中的抽象原型類,而實現(xiàn)了Cloneable接口的子實現(xiàn)類就是具體的原型類。代碼如下:

Realizetype(具體的原型類):

public class Realizetype implements Cloneable {

    public Realizetype() {
        System.out.println("具體的原型對象創(chuàng)建完成!");
    }

    @Override
    protected Realizetype clone() throws CloneNotSupportedException {
        System.out.println("具體原型復(fù)制成功!");
        return (Realizetype) super.clone();
    }
}

PrototypeTest(測試訪問類):

public class PrototypeTest {
    public static void main(String[] args) throws CloneNotSupportedException {
        Realizetype r1 = new Realizetype();
        Realizetype r2 = r1.clone();

        System.out.println("對象r1和r2是同一個對象?" + (r1 == r2));
    }
}

3.2 案例

用原型模式生成“三好學(xué)生”獎狀

同一學(xué)校的“三好學(xué)生”獎狀除了獲獎人姓名不同,其他都相同,可以使用原型模式復(fù)制多個“三好學(xué)生”獎狀出來,然后在修改獎狀上的名字即可。
設(shè)計模式--------創(chuàng)建型模式,設(shè)計模式,單例模式

//獎狀類
public class Citation implements Cloneable {
    private String name;

    public void setName(String name) {
        this.name = name;
    }

    public String getName() {
        return (this.name);
    }

    public void show() {
        System.out.println(name + "同學(xué):在2020學(xué)年第一學(xué)期中表現(xiàn)優(yōu)秀,被評為三好學(xué)生。特發(fā)此狀!");
    }

    @Override
    public Citation clone() throws CloneNotSupportedException {
        return (Citation) super.clone();
    }
}

//測試訪問類
public class CitationTest {
    public static void main(String[] args) throws CloneNotSupportedException {
        Citation c1 = new Citation();
        c1.setName("張三");

        //復(fù)制獎狀
        Citation c2 = c1.clone();
        //將獎狀的名字修改李四
        c2.setName("李四");

        c1.show();
        c2.show();
    }
}

3.3 擴展(深克?。?/h4>

將上面的“三好學(xué)生”獎狀的案例中Citation類的name屬性修改為Student類型的屬性。

//獎狀類
public class Citation implements Cloneable {
    private Student stu;

    public Student getStu() {
        return stu;
    }

    public void setStu(Student stu) {
        this.stu = stu;
    }

    void show() {
        System.out.println(stu.getName() + "同學(xué):在2020學(xué)年第一學(xué)期中表現(xiàn)優(yōu)秀,被評為三好學(xué)生。特發(fā)此狀!");
    }

    @Override
    public Citation clone() throws CloneNotSupportedException {
        return (Citation) super.clone();
    }
}

//學(xué)生類
public class Student {
    private String name;
    private String address;

    public Student(String name, String address) {
        this.name = name;
        this.address = address;
    }

    public Student() {
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getAddress() {
        return address;
    }

    public void setAddress(String address) {
        this.address = address;
    }
}

//測試類
public class CitationTest {
    public static void main(String[] args) throws CloneNotSupportedException {

        Citation c1 = new Citation();
        Student stu = new Student("張三", "西安");
        c1.setStu(stu);

        //復(fù)制獎狀
        Citation c2 = c1.clone();
        //獲取c2獎狀所屬學(xué)生對象
        Student stu1 = c2.getStu();
        stu1.setName("李四");

        //判斷stu對象和stu1對象是否是同一個對象
        System.out.println("stu和stu1是同一個對象?" + (stu == stu1));

        c1.show();
        c2.show();
    }
}

淺復(fù)制對于對象中的引用類型只是將類型的地址復(fù)制到新對象中,指向的還是同一個對象。必須將指向的對象也重新復(fù)制一份,才是深復(fù)制
說明:

? stu對象和stu1對象是同一個對象,就會產(chǎn)生將stu1對象中name屬性值改為“李四”,兩個Citation(獎狀)對象中顯示的都是李四。這就是淺克隆的效果,對具體原型類(Citation)中的引用類型的屬性進行引用的復(fù)制。這種情況需要使用深克隆,而進行深克隆需要使用對象流。代碼如下:

public class CitationTest1 {
    public static void main(String[] args) throws Exception {
        Citation c1 = new Citation();
        Student stu = new Student("張三", "西安");
        c1.setStu(stu);

        //創(chuàng)建對象輸出流對象
        ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("C:\\Users\\Think\\Desktop\\b.txt"));
        //將c1對象寫出到文件中
        oos.writeObject(c1);
        oos.close();

        //創(chuàng)建對象出入流對象
        ObjectInputStream ois = new ObjectInputStream(new FileInputStream("C:\\Users\\Think\\Desktop\\b.txt"));
        //讀取對象
        Citation c2 = (Citation) ois.readObject();
        //獲取c2獎狀所屬學(xué)生對象
        Student stu1 = c2.getStu();
        stu1.setName("李四");

        //判斷stu對象和stu1對象是否是同一個對象
        System.out.println("stu和stu1是同一個對象?" + (stu == stu1));

        c1.show();
        c2.show();
    }
}

注意:Citation類和Student類必須實現(xiàn)Serializable接口,否則會拋NotSerializableException異常。

4.建造者模式

將一個復(fù)雜對象的構(gòu)建與表示分離,使得同樣的構(gòu)建過程可以創(chuàng)建不同的表示。
設(shè)計模式--------創(chuàng)建型模式,設(shè)計模式,單例模式

  • 分離了部件的構(gòu)造(由Builder來負(fù)責(zé))和裝配(由Director負(fù)責(zé))。 從而可以構(gòu)造出復(fù)雜的對象。這個模式適用于:某個對象的構(gòu)建過程復(fù)雜的情況。
  • 由于實現(xiàn)了構(gòu)建和裝配的解耦。不同的構(gòu)建器,相同的裝配,也可以做出不同的對象;相同的構(gòu)建器,不同的裝配順序也可以做出不同的對象。也就是實現(xiàn)了構(gòu)建算法、裝配算法的解耦,實現(xiàn)了更好的復(fù)用。
  • 建造者模式可以將部件和其組裝過程分開,一步一步創(chuàng)建一個復(fù)雜的對象。用戶只需要指定復(fù)雜對象的類型就可以得到該對象,而無須知道其內(nèi)部的具體構(gòu)造細(xì)節(jié)。

結(jié)構(gòu)

建造者(Builder)模式包含如下角色:

  • 抽象建造者類(Builder):這個接口規(guī)定要實現(xiàn)復(fù)雜對象的那些部分的創(chuàng)建,并不涉及具體的部件對象的創(chuàng)建。

  • 具體建造者類(ConcreteBuilder):實現(xiàn) Builder 接口,完成復(fù)雜產(chǎn)品的各個部件的具體創(chuàng)建方法。在構(gòu)造過程完成后,提供產(chǎn)品的實例。

  • 產(chǎn)品類(Product):要創(chuàng)建的復(fù)雜對象。

  • 指揮者類(Director):調(diào)用具體建造者來創(chuàng)建復(fù)雜對象的各個部分,在指導(dǎo)者中不涉及具體產(chǎn)品的信息,只負(fù)責(zé)保證對象各部分完整創(chuàng)建或按某種順序創(chuàng)建。

4.1 實現(xiàn)

設(shè)計模式--------創(chuàng)建型模式,設(shè)計模式,單例模式
創(chuàng)建共享單車

生產(chǎn)自行車是一個復(fù)雜的過程,它包含了車架,車座等組件的生產(chǎn)。而車架又有碳纖維,鋁合金等材質(zhì)的,車座有橡膠,真皮等材質(zhì)。對于自行車的生產(chǎn)就可以使用建造者模式。

這里Bike是產(chǎn)品,包含車架,車座等組件;Builder是抽象建造者,MobikeBuilder和OfoBuilder是具體的建造者;Director是指揮者。

//自行車類
public class Bike {
    private String frame;
    private String seat;

    public String getFrame() {
        return frame;
    }

    public void setFrame(String frame) {
        this.frame = frame;
    }

    public String getSeat() {
        return seat;
    }

    public void setSeat(String seat) {
        this.seat = seat;
    }
}

// 抽象 builder 類
public abstract class Builder {

    protected Bike mBike = new Bike();

    public abstract void buildFrame();
    public abstract void buildSeat();
    public abstract Bike createBike();
}

//摩拜單車Builder類
public class MobikeBuilder extends Builder {

    @Override
    public void buildFrame() {
        mBike.setFrame("鋁合金車架");
    }

    @Override
    public void buildSeat() {
        mBike.setSeat("真皮車座");
    }

    @Override
    public Bike createBike() {
        return mBike;
    }
}

//ofo單車Builder類
public class OfoBuilder extends Builder {

    @Override
    public void buildFrame() {
        mBike.setFrame("碳纖維車架");
    }

    @Override
    public void buildSeat() {
        mBike.setSeat("橡膠車座");
    }

    @Override
    public Bike createBike() {
        return mBike;
    }
}

//指揮者類
public class Director {
    private Builder mBuilder;

    public Director(Builder builder) {
        mBuilder = builder;
    }

    public Bike construct() {
        mBuilder.buildFrame();
        mBuilder.buildSeat();
        return mBuilder.createBike();
    }
}

//測試類
public class Client {
    public static void main(String[] args) {
        showBike(new OfoBuilder());
        showBike(new MobikeBuilder());
    }
    private static void showBike(Builder builder) {
        Director director = new Director(builder);
        Bike bike = director.construct();
        System.out.println(bike.getFrame());
        System.out.println(bike.getSeat());
    }
}

注意:

上面示例是 Builder模式的常規(guī)用法,指揮者類 Director 在建造者模式中具有很重要的作用,它用于指導(dǎo)具體構(gòu)建者如何構(gòu)建產(chǎn)品,控制調(diào)用先后次序,并向調(diào)用者返回完整的產(chǎn)品類,但是有些情況下需要簡化系統(tǒng)結(jié)構(gòu),可以把指揮者類和抽象建造者進行結(jié)合

// 抽象 builder 類
public abstract class Builder {

    protected Bike mBike = new Bike();

    public abstract void buildFrame();
    public abstract void buildSeat();
    public abstract Bike createBike();
    
    public Bike construct() {
        this.buildFrame();
        this.BuildSeat();
        return this.createBike();
    }
}

說明:

這樣做確實簡化了系統(tǒng)結(jié)構(gòu),但同時也加重了抽象建造者類的職責(zé),也不是太符合單一職責(zé)原則,如果construct() 過于復(fù)雜,建議還是封裝到 Director 中。

4.2 優(yōu)缺點

優(yōu)點:

  • 建造者模式的封裝性很好。使用建造者模式可以有效的封裝變化,在使用建造者模式的場景中,一般產(chǎn)品類和建造者類是比較穩(wěn)定的,因此,將主要的業(yè)務(wù)邏輯封裝在指揮者類中對整體而言可以取得比較好的穩(wěn)定性。
  • 在建造者模式中,客戶端不必知道產(chǎn)品內(nèi)部組成的細(xì)節(jié),將產(chǎn)品本身與產(chǎn)品的創(chuàng)建過程解耦,使得相同的創(chuàng)建過程可以創(chuàng)建不同的產(chǎn)品對象。
  • 可以更加精細(xì)地控制產(chǎn)品的創(chuàng)建過程 。將復(fù)雜產(chǎn)品的創(chuàng)建步驟分解在不同的方法中,使得創(chuàng)建過程更加清晰,也更方便使用程序來控制創(chuàng)建過程。
  • 建造者模式很容易進行擴展。如果有新的需求,通過實現(xiàn)一個新的建造者類就可以完成,基本上不用修改之前已經(jīng)測試通過的代碼,因此也就不會對原有功能引入風(fēng)險。符合開閉原則。

缺點:

造者模式所創(chuàng)建的產(chǎn)品一般具有較多的共同點,其組成部分相似,如果產(chǎn)品之間的差異性很大,則不適合使用建造者模式,因此其使用范圍受到一定的限制。

4.3 使用場景

建造者(Builder)模式創(chuàng)建的是復(fù)雜對象,其產(chǎn)品的各個部分經(jīng)常面臨著劇烈的變化,但將它們組合在一起的算法卻相對穩(wěn)定,所以它通常在以下場合使用。

  • 創(chuàng)建的對象較復(fù)雜,由多個部件構(gòu)成,各部件面臨著復(fù)雜的變化,但構(gòu)件間的建造順序是穩(wěn)定的。
  • 創(chuàng)建復(fù)雜對象的算法獨立于該對象的組成部分以及它們的裝配方式,即產(chǎn)品的構(gòu)建過程和最終的表示是獨立的。

4.4 模式擴展

建造者模式除了上面的用途外,在開發(fā)中還有一個常用的使用方式,就是當(dāng)一個類構(gòu)造器需要傳入很多參數(shù)時,如果創(chuàng)建這個類的實例,代碼可讀性會非常差,而且很容易引入錯誤,此時就可以利用建造者模式進行重構(gòu)。

public class Phone {
    private String cpu;
    private String screen;
    private String memory;
    private String mainboard;

    public Phone(String cpu, String screen, String memory, String mainboard) {
        this.cpu = cpu;
        this.screen = screen;
        this.memory = memory;
        this.mainboard = mainboard;
    }
....get/set/toString
public class Client {
    public static void main(String[] args) {
        //構(gòu)建Phone對象
        Phone phone = new Phone("intel","三星屏幕","金士頓","華碩");
        System.out.println(phone);
    }
}
 

上面在客戶端代碼中構(gòu)建Phone對象,傳遞了四個參數(shù),如果參數(shù)更多呢?代碼的可讀性及使用的成本就是比較高。
重構(gòu)后

public class Phone {

    private String cpu;
    private String screen;
    private String memory;
    private String mainboard;

    private Phone(Builder builder) {
        cpu = builder.cpu;
        screen = builder.screen;
        memory = builder.memory;
        mainboard = builder.mainboard;
    }

    public static final class Builder {
        private String cpu;
        private String screen;
        private String memory;
        private String mainboard;

        public Builder() {}

        public Builder cpu(String val) {
            cpu = val;
            return this;
        }
        public Builder screen(String val) {
            screen = val;
            return this;
        }
        public Builder memory(String val) {
            memory = val;
            return this;
        }
        public Builder mainboard(String val) {
            mainboard = val;
            return this;
        }
        public Phone build() {
            return new Phone(this);}
    }
    @Override
    public String toString() {
        return "Phone{" +
                "cpu='" + cpu + '\'' +
                ", screen='" + screen + '\'' +
                ", memory='" + memory + '\'' +
                ", mainboard='" + mainboard + '\'' +
                '}';
    }
}

public class Client {
    public static void main(String[] args) {
        Phone phone = new Phone.Builder()
                .cpu("intel")
                .mainboard("華碩")
                .memory("金士頓")
                .screen("三星")
                .build();
        System.out.println(phone);
    }
}

4.5對比

工廠方法模式VS建造者模式

工廠方法模式注重的是整體對象的創(chuàng)建方式;而建造者模式注重的是部件構(gòu)建的過程,意在通過一步一步地精確構(gòu)造創(chuàng)建出一個復(fù)雜的對象。

我們舉個簡單例子來說明兩者的差異,如要制造一個超人,如果使用工廠方法模式,直接產(chǎn)生出來的就是一個力大無窮、能夠飛翔、內(nèi)褲外穿的超人;而如果使用建造者模式,則需要組裝手、頭、腳、軀干等部分,然后再把內(nèi)褲外穿,于是一個超人就誕生了。

抽象工廠模式VS建造者模式

抽象工廠模式實現(xiàn)對產(chǎn)品家族的創(chuàng)建,一個產(chǎn)品家族是這樣的一系列產(chǎn)品:具有不同分類維度的產(chǎn)品組合,采用抽象工廠模式則是不需要關(guān)心構(gòu)建過程,只關(guān)心什么產(chǎn)品由什么工廠生產(chǎn)即可。

建造者模式則是要求按照指定的藍(lán)圖建造產(chǎn)品,它的主要目的是通過組裝零配件而產(chǎn)生一個新產(chǎn)品。

如果將抽象工廠模式看成汽車配件生產(chǎn)工廠,生產(chǎn)一個產(chǎn)品族的產(chǎn)品,那么建造者模式就是一個汽車組裝工廠,通過對部件的組裝可以返回一輛完整的汽車。文章來源地址http://www.zghlxwxcb.cn/news/detail-526512.html

到了這里,關(guān)于設(shè)計模式--------創(chuàng)建型模式的文章就介紹完了。如果您還想了解更多內(nèi)容,請在右上角搜索TOY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!

本文來自互聯(lián)網(wǎng)用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務(wù),不擁有所有權(quán),不承擔(dān)相關(guān)法律責(zé)任。如若轉(zhuǎn)載,請注明出處: 如若內(nèi)容造成侵權(quán)/違法違規(guī)/事實不符,請點擊違法舉報進行投訴反饋,一經(jīng)查實,立即刪除!

領(lǐng)支付寶紅包贊助服務(wù)器費用

相關(guān)文章

  • 學(xué)習(xí)筆記-設(shè)計模式-創(chuàng)建型模式-單例模式

    一個類只有一個實例,并提供一個全局訪問此實例的點,哪怕多線程同時訪問。 單例模式主要解決了 一個全局使用的類被頻繁的創(chuàng)建和消費 的問題。 單例模式的案例場景 數(shù)據(jù)庫的連接池不會反復(fù)創(chuàng)建 spring中一個單例模式bean的生成和使用 在我們平常的代碼中需要設(shè)置全局

    2024年02月08日
    瀏覽(18)
  • 【地鐵上的設(shè)計模式】--創(chuàng)建型模式:單例模式(五)--枚舉單例

    什么是枚舉單例 枚舉單例是指使用枚舉類型來實現(xiàn)單例模式,它是單例模式中最簡單、最安全的一種實現(xiàn)方式。在枚舉類型中定義的枚舉值只會被實例化一次,即保證了全局唯一的實例,而且實現(xiàn)簡單、線程安全、防止反射攻擊、支持序列化等。 如何實現(xiàn)枚舉單例 實現(xiàn)枚舉

    2023年04月25日
    瀏覽(20)
  • 設(shè)計模式-創(chuàng)建型模式(單例、工廠、建造、原型)

    設(shè)計模式:軟件設(shè)計中普遍存在(反復(fù)出現(xiàn))的各種問題,所提出的解決方案。 面向?qū)ο笕筇匦裕悍庋b、繼承、多態(tài)。 面向?qū)ο笤O(shè)計的SOLID原則: (1)開放封閉原則:一個軟件實體如類、模塊和函數(shù)應(yīng)該對擴展開放,對修改關(guān)閉。即軟件實體應(yīng)盡量在不修改原有代碼的情

    2024年02月08日
    瀏覽(28)
  • c#設(shè)計模式-創(chuàng)建型模式 之 單例模式

    目錄 前言: 優(yōu)點: 缺點: 餓漢式(靜態(tài)變量方式) 懶漢式(線程不安全) 懶漢式(雙重檢查鎖定) 推薦方式Lazy 總結(jié): 這種模式涉及到一個單一的類,該類負(fù)責(zé)創(chuàng)建自己的對象,同時確保只有單個對象被創(chuàng)建。這個類提供 了一種訪問其唯一的對象的方式,可以直接訪問,

    2024年02月13日
    瀏覽(31)
  • GO設(shè)計模式——4、單例模式(創(chuàng)建型)

    目錄 單例模式(Singleton Pattern)?? 優(yōu)缺點 使用場景 餓漢式和懶漢式單例模式 ????????單例模式(Singleton Pattern)是一個類 只允許創(chuàng)建一個 對象(或者實例),那這個類就是一個單例類,這種設(shè)計模式就叫作單例設(shè)計模式,簡稱單例模式。單例模式的要點有三個:一是

    2024年02月05日
    瀏覽(24)
  • C++設(shè)計模式創(chuàng)建型之單例模式

    一、概述 ? ? ? ? 單例模式也稱單態(tài)模式,是一種創(chuàng)建型模式,用于創(chuàng)建只能產(chǎn)生一個對象實例的類。例如,項目中只存在一個聲音管理系統(tǒng)、一個配置系統(tǒng)、一個文件管理系統(tǒng)、一個日志系統(tǒng)等,甚至如果吧整個Windows操作系統(tǒng)看成一個項目,那么其中只存在一個任務(wù)管理

    2024年02月14日
    瀏覽(29)
  • 深入理解設(shè)計模式-創(chuàng)建型之單例模式

    如果有些數(shù)據(jù)在系統(tǒng)中應(yīng)該且只能保存一份,那就應(yīng)該設(shè)計為單例類。 如:配置類:在系統(tǒng)中,我們只有一個配置文件,當(dāng)配置文件被加載到內(nèi)存之后,應(yīng)該被映射為一個唯一的【配置實例】,此時就可以使用單例,當(dāng)然也可以不用。 全局計數(shù)器:我們使用一個全局的計數(shù)

    2024年02月12日
    瀏覽(24)
  • 【Java 設(shè)計模式】創(chuàng)建型之單例模式

    【Java 設(shè)計模式】創(chuàng)建型之單例模式

    在軟件開發(fā)中,單例模式是一種常見的設(shè)計模式, 它確保一個類只有一個實例,并提供一個全局訪問點 。單例模式在需要控制某些資源,如數(shù)據(jù)庫連接池、線程池等共享資源的情況下非常有用。在本文中,我們將介紹 Java 設(shè)計模式中的單例模式,了解其實現(xiàn)方式、使用場景

    2024年01月18日
    瀏覽(26)
  • Java23種設(shè)計模式-創(chuàng)建型模式之單例模式

    單例模式 (Singleton Pattern):通過單例模式的方法創(chuàng)建的 類在當(dāng)前進程中只有一個實例 (根據(jù)需要,也有可能一個線程中屬于單例,如:僅線程上下文內(nèi)使用同一個實例),該類負(fù)責(zé) 創(chuàng)建自己的對象 ,同時 確保只有單個對象 被創(chuàng)建。 注 : 1、單例類 只能 有 一個實例 。

    2024年04月26日
    瀏覽(27)
  • 《golang設(shè)計模式》第一部分·創(chuàng)建型模式-01-單例模式(Singleton)

    《golang設(shè)計模式》第一部分·創(chuàng)建型模式-01-單例模式(Singleton)

    指目標(biāo)類(Class)只有一個實例對象(Object),并且向使用該對象的客戶端提供訪問單例的全局方法。 保證類只有一個實例 有方法能讓外部訪問到該實例 懶漢式 在第一次調(diào)用單例對象時創(chuàng)建該對象,這樣可以避免不必要的資源浪費 餓漢式 在程序啟動時就創(chuàng)建單例對象,這

    2024年02月14日
    瀏覽(23)

覺得文章有用就打賞一下文章作者

支付寶掃一掃打賞

博客贊助

微信掃一掃打賞

請作者喝杯咖啡吧~博客贊助

支付寶掃一掃領(lǐng)取紅包,優(yōu)惠每天領(lǐng)

二維碼1

領(lǐng)取紅包

二維碼2

領(lǐng)紅包