(Java)設計模式:創建型

来源:https://www.cnblogs.com/xiegongzi/archive/2022/11/25/16911098.html
-Advertisement-
Play Games

前言 這篇內容是從另一篇:UML建模、設計原則 中分離出來的,原本這個創建型設計模式是和其放在一起的 但是:把這篇創建型設計模式放在一起讓我賊彆扭,看起來賊不舒服,越看念頭越不通達,導致老衲躺在床上腦海中冒出來時都睡不著了 因此:最後實在受不了了,還是將其抽離出來 3、設計模式 分類: 註:使用設計 ...


前言

這篇內容是從另一篇:UML建模、設計原則 中分離出來的,原本這個創建型設計模式是和其放在一起的

但是:把這篇創建型設計模式放在一起讓我賊彆扭,看起來賊不舒服,越看念頭越不通達,導致老衲躺在床上腦海中冒出來時都睡不著了

因此:最後實在受不了了,還是將其抽離出來


3、設計模式

分類:

  • image

  • 註:使用設計模式的規範,類名 = 需求名+使用的對應設計模式名,如:StringBuilder,這就是使用了Builder建造者模式

  • 設計模式不是一成不變的,主要是思想,至於形不需要在意,形只是便於理解罷了


3.1、創建型

這個類型的模式是專門針對於創建對象的,也就是它的適用機制
換言之:這些設計模式提供了一種在創建對象的同時隱藏創建邏輯的方式,而不是使用 new 運算符直接實例化對象


3.1.1、單例模式

定義:保證對象全局唯一,即:保證一個類只有一個實例,哪怕是多線程來進行訪問,向外提供一個訪問此實例的方法即可

使用場景

  • 1、資料庫連接池不會反覆創建
  • 2、Spring中一個單例模式Bean的創建
  • 3、開發中設置一些全局的屬性進行保存(當然:用Redis更好)

3.1.1.1、static實現

package com.zixieqing.o1static;

import java.util.HashMap;
import java.util.Map;

/**
 * <p>@description  : 該類功能  使用static的方式</p>
 * <p>@package      : com.zixieqing.o1static</p>
 * <p>@author       : ZiXieqing</p>
 * <p>@version      : V1.0.0</p>
 */

public class StaticSingleton {

    private static Map<String, String> CACHE = new HashMap<>();
}

  • 這種方式在第一次運行時就初始化Map了,不需要延遲載入
  • 缺點:需要被繼承 或 需要維持一些特定狀態時就不適合了

3.1.1.2、懶漢模式

定義:體現在一個“懶”字上,即:需要時才去創建對象

package com.zixieqing.o2lazy;

/**
 * <p>@description  : 該類功能  懶漢式
 *  此種方式不安全:好比多個人搶廁所,會造成不安全,可能有多個人搶到
 * </p>
 * <p>@package      : com.zixieqing.o2lazy</p>
 * <p>@author       : ZiXieqing</p>
 * <p>@version      : V1.0.0</p>
 */

public class LazySingleton {

    /**
     * 1、private static 當前類的屬性
     */
    private static LazySingleton LAZY_SINGLETON_INSTANCE;

    /**
     * 2、private 的構造
     */
    private LazySingleton() {
    }

    /**
     * 3、提供public static 創建當前類的對象的方法
     */
    public static LazySingleton getInstance() {
        if (null != LAZY_SINGLETON_INSTANCE) return LAZY_SINGLETON_INSTANCE;

        LAZY_SINGLETON_INSTANCE = new LazySingleton();
        return LAZY_SINGLETON_INSTANCE;

    }

    /**
     * 4、要想稍微安全就加synchronized同步鎖
     * 但是:此種方式因為把synchronized加在了方法上,導致所有訪問爭鎖而出現 資源的浪費
     */
/*    public static synchronized lazy_unsafe_singleton getInstance() {
        if (null != LAZY_UNSAFE_INSTANCE_SINGLETON) return LAZY_UNSAFE_INSTANCE_SINGLETON;

        LAZY_UNSAFE_INSTANCE_SINGLETON = new Singleton_lazy_unsafe();
        return LAZY_UNSAFE_INSTANCE_SINGLETON;

    }*/
}


3.1.1.3、餓漢模式

定義:體現在“餓”字上,即:一開始就初始化

package com.zixieqing.o3hunger;

/**
 * <p>@description  : 該類功能  餓漢式實現
 * 這種方式和利用static的方式是異曲同工的
 * </p>
 * <p>@package      : com.zixieqing.o3hunger</p>
 * <p>@author       : ZiXieqing</p>
 * <p>@version      : V1.0.0</p>
 */

public class HungerSingleton {

    private static HungerSingleton HUNGER_SINGLETON_INSTANCE = new HungerSingleton();

    private HungerSingleton() {}

    /**
     * 這種方式其實也不安全
     * 因為當多線程在if判斷時如果在同一時刻二者都判斷成立為null,就會創建不同的實例
     */
    public static HungerSingleton getInstance() {
        if (null != HUNGER_SINGLETON_INSTANCE) return HUNGER_SINGLETON_INSTANCE;

        HUNGER_SINGLETON_INSTANCE = new HungerSingleton();
        return HUNGER_SINGLETON_INSTANCE;
    }
}


3.1.1.4、內部類


package com.zixieqing.o4innerclass;

/**
 * <p>@description  : 該類功能  使用內部類實現 - 推薦的一種</p>
 * <p>@package      : com.zixieqing.o4innerclass</p>
 * <p>@author       : ZiXieqing</p>
 * <p>@version      : V1.0.0</p>
 */

public class InnerClassSingleton {

    /**
     * 1、private的構造
     */
    private InnerClassSingleton() {}

    /**
     * 2、private static的內部類
     * 巧妙之處:使用static修飾,則:做到線程安全,也巧妙藉助了第一種實現方式:使用static的形式
     * 同時:內部類可以訪問外部類的靜態屬性和靜態方法
     */
    private static class NewInstance{
        public static InnerClassSingleton INSTANCE = new InnerClassSingleton();
    }

    /**
     * 3、public static對外提供獲取當前類實例的方法
     */
    public static InnerClassSingleton getInstance() {
        return NewInstance.INSTANCE;
    }
}



3.1.1.5、雙重鎖驗證


package com.zixieqing.o5twinlock;

/**
 * <p>@description  : 該類功能  雙重鎖校驗(線程安全)</p>
 * <p>@package      : com.zixieqing.o5twinlock</p>
 * <p>@author       : ZiXieqing</p>
 * <p>@version      : V1.0.0</p>
 */

public class TwinLockSingleton {
    /**
     * 最好加上volatile關鍵字,它的作用是:不進行指令重排(指令重排是JVM中的)
     */
    private static volatile TwinLockSingleton INSTANCE;

    private TwinLockSingleton() {}

    public static TwinLockSingleton getInstance() {

        if (null != INSTANCE) return INSTANCE;

        // 雙重驗證:synchronized 和 if
        synchronized (TwinLockSingleton.class) {
            if (null == INSTANCE) return INSTANCE = new TwinLockSingleton();
        }
        return INSTANCE;
    }
}



3.1.1.6、CAS

package com.zixieqing.o6cas;

import java.util.concurrent.atomic.AtomicReference;

/**
 * <p>@description  : 該類功能  利用CAS演算法實現
 * 好處:CAS的忙等演算法是靠底層硬體,所以:保證了線程安全 和 不會產生線程的切換和阻塞的開銷,從而提高性能
 *      並且:可以支持較大的併發性
 * </p>
 * <p>@package      : com.zixieqing.o6cas</p>
 * <p>@author       : ZiXieqing</p>
 * <p>@version      : V1.0.0</p>
 */

public class CASSingleton {

    private static CASSingleton CAS_SINGLETON_INSTANCE;

    /**
     * AtomicReference<K> 原子引用  保存“一個”K實例
     */
    private static final AtomicReference<CASSingleton> INSTANCE = new AtomicReference<>();

    public static CASSingleton getInstance() {

        /*
            缺點就在這裡:CAS的忙等   從而造成:如果一直沒有獲取就會處於死循壞當中
         */
        while (true) {
            CAS_SINGLETON_INSTANCE = INSTANCE.get();
            if (null != CAS_SINGLETON_INSTANCE) return CAS_SINGLETON_INSTANCE;
        /*
            boolean compareAndSet(V expect, V update)
                expect 預期值
                update 要改成的新值
                如果當前值和預期值相等,那麼就以原子的方式將值改為新值

             下列邏輯:期望INSTANCE是null,所以將INSTANCE的值改為new Singleton_CAS()
         */
            INSTANCE.compareAndSet(null, new CASSingleton());
            // 獲取INSTANCE的值 返回值就是AtomicReference<Singleton_CAS>中的泛型類型
            return INSTANCE.get();
        }
    }
}


3.1.1.6、枚舉

package com.zixieqing.o7num;

/**
 * <p>@description  : 該類功能  使用枚舉來實現(極度推薦)
 * </p>
 * <p>@package      : com.zixieqing.o7num</p>
 * <p>@author       : ZiXieqing</p>
 * <p>@version      : V1.0.0</p>
 */

public enum EnumSingleton {

    /**
     * 對象
     */
    INSTANCE;

    /**
    * 根據需要自行配置getter也行
    */
}


3.1.2、原型模式

定義:根據一個已有對象(原型實例) 創建 新的對象(就是克隆)

解決的問題:創建重覆對象,而這部分對象本身比較複雜,生成過程從庫或者RPC介面中獲取數據的耗時時長可能會很長,因此:採用克隆的方式會節省時間,總之:當系統中需要創建相同或相似的對象時,就可以用原型模式


場景(在開發中貌似都沒用到過):

  • 1、CV大師(ctrl+cctrl+v
  • 2、JavaSE中的Object.clone()

瞭解兩個名詞:淺拷貝和深拷貝

  • 淺拷貝
    • 1、當類的成員變數是基本數據類型時,淺拷貝會將原對象的屬性值賦值給新對象
    • 2、當類中成員變數是引用數據類型時,淺拷貝 會將 原對象的引用數據類型的地址 賦值給新對象的成員變數。也就是說 兩個對象共用了同一個數據。當其中一個對象修改成員變數的值時,另外一個的值也會隨之改變
  • 深拷貝
    • 無論是 基本數據類型還是引用數據類型,都會去開闢額外的空間給新對象

3.1.2.1、用Object.clone() API(不推薦)

3.1.2.1.1、克隆基本數據類型
  • 淺拷貝會將原對象的屬性值賦值給新對象(拷貝的是值)

  • 註:String底層被final修飾了的,修改值之後是重新創建了一個Sting對象,修改之後不會影響原對象

package com.zixieqing;

/**
 * <p>@description  : 該類功能  原型類(屬性都是基本數據類型時)
 * Cloneable 標誌Object.clone()方法可以對Person該類的實例進行欄位的複製
 * </p>
 * <p>@package      : com.zixieqing</p>
 * <p>@author       : ZiXieqing</p>
 * <p>@version      : V1.0.0</p>
 */

public class Person implements Cloneable{

    private String name;

    public Person() {
    }

    public Person(String name) {
        this.name = name;
    }

    @Override
    public String toString() {
        return "Person{" +
                "name='" + name + '\'' +
                '}';
    }

    @Override
    protected Object clone() throws CloneNotSupportedException {
        Person person = null;
        try {
            person = (Person) super.clone();
        } catch (CloneNotSupportedException e) {
            e.printStackTrace();
        }
        return person;
    }

    public String getName() {
        return name;
    }

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

package com.zixieqing;


/**
 * <p>@description  : 該類功能  測試
 * </p>
 * <p>@package      : com.zixieqing</p>
 * <p>@author       : ZiXieqing</p>
 * <p>@version      : V1.0.0</p>
 */

public class Test {

    public static void main(String[] args) throws CloneNotSupportedException {

        Person person = new Person();
        person.setName("紫邪情");

        Person clonePerson = (Person) person.clone();
        System.out.println( "原型對象:" + person);
        System.out.println( "克隆對象:" + clonePerson);

        clonePerson.setName("小紫");

        System.out.println("==========修改之後=============");
        System.out.println(person);
        System.out.println(clonePerson);

    }
}

image


3.1.2.1.2、克隆引用數據類型
  • 淺拷貝 會將 原對象的引用數據類型的地址 賦值給新對象的成員變數(拷貝的是地址)。也就是說 兩個對象共用了同一個數據。當其中一個對象修改成員變數的值時,另外一個的值也會隨之改變
package com.zixieqing;

/**
 * <p>@description  : 該類功能  原型類(屬性是引用數據類型時)
 * </p>
 * <p>@package      : com.zixieqing</p>
 * <p>@author       : ZiXieqing</p>
 * <p>@version      : V1.0.0</p>
 */

public class Peron2 implements Cloneable{
    private Person person;

    public Peron2() {
    }

    public Peron2(Person person) {
        this.person = person;
    }

    @Override
    protected Object clone() throws CloneNotSupportedException {
        Peron2 peron2 = null;

        try {
            peron2 = (Peron2) super.clone();
        } catch (CloneNotSupportedException e) {
            e.printStackTrace();
        }

        return peron2;
    }

    @Override
    public String toString() {
        return "Peron2{" +
                "person=" + person +
                '}';
    }

    public Person getPerson() {
        return person;
    }

    public void setPerson(Person person) {
        this.person = person;
    }
}

package com.zixieqing;


/**
 * <p>@description  : 該類功能  測試
 * </p>
 * <p>@package      : com.zixieqing</p>
 * <p>@author       : ZiXieqing</p>
 * <p>@version      : V1.0.0</p>
 */

public class Test {

    public static void main(String[] args) throws CloneNotSupportedException {

        Peron2 peron2 = new Peron2();
        Person person = new Person("法外狂徒");
        peron2.setPerson(person);

        Peron2 clonePerson2 = (Peron2) peron2.clone();

        System.out.println(peron2);
        System.out.println(clonePerson2);

        person.setName("張三");
        clonePerson2.setPerson(person);

        System.out.println("修改之後");
        System.out.println(peron2);
        System.out.println(clonePerson2);
    }
}

image


3.1.2.2、使用序列化(推薦)

package com.zixieqing.o2useserialize;

import com.zixieqing.o1useclone.Person;

import java.io.*;

/**
 * <p>@description  : 該類功能  測試
 * </p>
 * <p>@package      : com.zixieqing.o2useserialize</p>
 * <p>@author       : ZiXieqing</p>
 * <p>@version      : V1.0.0</p>
 */

public class Test {

    public static void main(String[] args) throws IOException {

        Person3 person3 = new Person3(0, new Person("紫邪情"));
        Person3 cloneInstance = cloneInstance(person3);

        System.out.println(person3);
        System.out.println(cloneInstance);

        cloneInstance.setSex(1);

        System.out.println("===========修改之後=============");

        System.out.println(person3);
        System.out.println(cloneInstance);
    }


    /**
     * <p>@description  : 該方法功能 對象序列化克隆
     * </p>
     * <p>@methodName   : cloneInstance</p>
     * <p>@author: ZiXieqing</p>
     * <p>@version: V1.0.0</p>
     * @param person3 要進行序列化克隆的對象
     * @return com.zixieqing.o2useserialize.Person3
     */
    private static Person3 cloneInstance(Person3 person3) throws IOException {
        ByteArrayOutputStream bos = null;
        ObjectOutputStream oos = null;
        ByteArrayInputStream bis;
        ObjectInputStream ois;
        Person3 person = null;

        try {
            // 序列化
            bos = new ByteArrayOutputStream();
            oos = new ObjectOutputStream(bos);
            oos.writeObject(person3);

            bis = new ByteArrayInputStream(bos.toByteArray());
            ois = new ObjectInputStream(bis);
            person = (Person3) ois.readObject();
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            if (null != bos) bos.close();

            if (null != oos) oos.close();
        }

        return person;
    }
}

image-20221020163706137


* 3.1.3、工廠模式

3.1.3.1、簡單工廠(工廠基礎)

定義:把對類的創建初始化全都交給一個工廠來執行,而用戶不需要關心創建的過程是什麼樣的,只需要告訴工廠,我想要什麼就行了

設計模式中並沒有所謂的簡單工廠,這玩意兒嚴格來說是一種編碼規範,但是:也是學工廠模式的基礎

簡單工廠的角色

  • 抽象產品:定義產品的規則,即產品有哪些特性和功能,可以是介面、抽象類、普通類也行(但一般不會這麼乾)
  • 具體產品:實現或繼承抽象產品的子類
  • 產品工廠:提供創建產品的方法,讓使用者通過該方法獲取產品

3.1.3.1.1、簡單邏輯

開發場景:網上買商品,假設有三種購買方式(前面的數字對應其類型):1、通過優惠卡;2、通過快播兌換卡;3、啥也沒用,直接購買實物商品,根據前面說的三角色來整活


準備工作:依賴導入

        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>fastjson</artifactId>
            <version>1.2.62</version>
        </dependency>
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.12</version>
            <scope>test</scope>
        </dependency>
        <!-- LOGGING begin -->
        <dependency>
            <groupId>org.slf4j</groupId>
            <artifactId>slf4j-api</artifactId>
            <version>1.7.5</version>
        </dependency>
        <dependency>
            <groupId>org.slf4j</groupId>
            <artifactId>jcl-over-slf4j</artifactId>
            <version>1.7.5</version>
        </dependency>
        <dependency>
            <groupId>ch.qos.logback</groupId>
            <artifactId>logback-classic</artifactId>
            <version>1.0.9</version>
            <exclusions>
                <exclusion>
                    <artifactId>slf4j-api</artifactId>
                    <groupId>org.slf4j</groupId>
                </exclusion>
            </exclusions>
        </dependency>


1、抽象產品:定義規則

package com.zixieqing.o1simplefactory.o1simplelogic;

/**
 * <p>@description  : 該類功能  抽象產品:購物
 * </p>
 * <p>@package      : com.zixieqing.o1simplefactory.o1simplelogic</p>
 * <p>@author       : ZiXieqing</p>
 * <p>@version      : V1.0.0</p>
 */

public interface IShopping {

    /**
     * <p>@description  : 該方法功能 發送商品
     * </p>
     * <p>@methodName   : sendCommodity</p>
     * <p>@author: ZiXieqing</p>
     * <p>@version: V1.0.0</p>
     * @param userId 用戶id
     * @param goodsName  商品名
     */
    void sendCommodity(String userId, String goodsName) throws Exception;
}


2、具體產品:實現或繼承抽象產品的子類

  • 優惠卡方式

    • 
        package com.zixieqing.o1simplefactory.o1simplelogic.impl;
      
        import com.zixieqing.o1simplefactory.o1simplelogic.IShopping;
        import org.slf4j.Logger;
        import org.slf4j.LoggerFactory;
      
        /**
         * <p>@description  : 該類功能  具體商品:優惠卡
         * </p>
         * <p>@package      : com.zixieqing.o1simplefactory.o1simplelogic.impl</p>
         * <p>@author       : ZiXieqing</p>
         * <p>@version      : V1.0.0</p>
         */
      
        public class CouponService implements IShopping {
      
            private Logger logger = LoggerFactory.getLogger(CouponService.class);
      
            @Override
            public void sendCommodity(String userId, String goodsName) throws Exception {
                logger.info("用戶:{},通過優惠卡xxxxxx,購買了:{}", userId, goodsName);
            }
        }
      
      
  • 快播兌換卡方式

    • 
        package com.zixieqing.o1simplefactory.o1simplelogic.impl;
      
        import com.zixieqing.o1simplefactory.o1simplelogic.IShopping;
        import org.slf4j.Logger;
        import org.slf4j.LoggerFactory;
      
        /**
         * <p>@description  : 該類功能  具體商品:快播兌換卡
         * </p>
         * <p>@package      : com.zixieqing.o1simplefactory.o1simplelogic.impl</p>
         * <p>@author       : ZiXieqing</p>
         * <p>@version      : V1.0.0</p>
         */
      
        public class QvodCardService implements IShopping {
      
            private Logger logger = LoggerFactory.getLogger(QvodCardService.class);
      
            @Override
            public void sendCommodity(String userId, String goodsName) throws Exception {
                logger.info("用戶:{},通過快播兌換卡yyyyy,購買了:{}", userId, goodsName);
            }
        }
      
      
  • 實物夠買的方式

    • 
        package com.zixieqing.o1simplefactory.o1simplelogic.impl;
      
        import com.zixieqing.o1simplefactory.o1simplelogic.IShopping;
        import org.slf4j.Logger;
        import org.slf4j.LoggerFactory;
      
        /**
         * <p>@description  : 該類功能  具體商品:啥也不用,直接實物購買
         * </p>
         * <p>@package      : com.zixieqing.o1simplefactory.o1simplelogic.impl</p>
         * <p>@author       : ZiXieqing</p>
         * <p>@version      : V1.0.0</p>
         */
      
        public class GoodsService implements IShopping {
      
            private Logger logger = LoggerFactory.getLogger(GoodsService.class);
      
            @Override
            public void sendCommodity(String userId, String goodsName) throws Exception {
                logger.info("用戶:{},實物購買了:{}", userId, goodsName);
            }
        }
      
      

3、產品工廠:提供創建產品的方法,讓調用者通過該工廠獲取產品

package com.zixieqing.o1simplefactory.o1simplelogic;

import com.zixieqing.o1simplefactory.o1simplelogic.impl.CouponService;
import com.zixieqing.o1simplefactory.o1simplelogic.impl.GoodsService;
import com.zixieqing.o1simplefactory.o1simplelogic.impl.QvodCardService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * <p>@description  : 該類功能  產品工廠:購物工廠
 * </p>
 * <p>@package      : com.zixieqing.o1simplefactory.o1simplelogic</p>
 * <p>@author       : ZiXieqing</p>
 * <p>@version      : V1.0.0</p>
 */

public class ShoppingFactory {

    private Logger logger = LoggerFactory.getLogger(ShoppingFactory.class);

    /**
     * <p>@description  : 該方法功能 購物
     * </p>
     * <p>@methodName   : shopping</p>
     * <p>@author: ZiXieqing</p>
     * <p>@version: V1.0.0</p>
     * @param type  購物方式 1、優惠卡;2、快播兌換卡;3、實物購買
     * @return com.zixieqing.o1simplefactory.o1simplelogic.IShopping
     */
    public IShopping shopping(Integer type) {
        if (null == type) return null;

        logger.info("正在揀貨.....");

        if (1 == type) return new CouponService();

        if (2 == type) return new QvodCardService();

        if (3 == type) return new GoodsService();

        throw new RuntimeException("不存在的商品服務類型");
    }
}

  • 註:如果上面這個工廠的方法加上了static就變成了靜態工廠(靜態方法能被繼承、但不能被重寫)

4、測試:調用者通過工廠獲取對應產品

package com.zixieqing;

import com.zixieqing.o1simplefactory.o1simplelogic.IShopping;
import com.zixieqing.o1simplefactory.o1simplelogic.ShoppingFactory;

/**
 * <p>@description  : 該類功能  測試
 * </p>
 * <p>@package      : com.zixieqing</p>
 * <p>@author       : ZiXieqing</p>
 * <p>@version      : V1.0.0</p>
 */

public class APITest {

    public static void main(String[] args) throws Exception{

        ShoppingFactory shoppingFactory = new ShoppingFactory();

        // 1、優惠卡類型
        IShopping shopping_1 = shoppingFactory.shopping(1);
        shopping_1.sendCommodity(System.nanoTime()+"", "充氣娃娃");

        System.out.println("================華麗的分割線===================");

        // 2、快播兌換卡
        IShopping shopping_2 = shoppingFactory.shopping(2);
        shopping_2.sendCommodity(System.nanoTime()+"", "AI女票");

        System.out.println("================華麗的分割線===================");

        IShopping shopping_3 = shoppingFactory.shopping(3);
        shopping_3.sendCommodity(System.nanoTime()+"", "枸杞");

    }
}

image-20221023230202114


上面就是理解簡單工廠的邏輯,總結一丟丟

  • 簡單工廠的邏輯:
    • image-20221027102226203
  • 由上圖也可知,簡單工廠優點就是調用者可以免除直接創建產品對象的責任,而僅僅"消費"產品,明確責任邊界,降低耦合性,當然其缺點也很明顯
    • 1、違背了開閉原則
      • image-20221023232059889
      • image-20221027102536949
      • 所以從上圖可知:簡單工廠就是橫向發展(不斷加實現類、工廠類中不斷加邏輯判斷)

3.1.3.1.2、更加貼合開發場景的邏輯

1、先決條件:先簡單搞個返回結果集的工具類

package com.zixieqing.o1simplefactory.o2complex.util;

/**
 * <p>@description  : 該類功能  返回結果集工具類
 * </p>
 * <p>@package      : com.zixieqing.o1simplefactory.o2complex.util</p>
 * <p>@author       : ZiXieqing</p>
 * <p>@version      : V1.0.0</p>
 */

public class ResultUtil {

    /**
     * 編碼
     */
    private String code;

    /**
     * 信息
     */
    private String info;

    public ResultUtil(String code, String info) {
        this.code = code;
        this.info = info;
    }

    public String getCode() {
        return code;
    }

    public void setCode(String code) {
        this.code = code;
    }

    public String getInfo() {
        return info;
    }

    public void setInfo(String info) {
        this.info = info;
    }
}


2、優惠卡服務

package com.zixieqing.o1simplefactory.o2complex.coupon;

import com.zixieqing.o1simplefactory.o2complex.util.ResultUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * <p>@description  : 該類功能  模擬發放優惠券業務
 * </p>
 * <p>@package      : com.zixieqing.o1simplefactory.o2complex.coupon</p>
 * <p>@author       : ZiXieqing</p>
 * <p>@version      : V1.0.0</p>
 */

public class CouponService {

    private Logger logger = LoggerFactory.getLogger(CouponService.class);

    /**
     * <p>@description  : 該方法功能 發放優惠券
     * </p>
     * <p>@methodName   : sendCoupon</p>
     * <p>@author: ZiXieqing</p>
     * <p>@version: V1.0.0</p>
     * @param uId 用戶id
     * @param couponNumber 分配的優惠券號碼
     * @param uuid  隨機生成的uuid號
     * @return com.zixieqing.o1simplefactory.o2complex.util.ResultUtil
     */
    public ResultUtil sendCoupon(String uId, String couponNumber, String uuid) {
        logger.info("發放優惠券業務準備啟動..........");

        logger.info("用戶:{},獲得了優惠券:{}", uId, uId + couponNumber + uuid);

        return new ResultUtil("0000", "優惠券發放成功");
    }
}


3、快播兌換卡業務

package com.zixieqing.o1simplefactory.o2complex.qvod;

import com.zixieqing.o1simplefactory.o2complex.util.ResultUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * <p>@description  : 該類功能  快播兌換卡業務
 * </p>
 * <p>@package      : com.zixieqing.o1simplefactory.o2complex.qvod</p>
 * <p>@author       : ZiXieqing</p>
 * <p>@version      : V1.0.0</p>
 */

public class QvodService {

    private Logger logger = LoggerFactory.getLogger(QvodService.class);

    /**
     * <p>@description  : 該方法功能 授予兌換卡
     * </p>
     * <p>@methodName   : grentToken</p>
     * <p>@author: ZiXieqing</p>
     * <p>@version: V1.0.0</p>
     * @param phone 用戶手機號
     * @param cardId  隨機生成的卡號
     * @return com.zixieqing.o1simplefactory.o2complex.util.ResultUtil 
     */
    public ResultUtil grentToken(String phone, String cardId) {
        logger.info("授予的兌換卡為:{}", phone + cardId);
        return new ResultUtil("0000", phone + cardId);
    }
}


4、實物購買商品業務

  • 輔助對象

    • 
        package com.zixieqing.o1simplefactory.o2complex.goods;
      
        /**
         * <p>@description  : 該類功能  實物購買:支付要求對象
         * </p>
         * <p>@package      : com.zixieqing.o1simplefactory.o2complex.goods</p>
         * <p>@author       : ZiXieqing</p>
         * <p>@version      : V1.0.0</p>
         */
      
        public class DeliverRequest {
      
      
            /**
             * 用戶姓名
             */
            private String userName;
            /**
             * 用戶手機
             */
            private String userPhone;
            /**
             * 商品SKU:庫存保有單位
             */
            private String sku;
            /**
             * 訂單ID
             */
            private String orderId;
            /**
             * 收貨人姓名
             */
            private String consigneeUserName;
            /**
             * 收貨人手機
             */
            private String consigneeUserPhone;
            /**
             * 收穫人地址
             */
            private String consigneeUserAddress;
      
            public String getUserName() {
                return userName;
            }
      
            public void setUserName(String userName) {
                this.userName = userName;
            }
      
            public String getUserPhone() {
                return userPhone;
            }
      
            public void setUserPhone(String userPhone) {
                this.userPhone = userPhone;
            }
      
            public String getSku() {
                return sku;
            }
      
            public void setSku(String sku) {
                this.sku = sku;
            }
      
            public String getOrderId() {
                return orderId;
            }
      
            public void setOrderId(String orderId) {
                this.orderId = orderId;
            }
      
            public String getConsigneeUserName() {
                return consigneeUserName;
            }
      
            public void setConsigneeUserName(String consigneeUserName) {
                this.consigneeUserName = consigneeUserName;
            }
      
            public String getConsigneeUserPhone() {
                return consigneeUserPhone;
            }
      
            public void setConsigneeUserPhone(String consigneeUserPhone) {
                this.consigneeUserPhone = consigneeUserPhone;
            }
      
            public String getConsigneeUserAddress() {
                return consigneeUserAddress;
            }
      
            public void setConsigneeUserAddress(String consigneeUserAddress) {
                this.consigneeUserAddress = consigneeUserAddress;
            }
        }
      
      
  • 業務

    •   package com.zixieqing.o1simplefactory.o2complex.goods;
      
        import com.alibaba.fastjson.JSON;
        import com.zixieqing.o1simplefactory.o2complex.util.ResultUtil;
        import org.slf4j.Logger;
        import org.slf4j.LoggerFactory;
      
        /**
         * <p>@description  : 該類功能  實物購買商品業務
         * </p>
         * <p>@package      : com.zixieqing.o1simplefactory.o2complex.goods</p>
         * <p>@author       : ZiXieqing</p>
         * <p>@version      : V1.0.0</p>
         */
      
        public class GoodsService {
      
            private Logger logger = LoggerFactory.getLogger(GoodsService.class);
      
            /**
             * <p>@description  : 該方法功能 發貨
             * </p>
             * <p>@methodName   : deliverGoods</p>
             * <p>@author: ZiXieqing</p>
             * <p>@version: V1.0.0</p>
             * @param deliverRequest  輔助:支付對象
             * @return com.zixieqing.o1simplefactory.o2complex.util.ResultUtil 
             */
            public ResultUtil deliverGoods(DeliverRequest deliverRequest) {
                logger.info("模擬發送實物商品一個:{}", JSON.toJSONString(deliverRequest));
                return new ResultUtil("0000", "發貨成功:" + deliverRequest);
            }
        }
      
      

5、抽象產品:定義規則

package com.zixieqing.o1simplefactory.o2complex;

import java.util.Map;

/**
 * <p>@description  : 該類功能  商品
 * </p>
 * <p>@package      : com.zixieqing.o1simplefactory.o2complex</p>
 * <p>@author       : ZiXieqing</p>
 * <p>@version      : V1.0.0</p>
 */

public interface ICommodityService {

    /**
     * <p>@description  : 該方法功能 發送商品
     * </p>
     * <p>@methodName   : sendCommodity</p>
     * <p>@author: ZiXieqing</p>
     * <p>@version: V1.0.0</p>
     * @param uId 用戶id
     * @param commodityId 商品id
     * @param bizId 業務id
     * @param extMap  擴展信息
     */
    void sendCommodity(String uId, String commodityId, String bizId, Map<String, String> extMap) throws Exception;
}


6、具體商品:實現或繼承抽象產品的子類

  • 優惠卡

    •   package com.zixieqing.o1simplefactory.o2complex.impl;
      
        import com.zixieqing.o1simplefactory.o2complex.ICommodityService;
        import com.zixieqing.o1simplefactory.o2complex.coupon.CouponService;
        import com.zixieqing.o1simplefactory.o2complex.util.ResultUtil;
        import org.slf4j.Logger;
        import org.slf4j.LoggerFactory;
      
        import java.util.Map;
        import java.util.UUID;
      
        /**
         * <p>@description  : 該類功能  TODO
         * </p>
         * <p>@package      : com.zixieqing.o1simplefactory.o2complex.impl</p>
         * <p>@author       : ZiXieqing</p>
         * <p>@version      : V1.0.0</p>
         */
      
        public class CouponCommodityServiceImpl implements ICommodityService {
      
            private Logger logger = LoggerFactory.getLogger(CouponCommodityServiceImpl.class);
      
            /**
             * 模擬@autowried註入
             */
            private CouponService couponService = new CouponService();
      
            @Override
            public void sendCommodity(String uId, String commodityId, String bizId, Map<String, String> extMap) throws Exception {
                ResultUtil result = couponService.sendCoupon(uId, commodityId, UUID.randomUUID().toString());
      
                if (!"0000".equals(result.getCode()))
                    throw new RuntimeException(result.getInfo());
            }
        }
      
      
  • 快播兌換卡

    •   package com.zixieqing.o1simplefactory.o2complex.impl;
      
        import com.zixieqing.o1simplefactory.o2complex.ICommodityService;
        import com.zixieqing.o1simplefactory.o2complex.qvod.QvodService;
        import com.zixieqing.o1simplefactory.o2complex.util.ResultUtil;
        import org.slf4j.Logger;
        import org.slf4j.LoggerFactory;
      
        import java.util.Map;
      
        /**
         * <p>@description  : 該類功能  快播兌換卡發貨
         * </p>
         * <p>@package      : com.zixieqing.o1simplefactory.o2complex.impl</p>
         * <p>@author       : ZiXieqing</p>
         * <p>@version      : V1.0.0</p>
         */
      
        public class QvodCommodityServiceImpl implements ICommodityService {
      
            private Logger logger = LoggerFactory.getLogger(CouponCommodityServiceImpl.class);
      
            /**
             * 模擬註入
             */
            private QvodService qvodService = new QvodService();
      
            @Override
            public void sendCommodity(String uId, String commodityId, String bizId, Map<String, String> extMap) throws Exception {
                // 這裡把電話號碼定死,模擬而已
                ResultUtil result = qvodService.grentToken("12345678910", bizId + commodityId);
      
                logger.info("通過快播兌換卡:{},獲取商品:{}", bizId + commodityId, commodityId);
      
                if (!"0000".equals(result.getCode()))
                    throw new RuntimeException(result.getInfo());
            }
        }
      
      
  • 實物購買

    •   package com.zixieqing.o1simplefactory.o2complex.impl;
      
        import com.zixieqing.o1simplefactory.o2complex.ICommodityService;
        import com.zixieqing.o1simplefactory.o2complex.goods.DeliverRequest;
        import com.zixieqing.o1simplefactory.o2complex.goods.GoodsService;
        import com.zixieqing.o1simplefactory.o2complex.util.ResultUtil;
        import org.slf4j.Logger;
        import org.slf4j.LoggerFactory;
      
        import java.util.Map;
      
        /**
         * <p>@description  : 該類功能  實物購買商品
         * </p>
         * <p>@package      : com.zixieqing.o1simplefactory.o2complex.impl</p>
         * <p>@author       : ZiXieqing</p>
         * <p>@version      : V1.0.0</p>
         */
      
        public class GoodsCommodityServiceImpl implements ICommodityService {
      
            private Logger logger = LoggerFactory.getLogger(GoodsCommodityServiceImpl.class);
      
            /**
             * 模擬註入
             */
            private GoodsService goodsService = new GoodsService();
      
            @Override
            public void sendCommodity(String uId, String commodityId, String bizId, Map<String, String> extMap) throws Exception {
                DeliverRequest deliverRequest = new DeliverRequest();
                // 下麵這些信息去資料庫搞出來
                deliverRequest.setUserName("紫邪情");
                deliverRequest.setUserPhone("123143124342");
                deliverRequest.setSku(commodityId);
                deliverRequest.setOrderId(bizId);
                deliverRequest.setConsigneeUserName(extMap.get("consigneeUserName"));
                deliverRequest.setConsigneeUserPhone(extMap.get("consigneeUserPhone"));
                deliverRequest.setConsigneeUserAddress(extMap.get("consigneeUserAddress"));
      
                ResultUtil result = goodsService.deliverGoods(deliverRequest);
      
                if (!"0000".equals(result.getCode()))
                    throw new RuntimeException(result.getInfo());
            }
        }
      
      

7、產品工廠:提供創建產品的方法,讓調用者通過該方法獲取產品

package com.zixieqing.o1simplefactory.o2complex;

import com.zixieqing.o1simplefactory.o2complex.impl.CouponCommodityServiceImpl;
import com.zixieqing.o1simplefactory.o2complex.impl.GoodsCommodityServiceImpl;
import com.zixieqing.o1simplefactory.o2complex.impl.QvodCommodityServiceImpl;

/**
 * <p>@description  : 該類功能  產品工廠
 * </p>
 * <p>@package      : com.zixieqing.o1simplefactory.o2complex</p>
 * <p>@author       : ZiXieqing</p>
 * <p>@version      : V1.0.0</p>
 */

public class CommodityFactory {

    /**
     * <p>@description  : 該方法功能 獲取產品
     * </p>
     * <p>@methodName   : getCommodity</p>
     * <p>@author: ZiXieqing</p>
     * <p>@version: V1.0.0</p>
     * @param type  產品類型
     * @return com.zixieqing.o1simplefactory.o2complex.ICommodityService 
     */
    public ICommodityService getCommodity(Integer type) {
        if (1 == type) return new CouponCommodityServiceImpl();

        if (2 == type) return new QvodCommodityServiceImpl();

        if (3 == type) return new GoodsCommodityServiceImpl();

        throw new RuntimeException("不合法的商品類型");
    }
}


8、測試

package com.zixieqing;

import com.zixieqing.o1simplefactory.o1simplelogic.IShopping;
import com.zixieqing.o1simplefactory.o1simplelogic.ShoppingFactory;
import com.zixieqing.o1simplefactory.o2complex.CommodityFactory;
import com.zixieqing.o1simplefactory.o2complex.ICommodityService;

import java.util.UUID;

/**
 * <p>@description  : 該類功能  測試
 * </p>
 * <p>@package      : com.zixieqing</p>
 * <p>@author       : ZiXieqing</p>
 * <p>@version      : V1.0.0</p>
 */

public class APITest {

    public static void main(String[] args) throws Exception{

        System.out.println("================華麗的分割線:簡單結合業務開發進行測試===================");

        CommodityFactory commodityFactory = new CommodityFactory();

        // 1、優惠卡類型
        ICommodityService commodity_1 = commodityFactory.getCommodity(1);
        commodity_1.sendCommodity(System.nanoTime() + "",
                System.currentTimeMillis() + "",
                UUID.randomUUID() + "",
                null);

        // 2、快播兌換卡
        ICommodityService commodity_2 = commodityFactory.getCommodity(2);
        commodity_2.sendCommodity(System.nanoTime() + "",
                System.currentTimeMillis() + "",
                UUID.randomUUID() + "",
                null);

        // 3、實物購買
        ICommodityService commodity_3 = commodityFactory.getCommodity(3);
        HashMap<String, String> extMap = new HashMap<>();
        extMap.put("consigneeUserName", "紫邪情");
        extMap.put("consigneeUserPhone", "31343214321432");
        extMap.put("consigneeUserAddress", "浙江省.杭州市.餘杭區.XX街道.YY小區.324134321431");
        commodity_3.sendCommodity(System.nanoTime() + "",
                System.currentTimeMillis() + "",
                UUID.randomUUID() + "",
                extMap);
    }
}

image-20221024142958332


3.1.3.1.3、構建出簡單工廠的方式

廢話文學

  • 1、思考要創建的幾個實例(具體產品)之間有什麼共通性
  • 2、將多個實例的共通性抽取成一個介面(抽象產品)
  • 3、使用一個工廠來對創建的實例進行判斷,從而讓調用者根據條件得到想要的實例對象(還可以結合反射來創建對象)
  • 4、然後根據下圖進行架構即可

image-20221027102226203


3.1.3.2、工廠方法模式

定義:定義一個創建對象的介面,但由子類(具體工廠)決定要實例化的類是哪一個。工廠方法讓類把實例化推遲到子類
解決的問題:明確地計劃不同條件下創建不同實例時就可以考慮是否採用工廠模式,從而提高擴展性,減少以後的改代碼量


廢話文學:

  • 工廠方法模式的角色

    • 抽象工廠角色:工廠方法模式的核心,是具體工廠角色必須實現的介面或者繼承的父類
    • 具體工廠角色:含有和具體業務邏輯有關的代碼,由業務調用創建對應的具體產品的對象
    • 抽象產品角色:是具體產品繼承的父類或者是實現的介面
    • 具體產品角色:具體工廠角色所創建的對象就是此角色的實例
  • 工廠方法模式這玩意兒其實就是在簡單工廠的基礎上稍微變了一下而已,多了一層罷了(沒什麼是加一層解決不了的,一層不行,那就再來一層),這裡加的這一層就是對業務層再抽象了一下而已

  • 簡單工廠是橫向發展(不斷橫向添加實現類),而工廠方法模式本質是為瞭解決簡單工廠模式的問題(違背開閉原則),所以優點和簡單工廠模式一樣,其是縱向發展(不斷縱向添加工廠類+實現類)

  • 簡單工廠模式

    • image-20221027102226203
  • 工廠方法模式:

    • image-20221027105341110
    • 從上圖可以看出:工廠方法模式做的是同一類產品(一條流水線開機時不會還搞多產品加工吧),這個點就是和下麵抽象工廠的最大區別(抽象工廠針對的是產品簇)

3.1.3.2.1、Java中使用工廠方法模式的地方

這個東西其實在剛剛前面的代碼中有一個東西就用到了,即:SLF4J日誌門面,前面用了一個LoggerFactory,它裡面就用到了工廠方法模式

1、進入getLogger()

// 進入getLogger()
private Logger logger = LoggerFactory.getLogger(QvodService.class);


// 得到的代碼
    public static Logger getLogger(Class clazz) {
        // 進入這裡的getLogger()
        return getLogger(clazz.getName());
    }

// 得到代碼
    public static Logger getLogger(String name) {
        // 再看一下getILoggerFactory()
        ILoggerFactory iLoggerFactory = getILoggerFactory();
        return iLoggerFactory.getLogger(name);
    }

// getILoggerFactory()的代碼
    public static ILoggerFactory getILoggerFactory() {
        if (INITIALIZATION_STATE == 0) {
            INITIALIZATION_STATE = 1;
            performInitialization();
        }

        switch(INITIALIZATION_STATE) {
        case 1:
			// 重點1、static SubstituteLoggerFactory TEMP_FACTORY = new SubstituteLoggerFactory();
            return TEMP_FACTORY;
        case 2:
            throw new IllegalStateException("org.slf4j.LoggerFactory could not be successfully initialized. See also http://www.slf4j.org/codes.html#unsuccessfulInit");
        case 3:
            return StaticLoggerBinder.getSingleton().getLoggerFactory();
        case 4:
			// 重點2、static NOPLoggerFactory NOP_FALLBACK_FACTORY = new NOPLoggerFactory();
            return NOP_FALLBACK_FACTORY;
        default:
            throw new IllegalStateException("Unreachable code");
        }
    }

  • 上面的兩個:TEMP_FACTORYNOP_FALLBACK_FACTORY都實現了ILoggerFactory

2、看一眼ILoggerFactory

// 這個就是根工廠:定義最大規則的那個叼毛
public interface ILoggerFactory {
    Logger getLogger(String var1);
}


逆向回來,邏輯就變成如下的樣子

  • image

廢話文學

  • 在開發中怎麼使用工廠方法模式(下列邏輯不止適用於此模式,創建型、行為型、結構型均適合,瞭解每種類型針對的是對什麼做架構即可,如:是對類中方法、還是類本身等等做架構來進行抽離,最後時間長了一看需求就知道咋個設計了)

    • 1、思考自己要創建的幾個實例( 即:具體產品)有什麼共通性

    • 2、將共通性抽取出來變成一個介面或抽象類(即:抽象產品)

    • 3、思考對每一個實例(產品)弄一個工廠類之後(即:具體工廠),那這幾個工廠類之間又有什麼共通性

    • 4、將工廠類的共通性抽取出來變成一個介面(即:抽象工廠)

    • 5、當然:再考慮以後應該會在什麼地方添加功能、是否會擴展的話更好,但這一條需要經驗積累

    • 6、然後使用下圖方式做架構即可

image-20221027105341110


3.1.3.2.2、實例

場景:文件解析,假設有兩種:1、xml文件解析;2、json文件解析

邏輯如下

  • image-20221026120019726

1、抽象產品

package com.zixieqing.o2factorymethod;

/**
 * <p>@description  : 該類功能  文件解析器
 * </p>
 * <p>@package      : com.zixieqing.o2factorymethod</p>
 * <p>@author       : ZiXieqing</p>
 * <p>@version      : V1.0.0</p>
 */

public interface IFileParser {

    String parse();
}


2、具體產品

  • json解析

    • 
        package com.zixieqing.o2factorymethod.impl;
      
        import com.zixieqing.o2factorymethod.IFileParser;
      
        /**
         * <p>@description  : 該類功能  json文件解析器
         * </p>
         * <p>@package      : com.zixieqing.o2factorymethod.impl</p>
         * <p>@author       : ZiXieqing</p>
         * <p>@version      : V1.0.0</p>
         */
      
        public class JsonFileParse implements IFileParser {
            @Override
            public String parse() {
                return "這裡就搞json文件解析的邏輯";
            }
        }
      
      
  • xml解析

    • 
        package com.zixieqing.o2factorymethod.impl;
      
        import com.zixieqing.o2factorymethod.IFileParser;
      
        /**
         * <p>@description  : 該類功能  xml文件解析器
         * </p>
         * <p>@package      : com.zixieqing.o2factorymethod</p>
         * <p>@author       : ZiXieqing</p>
         * <p>@version      : V1.0.0</p>
         */
      
        public class XMLFileParse implements IFileParser {
            @Override
            public String parse() {
                return "這裡就搞xml文件的解析邏輯";
            }
        }
      
      

3、抽象工廠

package com.zixieqing.o2factorymethod.factory;

import com.zixieqing.o2factorymethod.IFileParser;

/**
 * <p>@description  : 該類功能  解析器抽象工廠
 * </p>
 * <p>@package      : com.zixieqing.o2factorymethod</p>
 * <p>@author       : ZiXieqing</p>
 * <p>@version      : V1.0.0</p>
 */

public interface IParserFactory {

    IFileParser parse();
}


4、具體工廠

  • json解析工廠

    • 
        package com.zixieqing.o2factorymethod.factory.impl;
      
        import com.zixieqing.o2factorymethod.IFileParser;
        import com.zixieqing.o2factorymethod.factory.IParserFactory;
        import com.zixieqing.o2factorymethod.impl.JsonFileParse;
      
        /**
         * <p>@description  : 該類功能  json解析工廠
         * </p>
         * <p>@package      : com.zixieqing.o2factorymethod.factory</p>
         * <p>@author       : ZiXieqing</p>
         * <p>@version      : V1.0.0</p>
         */
      
        public class JsonParseFactory implements IParserFactory {
      
            @Override
            public IFileParser parse() {
                return new JsonFileParse();
            }
        }
      
      
  • xml解析工廠

    • 
        package com.zixieqing.o2factorymethod.factory.impl;
      
        import com.zixieqing.o2factorymethod.IFileParser;
        import com.zixieqing.o2factorymethod.factory.IParserFactory;
        import com.zixieqing.o2factorymethod.impl.XMLFileParse;
      
        /**
         * <p>@description  : 該類功能  xml解析工廠
         * </p>
         * <p>@package      : com.zixieqing.o2factorymethod.factory</p>
         * <p>@author       : ZiXieqing</p>
         * <p>@version      : V1.0.0</p>
         */
      
        public class XMLParseFactory implements IParserFactory {
            @Override
            public IFileParser parse() {
                return new XMLFileParse();
            }
        }
      
      

3.1.3.3、抽象工廠模式

定義:在工廠方法模式的基礎上,對工廠進行變化一下

解決的問題:產品簇的問題(一個中心工廠來創建其他工廠)

對於產品簇百度有一個通俗易懂的解釋:指具有相同或相似的功能結構或性能,共用主要的產品特征、組件或子結構,並通過變型配置來滿足特定市場的一組產品的聚類

廢話文學對產品簇的解釋:產品簇是指工廠生產出的產品們之間彼此具備強關聯。比如:AK47工廠生產的 AK47步槍、AK47專配的子彈,一旦 AK47裝錯了子彈是無法正常開槍的(甚至會炸膛)

抽象工廠模式的角色

  • 抽象工廠角色:工廠方法模式的核心,是具體工廠角色必須實現的介面或者繼承的父類
  • 具體工廠角色:含有和具體業務邏輯有關的代碼,由業務調用創建對應的具體產品的對象
  • 抽象產品角色:是具體產品繼承的父類或者是實現的介面
  • 具體產品角色:具體工廠角色所創建的對象就是此角色的實例

抽象工廠模式邏輯舉例(上面的四角色自行對應)

image-20221026164247527


3.1.3.3.1、簡單邏輯實現

就用上面說的傢具來舉例


1、椅子介面(抽象產品)

package com.zixieqing.o3abstractfactory;

/**
 * <p>@description  : 該類功能  抽象產品:椅子介面
 * </p>
 * <p>@package      : com.zixieqing.o3abstractfactory</p>
 * <p>@author       : ZiXieqing</p>
 * <p>@version      : V1.0.0</p>
 */

public interface IChair {

    /**
     * <p>@description  : 該方法功能 生產椅子
     * </p>
     * <p>@methodName   : createChair</p>
     * <p>@author: ZiXieqing</p>
     * <p>@version: V1.0.0</p>
     *
     * @return java.lang.String
     */
    String create();
}

  • 1.1、木質桌子(具體產品)
package com.zixieqing.o3abstractfactory.impl;

import com.zixieqing.o3abstractfactory.IChair;

/**
 * <p>@description  : 該類功能  具體產品:木質椅子
 * </p>
 * <p>@package      : com.zixieqing.o3abstractfactory.impl</p>
 * <p>@author       : ZiXieqing</p>
 * <p>@version      : V1.0.0</p>
 */

public class WoodenChair implements IChair {
    @Override
    public String create() {
        return "木質椅子";
    }
}

  • 1.2、塑料桌子(具體產品)
package com.zixieqing.o3abstractfactory.impl;

import com.zixieqing.o3abstractfactory.IChair;

/**
 * <p>@description  : 該類功能  具體產品:塑料椅子
 * </p>
 * <p>@package      : com.zixieqing.o3abstractfactory.impl</p>
 * <p>@author       : ZiXieqing</p>
 * <p>@version      : V1.0.0</p>
 */

public class PlasticChair implements IChair {
    @Override
    public String create() {
        return "塑料椅子";
    }
}


2、桌子介面(抽象產品)

package com.zixieqing.o3abstractfactory;

/**
 * <p>@description  : 該類功能  抽象產品:桌子介面
 * </p>
 * <p>@package      : com.zixieqing.o3abstractfactory</p>
 * <p>@author       : ZiXieqing</p>
 * <p>@version      : V1.0.0</p>
 */

public interface IDesk {

    /**
     * <p>@description  : 該方法功能 生產桌子
     * </p>
     * <p>@methodName   : create</p>
     * <p>@author: ZiXieqing</p>
     * <p>@version: V1.0.0</p>
     *
     * @return java.lang.String
     */
    String create();

}

  • 木質桌子
package com.zixieqing.o3abstractfactory.impl;

import com.zixieqing.o3abstractfactory.IDesk;

/**
 * <p>@description  : 該類功能  具體產品:木質桌子
 * </p>
 * <p>@package      : com.zixieqing.o3abstractfactory.impl</p>
 * <p>@author       : ZiXieqing</p>
 * <p>@version      : V1.0.0</p>
 */

public class WoodenDesk implements IDesk {
    @Override
    public String create() {
        return "木質桌子";
    }
}

  • 塑料桌子
package com.zixieqing.o3abstractfactory.impl;

import com.zixieqing.o3abstractfactory.IDesk;

/**
 * <p>@description  : 該類功能  具體產品:塑料桌子
 * </p>
 * <p>@package      : com.zixieqing.o3abstractfactory.impl</p>
 * <p>@author       : ZiXieqing</p>
 * <p>@version      : V1.0.0</p>
 */

public class PlastidDeck implements IDesk {
    @Override
    public String create() {
        return "塑料桌子";
    }
}


3、傢具抽象工廠

package com.zixieqing.o3abstractfactory;

/**
 * <p>@description  : 該類功能  抽象工廠:傢具工廠
 * </p>
 * <p>@package      : com.zixieqing.o3abstractfactory</p>
 * <p>@author       : ZiXieqing</p>
 * <p>@version      : V1.0.0</p>
 */

public interface IFurnitureFactory {

    IChair createChair();

    IDesk createDesk();
}

  • 木質傢具工廠
package com.zixieqing.o3abstractfactory.factory;

import com.zixieqing.o3abstractfactory.IChair;
import com.zixieqing.o3abstractfactory.IDesk;
import com.zixieqing.o3abstractfactory.IFurnitureFactory;
import com.zixieqing.o3abstractfactory.impl.WoodenChair;
import com.zixieqing.o3abstractfactory.impl.WoodenDesk;

/**
 * <p>@description  : 該類功能  具體工廠:專門生產木質傢具這一產品簇需要的東西
 * </p>
 * <p>@package      : com.zixieqing.o3abstractfactory.factory</p>
 * <p>@author       : ZiXieqing</p>
 * <p>@version      : V1.0.0</p>
 */

public class WoodenIFurnitureFactory implements IFurnitureFactory {
    @Override
    public IChair createChair() {
        return new WoodenChair();
    }

    @Override
    public IDesk createDesk() {
        return new WoodenDesk();
    }
}

  • 塑料傢具工廠
package com.zixieqing.o3abstractfactory.factory;

import com.zixieqing.o3abstractfactory.IChair;
import com.zixieqing.o3abstractfactory.IDesk;
import com.zixieqing.o3abstractfactory.IFurnitureFactory;
import com.zixieqing.o3abstractfactory.impl.PlasticChair;
import com.zixieqing.o3abstractfactory.impl.PlastidDeck;

/**
 * <p>@description  : 該類功能  具體工廠:專門生產塑料傢具這一產品簇需要的東西
 * </p>
 * <p>@package      : com.zixieqing.o3abstractfactory</p>
 * <p>@author       : ZiXieqing</p>
 * <p>@version      : V1.0.0</p>
 */

public class PlasticFurnitureFactory implements IFurnitureFactory {
    @Override
    public IChair createChair() {
        return new PlasticChair();
    }

    @Override
    public IDesk createDesk() {
        return new PlastidDeck();
    }
}


4、測試

package com.zixieqing;

import com.zixieqing.o3abstractfactory.factory.PlasticFurnitureFactory;
import com.zixieqing.o3abstractfactory.factory.WoodenIFurnitureFactory;

/**
 * <p>@description  : 該類功能  測試
 * </p>
 * <p>@package      : com.zixieqing</p>
 * <p>@author       : ZiXieqing</p>
 * <p>@version      : V1.0.0</p>
 */

public class AbstractFactoryTest {

    public static void main(String[] args) {
        // 木質椅子
        String chair = new WoodenIFurnitureFactory().createChair().create();
  

您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • TIS整合ChunJun實操 B站視頻: https://www.bilibili.com/video/BV1QM411z7w5/?spm_id_from=333.999.0.0 一、ChunJun 概述 ChunJun是一款易用、穩定、高效的批流統一的數據集成框架,可基於實時計算引擎Flink實現 ...
  • 當我們把介面都做好以後,我們需要去開發前端界面。 添加文章功能裡面,最重要的就是文章內容部分,需要配置上富文本編輯器,這樣才能給我們的內容增加樣式。 下載ueditor代碼 ueditor已經很久沒有更新了,我們現在去github下載壓縮好的代碼包 https://github.com/fex-te ...
  • 好家伙,本篇將繼續完善前端界面 效果展示: 1.註冊登陸 (後端已啟動) 2.註冊表單驗證 (前端實現的表單驗證) 在此之前: 我的第一個項目(二):使用Vue做一個登錄註冊界面 - 養肥胖虎 - 博客園 (cnblogs.com) 後端部分: 我的第一個項目(三):註冊登陸功能(後端) - 養肥胖 ...
  • Unhandled Runtime Error TypeError: Cannot read properties of null (reading '1') 錯誤再現 # 1. 安裝 next yarn add next # 2. 配置頁面 pages # 3. 啟動項目 ## 當啟動項目的時候, ...
  • 這裡給大家分享我在網上總結出來的一些知識,希望對大家有所幫助 前言 最近項目遇到一個要在網頁上錄音的需求,在一波搜索後,發現了 react-media-recorder 這個庫。今天就跟大家一起研究一下這個庫的源碼吧,從 0 到 1 來實現一個 React 的錄音、錄像和錄屏的功能。 完整項目代碼放 ...
  • HTML< from >元素 from可向Web伺服器提交請求 普遍格式: <from action="伺服器地址" method="請求方式" enctype="數據格式"> <input type="submit" value="Test按鈕"> </from> method請求方式有: get ...
  • 案例介紹 歡迎來到我的小院,我是霍大俠,恭喜你今天又要進步一點點了!我們來用JavaScript編程實戰案例,做一個輪播圖。圖片每3秒自動輪換,也可以點擊左右按鍵輪播圖片,當圖片到達最左端或最右端時,再點擊左右鍵圖片彈回最初始的圖片或最末尾的圖片。通過實戰我們將學會clearTimeout方法、ob ...
  • hello,大家好呀,我是小樓。 前段時間不是在忙麽,忙的內容之一就是花了點時間重構了一個服務的健康檢查組件,目前已經慢慢在灰度線上,本文就來分享下這次重構之旅,也算作個總結吧。 背景 服務健康檢查簡介 服務健康檢查是應對分散式應用下某些服務節點不健康問題的一種解法。如下圖,消費者調用提供方集群,通 ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...