(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
  • 概述:在C#中,++i和i++都是自增運算符,其中++i先增加值再返回,而i++先返回值再增加。應用場景根據需求選擇,首碼適合先增後用,尾碼適合先用後增。詳細示例提供清晰的代碼演示這兩者的操作時機和實際應用。 在C#中,++i 和 i++ 都是自增運算符,但它們在操作上有細微的差異,主要體現在操作的 ...
  • 上次發佈了:Taurus.MVC 性能壓力測試(ap 壓測 和 linux 下wrk 壓測):.NET Core 版本,今天計劃準備壓測一下 .NET 版本,來測試並記錄一下 Taurus.MVC 框架在 .NET 版本的性能,以便後續持續優化改進。 為了方便對比,本文章的電腦環境和測試思路,儘量和... ...
  • .NET WebAPI作為一種構建RESTful服務的強大工具,為開發者提供了便捷的方式來定義、處理HTTP請求並返迴響應。在設計API介面時,正確地接收和解析客戶端發送的數據至關重要。.NET WebAPI提供了一系列特性,如[FromRoute]、[FromQuery]和[FromBody],用 ...
  • 原因:我之所以想做這個項目,是因為在之前查找關於C#/WPF相關資料時,我發現講解圖像濾鏡的資源非常稀缺。此外,我註意到許多現有的開源庫主要基於CPU進行圖像渲染。這種方式在處理大量圖像時,會導致CPU的渲染負擔過重。因此,我將在下文中介紹如何通過GPU渲染來有效實現圖像的各種濾鏡效果。 生成的效果 ...
  • 引言 上一章我們介紹了在xUnit單元測試中用xUnit.DependencyInject來使用依賴註入,上一章我們的Sample.Repository倉儲層有一個批量註入的介面沒有做單元測試,今天用這個示例來演示一下如何用Bogus創建模擬數據 ,和 EFCore 的種子數據生成 Bogus 的優 ...
  • 一、前言 在自己的項目中,涉及到實時心率曲線的繪製,項目上的曲線繪製,一般很難找到能直接用的第三方庫,而且有些還是定製化的功能,所以還是自己繪製比較方便。很多人一聽到自己畫就害怕,感覺很難,今天就分享一個完整的實時心率數據繪製心率曲線圖的例子;之前的博客也分享給DrawingVisual繪製曲線的方 ...
  • 如果你在自定義的 Main 方法中直接使用 App 類並啟動應用程式,但發現 App.xaml 中定義的資源沒有被正確載入,那麼問題可能在於如何正確配置 App.xaml 與你的 App 類的交互。 確保 App.xaml 文件中的 x:Class 屬性正確指向你的 App 類。這樣,當你創建 Ap ...
  • 一:背景 1. 講故事 上個月有個朋友在微信上找到我,說他們的軟體在客戶那邊隔幾天就要崩潰一次,一直都沒有找到原因,讓我幫忙看下怎麼回事,確實工控類的軟體環境複雜難搞,朋友手上有一個崩潰的dump,剛好丟給我來分析一下。 二:WinDbg分析 1. 程式為什麼會崩潰 windbg 有一個厲害之處在於 ...
  • 前言 .NET生態中有許多依賴註入容器。在大多數情況下,微軟提供的內置容器在易用性和性能方面都非常優秀。外加ASP.NET Core預設使用內置容器,使用很方便。 但是筆者在使用中一直有一個頭疼的問題:服務工廠無法提供請求的服務類型相關的信息。這在一般情況下並沒有影響,但是內置容器支持註冊開放泛型服 ...
  • 一、前言 在項目開發過程中,DataGrid是經常使用到的一個數據展示控制項,而通常表格的最後一列是作為操作列存在,比如會有編輯、刪除等功能按鈕。但WPF的原始DataGrid中,預設只支持固定左側列,這跟大家習慣性操作列放最後不符,今天就來介紹一種簡單的方式實現固定右側列。(這裡的實現方式參考的大佬 ...