JS设计模式之“名片设计师” - 工厂方法模式

image.png

前言

上篇文章我们了解到什么是简单工厂模式 ,请参考上篇文章:JS设计模式之 "神奇的魔术师" - 简单工厂模式,不过这是工厂中最简单的一种,本篇文章我们将同大家一起认识一种更复杂的工厂模式,它将给我们提供复杂的对象创建场景,以模块化的思想实现我们复杂的需求。就像给我们设计不同的名片一样,我们暂且亲切的称呼它为"名片设计师"。

一. 什么是工厂方法模式

概念

工厂方法模式Factory Method Pattern)是一种创建型设计模式,在软件开发中被广泛应用。它提供了一种将对象的创建过程封装起来的方式,使得代码可扩展性更好、更灵活。

工厂方法模式的主要思想是 定义一个用于创建对象的接口 ,但将具体的对象创建延迟到子类中去实现。这样,客户端程序使用工厂方法来创建对象,而不需要知道具体的实现细节,从而实现了解耦

工厂方法模式类图

使用步骤

JavaScript 中,可以使用工厂方法模式实现对象的创建和管理,具体的实现方式如下:

首先,定义一个基础工厂类,作为对象创建的接口,其中包含一个用于创建对象的方法(通常称为工厂方法)。

复制代码
class Factory {
  createObject() {
    // 子类需要实现该方法来创建具体对象
  }
}

然后,根据具体的需求,创建子类继承基础工厂类,并实现工厂方法来创建具体的对象。

复制代码
class ConcreteFactory extends Factory {
  createObject() {
    return new ConcreteObject();
  }
}

最后,通过客户端代码来使用工厂方法创建对象。

复制代码
const factory = new ConcreteFactory();
const object = factory.createObject();

使用工厂方法模式的好处 是,当需要新增一种对象时,只需要创建一个新的子类并实现工厂方法即可,而不需要修改客户端代码。这样,能够降低代码的耦合度 ,提高代码的可维护性可扩展性

工厂方法模式是一种简单而有效的对象创建方式,适用于需要创建多个具有相同行为的对象的场景,能够提供一种灵活的对象创建和管理机制。

二. 安全模式创建的工厂类

介绍

安全模式创建的工厂类Safe Factory Pattern)是一种在JavaScript中实现工厂方法模式的方式,它可以确保只能通过工厂类的方法来创建对象,而不能直接实例化工厂类。

通过使用安全模式创建工厂类,可以确保工厂类的使用符合预期,同时也增强了代码的安全性和可靠性。以下是一个简单示例:

复制代码
function Factory() {
  if (!(this instanceof Factory)) {
    return new Factory();
  }
  
  this.createObject = function() {
    // 创建对象的逻辑
  };
}

在上述示例中,我们使用了构造函数Factory)来实现工厂类,并通过判断this对象是否是工厂类的实例来确保只能通过构造函数来创建工厂类的实例。这样,在使用时如果忘记使用new关键字来实例化工厂类,则会自动进行实例化,避免了直接实例化工厂类导致的问题。

通过使用安全模式创建的工厂类,可以实现更严格的对象创建和管理机制,同时保证了代码的安全性和一致性。在实际应用中,可以根据需求对工厂类进行扩展和定制,以满足具体的业务需求。

优点

由此可见,安全模式创建的工厂类 具有以下优点

1. 隐藏实例化细节: 安全模式的工厂类只能通过工厂方法来创建对象,而不允许直接实例化或继承该工厂类。这样可以隐藏具体对象的实例化细节,使得客户端无法直接访问和创建对象,只能通过工厂方法来获取实例。

2. 防止子类破坏对象的创建逻辑: 由于安全模式的工厂类不能被继承,子类无法改变工厂方法中的创建逻辑。这确保了对象的创建过程不会被子类随意修改,防止了在创建过程中可能出现的错误或安全隐患。

3. 提供一致的接口: 通过工厂方法来统一创建对象,工厂类可以根据不同的参数或条件返回不同类型的对象,但对外提供的接口是一致的。这样可以简化客户端的使用,客户端不需要知道具体的创建过程,只需要调用工厂方法并传入相应的即可获得所需对象。

案例场景:日志工厂

下面以一个Logger工厂类的示例来说明安全模式创建工厂类的优点:

复制代码
public abstract class Logger {
    public abstract void log(String message);
}

public class FileLogger extends Logger {
    public void log(String message) {
        // 将日志信息写入文件
    }
}

public class DatabaseLogger extends Logger {
    public void log(String message) {
        // 将日志信息写入数据库
    }
}

public class LoggerFactory {
    private LoggerFactory() {}
    
    public static Logger createLogger type) {
        if (type.equals("file")) {
            return new FileLogger();
        } else if (type.equals("database")) {
            return new DatabaseLogger();
        } else {
            throw new IllegalArgumentException("Invalid logger type.");
        }
    }
}

在上述示例中,Logger是一个抽象类,具体的日志记录逻辑由FileLoggerDatabaseLogger来实现。LoggerFactory是一个安全模式创建的工厂类,通过工厂方法createLogger来创建Logger的实例。客户端只需调用LoggerFactorycreateLogger方法,并传入相应的参数(如filedatabase)即可获取对应的Logger实例。客户端无法直接实例化Logger类或LoggerFactory类,以保对象的创建逻辑被固定并且隐藏了具体实例化细节。这样的设计使得客户端使用起来更加简单方便,并且保护了对象创建过程的安全性和稳定性。

三. 简单工厂模式与工厂方法模式之间的对比

披萨工厂

案例场景:披萨店点餐

当你在一个披萨店点餐时,你可以通过简单工厂模式或工厂方法模式来创建不同类型的披萨。这里有两个例子来说明它们之间的区别:

1. 简单工厂模式示例:

考虑一个披萨店,它提供不同类型的披萨,如奶酪披萨(Cheese Pizza)、蔬菜披萨(Vegetable Pizza)和海鲜披萨(Seafood Pizza)等。使用简单工厂模式,我们可以创建一个披萨工厂类来处理披萨的实例化逻辑:

复制代码
public class PizzaFactory {
    public static Pizza createPizza(String type) {
        if (type.equals("cheese")) {
            return new CheesePizza();
        } else if (type.equals("vegetable")) {
            return new VegetablePizza();
        } else if (type.equals("seafood")) {
            return new SeafoodPizza();
        } else {
            throw new IllegalArgumentException("Invalid pizza type.");
        }
    }
}

public abstract class Pizza {
    // 披萨的公共方法和属性
}

public class CheesePizza extends Pizza {
    // 奶酪披萨特有的方法和属性
}

// 其他类型的披萨类类似,如VegetablePizza和SeafoodPizza

使用简单工厂模式,我们只需要通过披萨工厂类(PizzaFactory)来创建不同类型的披萨对象,而不需要直接实例化特定类型的披萨。

2. 工厂方法模式示例:

假设我们的披萨店进一步发展,对于不同类型的披萨,现在要创建不同的披萨店来处理它们的制作。这里为每个披萨类型创建一个具体的披萨店类,用工厂方法模式实现:

复制代码
public abstract class PizzaStore {
    public abstract Pizza createPizza();

    public void orderPizza() {
        Pizza pizza = createPizza();
        // 其他制作披萨的逻辑
    }
}

public class CheesePizzaStore extends PizzaStore {
    public Pizza createPizza() {
        return new CheesePizza();
    }
}

// 其他类型的披萨店类类似,如VegetablePizzaStore和SeafoodPizzaStore

在工厂方法模式中,我们定义了一个抽象的PizzaStore类,并在每个具体的店类(如CheesePizzaStore)中实现了创建具体披萨对象的方法。每个具体的店类负责创建特定的披萨类型,使得披萨的创建逻辑分散到不同的类中。

通过上述两个示例可以看出,简单工厂模式通过一个工厂类集中处理对象的创建逻辑,而工厂方法模式将对象的创建推迟到具体的子类中实现,从而使得不同的产品创建逻辑能够被更加灵活地扩展和修改。

由此可见,整体区别如下:

工厂方法模式Factory Method Pattern)和简单工厂模式Simple Factory Pattern)是两种常见的工厂模式,它们之间有以下区别:

1. 设计理念:

  • 简单工厂模式的主要思想是通过一个工厂类来创建不同类型的对象,将对象的创建逻辑集中在一个地方。工厂类根据传入的参数或条件来决定创建哪种对象。

  • 工厂方法模式的主要思想是将对象的创建延迟到子类中实现。定义一个抽象的工厂类,该类中声明一个工厂方法,由子类来实现该工厂方法来创建具体的对象。

2. 参与角色:

  • 简单工厂模式通常只涉及一个工厂类(Simple Factory)和多个产品类(Product)。

  • 工厂方法模式涉及一个抽象工厂类(Abstract Factory)、多个具体工厂类(Concrete Factory)和对应的产品类(Product)。

3. 可扩展性:

  • 简单工厂模式的可扩展性相对较差,当需要新增一种产品时,需要修改工厂类的代码来增加对新产品的支持。

  • 工厂方法模式的可扩展性较好,通过添加一个新的具体工厂类和对应的产品类,即可实现对新产品的支持,不需要修改抽象工厂类或其他已有类。

4. 对象创建的灵活性:

  • 简单工厂模式在工厂类中集中了对象的创建逻辑,可能会导致工厂类变得较为庞大,一旦需要新增或修改某个产品的创建逻辑,就需要修改工厂类。

  • 工厂方法模式将对象的创建委托给具体的工厂类,每个工厂类只负责创建一个具体的产品,使得代码更加模块化和灵活,容易扩展和维护。

总结

简单工厂模式适用于简单的对象创建场景 ,可以通过一个工厂类来集中对象的创建逻辑;而工厂方法模式适用于复杂的对象创建场景,需要根据具体的产品类型来创建相应的对象,通过子类来实现对象的创建逻辑。选择使用哪种模式取决于具体的需求和设计的复杂性。

相关推荐
Pedantic2 小时前
SwiftUI 手势层级(Gesture Hierarchy)详解
前端
飘尘3 小时前
前端转型全栈(Java后端)的快速上手指引
前端·后端·全栈
一颗烂土豆3 小时前
Meshopt 压缩深度解析,为什么它比 Draco 更快
前端·javascript·webgl
浏览器工程师4 小时前
AI Agent 接浏览器任务,先别让它一路点到底
前端·后端
雨季mo浅忆4 小时前
VSCode自动格式化三要素
前端
爱勇宝5 小时前
深扒 Anthropic 1680 位工程师简历:应届生几乎没机会,AI 公司最缺的不是博士
前端·后端·程序员
kyriewen5 小时前
同事每天催我 Code Review,我写了个脚本让 AI 替我 review PR——现在他反过来催 AI 了
前端·javascript·ai编程
user20585561518137 小时前
Windows 项目安装时报 `node-sass` 错误,如何快速处理
前端
LiaCode7 小时前
Redis 在生产项目的使用
前端·后端