」工欲善其事,必先利其器。「—孔子《論語.錄靈公》
首頁 > 程式設計 > 簡單工廠

簡單工廠

發佈於2024-11-17
瀏覽:347

什么是简单工厂?

简单工厂不是设计模式。它只是将对象创建与客户端代码解耦。换句话说,简单工厂通过将实例化逻辑移至单独的类来封装对象实例化。

简单工厂经常与工厂模式混淆。我们将研究简单工厂来阐明它们的区别。另外,学习简单工厂可以帮助我们轻松理解工厂模式。

简单工厂可以解决什么问题?

应避免对具体实现进行编程,因为这会使应用程序非常难以维护。对接口进行编程总是更好的选择。如果您在客户端代码中实例化一个具体类,那么简单工厂会派上用场,因为简单工厂可以将对象创建与客户端分离。这使得我们的应用程序更具可扩展性和可维护性。

问题

我们正在为汉堡店开发系统​​。系统需要制作各种汉堡,如牛肉汉堡、鸡肉汉堡等。

我们的第一次尝试是这样的:

// Client orders a burger
Burger orderBurger(String type) {
    Burger burger;

    if (type.equals("beef")) {
        burger = new BeefBurger();
    } else if (type.equals("chicken")) {
        burger = new ChickenBurger();
    } else if (type.equals("fish")) {
        burger = new FishBurger();
    }

    burger.prepareBun();
    burger.grillPatty();
    burger.addToppings();
    burger.wrap();

    return burger;
}

问题是,我们正在针对实现进行编码,而不是针对接口进行编码。在哪里?我们使用 if 语句并根据汉堡类型实例化一个具体类。
为什么会出现这个问题呢?我们的客户端代码与对象创建紧密耦合,导致灵活性降低!假设我们不再销售鱼汉堡,并开始销售素食汉堡。我们需要访问我们的客户端代码并修改它。也就是说不关闭修改。

解决方案

为了解决这个问题,我们可以创建单独的类,它只负责对象的创建。那么我们的客户端代码就不需要担心对象创建并且能够依赖抽象。这种技术被称为“封装变化的内容”。我们预计有关实例化具体对象的代码将经常更改,而未来所有汉堡中的prepareBun()、grillPatty()、addToppings()、wrap()过程可能会保持不变。
简单工厂的优点是可以被其他类重用。我们可能有其他客户端类,例如 BurgerRestaurant、BurgerCateringShop,它们将使用 SimpleBurgerFactory.createBurger() 方法。

Simple Factory

  1. 客户
    客户端通过SimpleBurgerFactory实例化特定的汉堡对象。请注意,从客户端角度来看,我们不知道将创建哪个具体汉堡,即对象创建逻辑现在与客户端解耦。

  2. SimpleBurgerFactory
    这个类封装了不同的内容,在本例中是对象创建逻辑! createBurger() 被声明为静态方法,因为客户端想要使用此类来实例化对象(当然,在实例化它之前我们不能有实例!)。 createBurger() 接受 BurgerType 枚举来确定应创建哪种类型的汉堡。

  3. 汉堡
    这个抽象类提供所有汉堡之间的通用接口并定义默认行为。

  4. 汉堡子类
    这是我们的具体产品。只要扩展 Burger 类,他们就可以通过重写方法来实现特定行为。

结构

Simple Factory

代码

public enum BurgerType {
    BEEF,
    CHICKEN,
    FISH,
    VEGGIE
}
// Abstract Product
public abstract class Burger {

    public BurgerType burgerType;
    public List toppings = new ArrayList();

    public void prepareBun() {
        System.out.println("Preparing a bun");
    }

    public void grillPatty() {
        if (burgerType == null) {
            throw new IllegalStateException("pattyType is undefined");
        }
        System.out.println("Grill a "   burgerType   " patty");
    }

    public void addToppings() {
        for (String item : toppings) {
            System.out.println("Add "   item);
        }
    }

    public void wrap() {
        System.out.println("Wrap a burger up");
    }
}
// Concrete product
public class BeefBurger extends Burger {

    public BeefBurger() {
        burgerType = BurgerType.BEEF;
        List items = List.of("lettuce", "pickle slices", "tomato slice", "BBQ sauce");
        toppings.addAll(items);
    }
}
// Concrete product
public class VeggieBurger extends Burger {

    public VeggieBurger() {
        burgerType = BurgerType.VEGGIE;
        List items = List.of("smoked paprika", "garlic chips", "crushed walnuts", "veggie sauce");
        toppings.addAll(items);
    }

    // Concrete product can implement specific behavior that differs from other products
    @Override
    public void wrap() {
        System.out.println("Wrapping paper shouldn't print any meats but vegetables");
    }
}
// Simple factory, responsible for instantiating an object
public class SimpleBurgerFactory {

    public static Burger createBurger(BurgerType type) {
        return switch (type) {
            case BEEF -> new BeefBurger();
            case CHICKEN -> new ChickenBurger();
            case FISH -> new FishBurger();
            case VEGGIE -> new VeggieBurger();
            default -> throw new IllegalArgumentException("unknown burger type");
        };
    }
}
public class Client {

    public static void main(String[] args) {
        Burger burger = orderBurger(BurgerType.VEGGIE);
        System.out.println(burger); // Check if the object is actually veggie burger
    }

    public static Burger orderBurger(BurgerType type) {
        // Factory is responsible for object creation
        Burger burger = SimpleBurgerFactory.createBurger(type);

        burger.prepareBun();
        burger.grillPatty();
        burger.addToppings();
        burger.wrap();

        return burger;
    }
}

输出:

Preparing a bun
Grill a VEGGIE patty
Add smoked paprika
Add garlic chips
Add crushed walnuts
Add veggie sauce
Wrapping paper shouldn't print any meats but vegetables
com.factories.simpleFactory.VeggieBurger@9807454

陷阱

  • 对象实例化的决策代码有时可能会更复杂。这种情况下,我们不妨考虑使用Factory方法来代替。

与工厂模式的比较

  • 在简单工厂中,通常有一个工厂类来决定创建哪种类型的产品,而工厂模式可能会引入多个工厂。
  • 简单工厂经常使用静态方法创建对象,调用容易,扩展困难。另一方面,工厂方法在超类中使用抽象方法,该方法充当所有工厂和子类的接口,为对象实例化提供具体的实现。

您可以在这里查看所有设计模式的实现。
GitHub 存储库


附言
我是刚开始写科技博客,如果您对我的写作有什么建议,或者有任何困惑的地方,请留言!
感谢您的阅读:)

版本聲明 本文轉載於:https://dev.to/sota_333ad4b72095606ab40c/simple-factory-3bnl?1如有侵犯,請聯絡[email protected]刪除
最新教學 更多>
  • Java 中有效的 @SuppressWarnings 註解警告名稱是什麼?
    Java 中有效的 @SuppressWarnings 註解警告名稱是什麼?
    Java 中的@SuppressWarnings 註解警告名稱@SuppressWarnings 註解應用於程式碼區塊時,會抑制某些類型的編譯器警告。 @SuppressWarnings 註解中可以使用的有效警告名稱會因所使用的 IDE 或編譯器而異。 有效警告名稱列表:以下列表包括Eclipse ...
    程式設計 發佈於2024-11-17
  • 如何在 Java 中繞 x 軸垂直旋轉形狀?
    如何在 Java 中繞 x 軸垂直旋轉形狀?
    圍繞x 軸垂直旋轉形狀提供的代碼演示瞭如何旋轉多邊形,但它不會圍繞x 軸旋轉它x 軸。要實現繞 x 軸的垂直旋轉,我們可以將多邊形旋轉 90 度,然後套用所需的弧度旋轉。修改後的程式碼如下:import java.awt.*; import java.awt.event.*; import java...
    程式設計 發佈於2024-11-17
  • Bootstrap 4 Beta 中的列偏移發生了什麼事?
    Bootstrap 4 Beta 中的列偏移發生了什麼事?
    Bootstrap 4 Beta:列偏移的刪除和恢復Bootstrap 4 在其Beta 1 版本中引入了重大更改柱子偏移了。然而,隨著 Beta 2 的後續發布,這些變化已經逆轉。 從 offset-md-* 到 ml-auto在 Bootstrap 4 Beta 1 中, offset-md-*...
    程式設計 發佈於2024-11-17
  • 如何在 PHP 中組合兩個關聯數組,同時保留唯一 ID 並處理重複名稱?
    如何在 PHP 中組合兩個關聯數組,同時保留唯一 ID 並處理重複名稱?
    在 PHP 中組合關聯數組在 PHP 中,將兩個關聯數組組合成一個數組是常見任務。考慮以下請求:問題描述:提供的代碼定義了兩個關聯數組,$array1和$array2。目標是建立一個新陣列 $array3,它合併兩個陣列中的所有鍵值對。 此外,提供的陣列具有唯一的 ID,而名稱可能重疊。要求是建構一...
    程式設計 發佈於2024-11-17
  • 大批
    大批
    方法是可以在物件上呼叫的 fns 數組是對象,因此它們在 JS 中也有方法。 slice(begin):將陣列的一部分提取到新數組中,而不改變原始數組。 let arr = ['a','b','c','d','e']; // Usecase: Extract till index ...
    程式設計 發佈於2024-11-17
  • 如何在不同網頁上儲存 JavaScript 變數?
    如何在不同網頁上儲存 JavaScript 變數?
    跨頁面持久保存 JavaScript 變數在 JavaScript 中,變數的作用域通常僅限於定義它們的頁面。但是,在某些情況下,您可能需要從一個頁面存取另一個頁面的變數。這就是持久化變數的概念發揮作用的地方。 跨頁面持久化 JavaScript 變數的一種方法是利用 window.name 屬性。...
    程式設計 發佈於2024-11-17
  • 如何在多項目 Gradle 配置中包含跨模組的測試依賴關係?
    如何在多項目 Gradle 配置中包含跨模組的測試依賴關係?
    Gradle 中的多項目測試依賴關係Gradle 中的多項目測試依賴關係在Gradle 中使用多項目配置時,管理跨項目測試的依賴關係可能具有挑戰性。本文探討了一個常見問題,即一個模組的測試依賴項在另一個模組中無法識別,並著重於使用者遇到的具體範例。 使用者俱有包含兩個專案 A 和 B 的多專案設定....
    程式設計 發佈於2024-11-17
  • 為什麼在 C++ 中包含“cstdio”時,“printf”可以在沒有“std::”的情況下工作?
    為什麼在 C++ 中包含“cstdio”時,“printf”可以在沒有“std::”的情況下工作?
    cstdio stdio.h 命名空間cstdio stdio.h 命名空間cstdio 的 C 參考聲明「庫的每個元素都在 std 命名空間內定義」。然而,您發現 std::printf 和 printf 都可以工作,這就提出了 C 標頭是否在兩個命名空間中都包含符號的問題。 答案更細緻。 包含 ...
    程式設計 發佈於2024-11-17
  • 使用 WordPress API 的綜合指南:身份驗證和後期調度
    使用 WordPress API 的綜合指南:身份驗證和後期調度
    在本指南中,我們將探討如何使用 WordPress API 進行驗證並安排特定發佈時間的貼文。這些步驟將幫助您以程式設計方式安全地管理您的 WordPress 內容。 使用 WordPress API 進行身份驗證 要安全地與 WordPress API 交互,您需要對您的要求進行...
    程式設計 發佈於2024-11-17
  • 如何在 Java 中將字串轉換為輸入流?
    如何在 Java 中將字串轉換為輸入流?
    Java中將字串轉換為InputStream給定一個字串,可以方便地將其轉換為InputStream物件以進行進一步處理.要實現此目的,可以利用ByteArrayInputStream 類別。此類包裝了一個位元組數組並將其公開為 InputStream。可以使用與所需字串對應的位元組來初始化位元組數...
    程式設計 發佈於2024-11-17
  • 為什麼 Flex 項目不透過邊距和「邊框」大小縮小以適應每行三個?
    為什麼 Flex 項目不透過邊距和「邊框」大小縮小以適應每行三個?
    Flex 項目忽略邊距和邊框大小在Flexbox 中,透過設定flex: 1 1 33.33% 和margin: 10px on flex物品,人們可能會期望每排三個盒子。然而,使用 flex-wrap:wrap 時,盒子不會縮小到每行三個。 原因在於 box-sizing: border-box ...
    程式設計 發佈於2024-11-17
  • 如何在SQL儲存過程中實現真正的動態排序?
    如何在SQL儲存過程中實現真正的動態排序?
    SQL 儲存過程中的動態排序:深入探究在SQL 儲存過程中動態排序的需求是Web 和應用程式中的常見需求Windows 應用程式。然而,有效實現它的問題仍然存在。 現有方法:Hackish 解一種流行的方法涉及複雜的PHP CASE-WHEN 構造,該構造動態分配排序列和基於參數值的方向。雖然這種方...
    程式設計 發佈於2024-11-17
  • Ubuntu 升級後如何解決 Python 中的「ImportError: No module named 'encodings'」?
    Ubuntu 升級後如何解決 Python 中的「ImportError: No module named 'encodings'」?
    解決Ubuntu升級後Python中的「ImportError: No module name 'encodings'」問題無法取得語言環境編碼時出現的問題,導致錯誤訊息「ImportError:沒有名為'encodings'的模組。」儘管重新安裝Python 並設定...
    程式設計 發佈於2024-11-17
  • 簡單工廠
    簡單工廠
    什么是简单工厂? 简单工厂不是设计模式。它只是将对象创建与客户端代码解耦。换句话说,简单工厂通过将实例化逻辑移至单独的类来封装对象实例化。 简单工厂经常与工厂模式混淆。我们将研究简单工厂来阐明它们的区别。另外,学习简单工厂可以帮助我们轻松理解工厂模式。 简单工厂可以...
    程式設計 發佈於2024-11-17
  • 在 Go 中使用 WebSocket 進行即時通信
    在 Go 中使用 WebSocket 進行即時通信
    构建需要实时更新的应用程序(例如聊天应用程序、实时通知或协作工具)需要一种比传统 HTTP 更快、更具交互性的通信方法。这就是 WebSockets 发挥作用的地方!今天,我们将探讨如何在 Go 中使用 WebSocket,以便您可以向应用程序添加实时功能。 在这篇文章中,我们将介绍: WebSoc...
    程式設計 發佈於2024-11-17

免責聲明: 提供的所有資源部分來自互聯網,如果有侵犯您的版權或其他權益,請說明詳細緣由並提供版權或權益證明然後發到郵箱:[email protected] 我們會在第一時間內為您處理。

Copyright© 2022 湘ICP备2022001581号-3