”工欲善其事,必先利其器。“—孔子《论语.录灵公》
首页 > 编程 > 简单工厂

简单工厂

发布于2024-11-17
浏览:233

什么是简单工厂?

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

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

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

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

问题

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

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

// 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 Gal...
    编程 发布于2024-11-17
  • 如何在 Java 中绕 x 轴垂直旋转形状?
    如何在 Java 中绕 x 轴垂直旋转形状?
    围绕 x 轴垂直旋转形状提供的代码演示了如何旋转多边形,但它不会围绕 x 轴旋转它x 轴。要实现绕 x 轴的垂直旋转,我们可以将多边形旋转 90 度,然后应用所需的弧度旋转。修改后的代码如下:import java.awt.*; import java.awt.event.*; import jav...
    编程 发布于2024-11-17
  • 如何使用 MySQL 查找今天生日的用户?
    如何使用 MySQL 查找今天生日的用户?
    如何使用 MySQL 识别今天生日的用户使用 MySQL 确定今天是否是用户的生日涉及查找生日匹配的所有行今天的日期。这可以通过一个简单的 MySQL 查询来实现,该查询将存储为 UNIX 时间戳的生日与今天的日期进行比较。以下 SQL 查询将获取今天有生日的所有用户: FROM USERS ...
    编程 发布于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 p...
    编程 发布于2024-11-17
  • 如何跨不同网页存储 JavaScript 变量?
    如何跨不同网页存储 JavaScript 变量?
    跨页面持久保存 JavaScript 变量在 JavaScript 中,变量的作用域通常仅限于定义它们的页面。但是,在某些情况下,您可能需要从一个页面访问另一页面的变量。这就是持久化变量的概念发挥作用的地方。跨页面持久化 JavaScript 变量的一种方法是利用 window.name 属性。此属...
    编程 发布于2024-11-17
  • 如何在多项目 Gradle 配置中包含跨模块的测试依赖关系?
    如何在多项目 Gradle 配置中包含跨模块的测试依赖关系?
    Gradle 中的多项目测试依赖关系在 Gradle 中使用多项目配置时,管理跨项目测试的依赖关系可能具有挑战性。本文探讨了一个常见问题,即一个模块的测试依赖项在另一个模块中无法识别,重点关注用户遇到的具体示例。用户具有包含两个项目 A 和 B 的多项目配置. 项目 A 包含主代码和测试源代码,而项...
    编程 发布于2024-11-17
  • 为什么在 C++ 中包含“cstdio”时,“printf”可以在没有“std::”的情况下工作?
    为什么在 C++ 中包含“cstdio”时,“printf”可以在没有“std::”的情况下工作?
    cstdio stdio.h 命名空间cstdio 的 C 参考声明“库的每个元素都在 std 命名空间内定义”。然而,您发现 std::printf 和 printf 都可以工作,这就提出了 C 标头是否在两个命名空间中都包含符号的问题。答案更加细致。包括 cstdio 包括 cstdio 将符号...
    编程 发布于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
  • 如何修复 macOS 上 Django 中的“配置不正确:加载 MySQLdb 模块时出错”?
    如何修复 macOS 上 Django 中的“配置不正确:加载 MySQLdb 模块时出错”?
    MySQL配置不正确:相对路径的问题在Django中运行python manage.py runserver时,可能会遇到以下错误:ImproperlyConfigured: Error loading MySQLdb module: dlopen(/Library/Python/2.7/site-...
    编程 发布于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

免责声明: 提供的所有资源部分来自互联网,如果有侵犯您的版权或其他权益,请说明详细缘由并提供版权或权益证明然后发到邮箱:[email protected] 我们会第一时间内为您处理。

Copyright© 2022 湘ICP备2022001581号-3