工厂模式 详解 设计模式

工厂模式

其主要目的是封装对象的创建过程 ,使客户端代码和具体的对象实现解耦。这样子就不用每次都new对象,更换对象的话,所有new对象的地方也要修改,违背了开闭原则(对扩展开放,对修改关闭)。使用工厂来生产对象,更换对象也直接在工厂更换即可。

工厂模式的主要好处包括:

  1. 解耦合:工厂模式将对象的创建过程与客户端代码分离,客户端不需要知道具体的对象是如何创建的,只需要通过工厂方法获取对象即可,从而降低了代码之间的耦合度。
  2. 灵活性:由于工厂负责创建对象,客户端可以通过工厂方法获取不同的对象实例,而无需关心具体的实现细节,从而提高了系统的灵活性。
  3. 可扩展性:如果需要添加新的产品类型,只需在工厂中添加相应的产品创建逻辑,而不需要修改客户端代码,这样可以很方便地扩展系统的功能。
  4. 统一管理:工厂模式将对象的创建集中在一个地方,便于统一管理和维护,提高了代码的可维护性。

使用场景:

  • 当一个系统需要创建多个类型的对象,并且这些对象之间存在着共同的接口时,可以考虑使用工厂模式。
  • 当客户端不需要知道具体的对象是如何创建的,只需要获取对象实例时,可以使用工厂模式。
  • 当系统需要动态地决定创建哪种类型的对象时,可以使用工厂模式。

工厂模式包含以下几个核心角色:

  • 抽象产品(Abstract Product):**定义了产品的共同接口或抽象类。**它可以是具体产品类的父类或接口,规定了产品对象的共同方法
  • 具体产品(Concrete Product):实现了抽象产品接口,定义了具体产品的特定行为和属性。
  • 抽象工厂(Abstract Factory):声明了创建产品的抽象方法,可以是接口或抽象类。它可以有多个方法用于创建不同类型的产品。
  • 具体工厂(Concrete Factory):实现了抽象工厂接口,负责实际创建具体产品的对象

这里介绍三种工厂

  • 简单工厂模式(不属于GOF的23种经典设计模式)
  • 工厂方法模式
  • 抽象工厂模式

简单工厂模式

简单工厂不是一种设计模式,反而比较像是一种编程习惯。

结构:

简单工厂包含如下角色:

  • 抽象产品 :定义了产品的规范,描述了产品的主要特性和功能。
  • 具体产品 :实现或者继承抽象产品的子类
  • 具体工厂 :提供了创建产品的方法,调用者通过该方法来获取产品。

使用场景

  • 当对象的创建逻辑相对简单,并且不需要频繁地进行变更时,可以考虑使用简单工厂模式。
  • 在客户端只知道所需产品的名称或类型,而不需要关心产品的创建过程时,可以使用简单工厂模式。

实现思路:

java 复制代码
// 抽象产品接口
interface Product {      
    void show();
}

// 具体产品类A
class ConcreteProductA implements Product {
    @Override
    public void show() {
        System.out.println("This is product A.");
    }
}

// 具体产品类B
class ConcreteProductB implements Product {
    @Override
    public void show() {
        System.out.println("This is product B.");
    }
}

// 简单工厂类
class SimpleFactory {
    public static Product createProduct(String type) {
        if ("A".equals(type)) {
            return new ConcreteProductA();
        } else if ("B".equals(type)) {
            return new ConcreteProductB();
        }
        return null;
    }
}

// 客户端
public class Client {
    public static void main(String[] args) {
        Product productA = SimpleFactory.createProduct("A");
        productA.show();
        
        Product productB = SimpleFactory.createProduct("B");
        productB.show();
    }
}

上面的工厂类创建对象的功能定义为静态的,这个属于是静态工厂模式,当然你也可以不设置为静态的。

优缺点:

优点:

  • 简单工厂模式中,客户端通过工厂类的静态方法来获取产品实例,而不需要直接实例化具体产品类。如果要实现新产品直接修改工厂类,而不需要在原代码中修改。

缺点:

  • 工厂类负责创建所有产品,因此如果系统需要添加新的产品类型,需要修改工厂类,违反了开放封闭原则。

工厂方法模式

使用工厂方法模式可以完美的解决简单工厂模式的缺点,完全遵循开闭原则。

概念

定义一个用于创建对象的接口,让子类决定实例化哪个产品类对象。工厂方法使一个产品类的实例化延迟到其工厂的子类。

结构

工厂方法模式的主要角色:

  • 抽象工厂(Abstract Factory):提供了创建产品的接口,调用者通过它访问具体工厂的工厂方法来创建产品。
  • 具体工厂(ConcreteFactory):主要是实现抽象工厂中的抽象方法,完成具体产品的创建。
  • 抽象产品(Product):定义了产品的规范,描述了产品的主要特性和功能。
  • 具体产品(ConcreteProduct):实现了抽象产品角色所定义的接口,由具体工厂来创建,它同具体工厂之间一一对应。

图例

使用工厂方法模式对上例进行改进:

工厂方法模式适用于需要创建一系列相关对象的情况

java 复制代码
// 抽象产品接口
interface Product {
    void show();
}

// 具体产品类A
class ConcreteProductA implements Product {
    @Override
    public void show() {
        System.out.println("This is product A.");
    }
}

// 具体产品类B
class ConcreteProductB implements Product {
    @Override
    public void show() {
        System.out.println("This is product B.");
    }
}

// 抽象工厂类
interface Factory {
    Product createProduct();
}

// 具体工厂类A,负责创建产品A
class ConcreteFactoryA implements Factory {
    @Override
    public Product createProduct() {
        return new ConcreteProductA();
    }
}

// 具体工厂类B,负责创建产品B
class ConcreteFactoryB implements Factory {
    @Override
    public Product createProduct() {
        return new ConcreteProductB();
    }
}

// 客户端
public class Client {
    public static void main(String[] args) {
        Factory factoryA = new ConcreteFactoryA();
        Product productA = factoryA.createProduct();
        productA.show();
        
        Factory factoryB = new ConcreteFactoryB();
        Product productB = factoryB.createProduct();
        productB.show();
    }
}

于是乎要增加产品类时只要相应地增加工厂类,不需要修改工厂类的代码了,这样就解决了简单工厂模式的缺点。

使用场景

  • 当需要创建的对象是一个具体的产品,但是不确定具体产品的类型时,可以使用工厂方法模式。
  • 在工厂类中定义一个创建产品的抽象方法,由子类负责实现具体产品的创建过程,从而实现了产品的创建和客户端的解耦

优缺点

优点:

  • 工厂方法模式中,客户端通过调用工厂类的方法来创建产品,具体产品的创建逻辑由子类实现,不同的产品由不同的工厂子类负责创建。
  • 工厂方法模式符合开放封闭原则,因为客户端可以通过新增工厂子类来添加新的产品类型,而无需修改原有的代码。

缺点:

  • 每增加一个产品就要增加一个具体产品类和一个对应的具体工厂类,这增加了系统的复杂度。

抽象工厂模式

抽象工厂模式通常涉及一族相关的产品,每个具体工厂类负责创建该族中的具体产品。

使用场景

  • 当一个系统需要创建一系列相互关联或相互依赖的产品对象时,可以考虑使用抽象工厂模式。
  • 抽象工厂模式提供了一个创建一组相关或相互依赖对象的接口,客户端可以通过该接口来创建产品族中的不同产品,而不需要关心具体的产品实现。

所以由此也可看出,普通工厂模式,工厂方法模式都只是单一产品类的工厂;而很多时候我们需要综合性的,需要生产多等级产品的工厂。下图所示横轴是产品等级,也就是同一类产品;纵轴是产品族,也就是同一品牌的产品,同一品牌的产品产自同一个工厂:

结构

抽象工厂模式的主要角色如下:

  • 抽象工厂(Abstract Factory):提供了创建产品的接口,它包含多个创建产品的方法,可以创建多个不同等级的产品。
  • 具体工厂(Concrete Factory):主要是实现抽象工厂中的多个抽象方法,完成具体产品的创建。
  • 抽象产品(Product):定义了产品的规范,描述了产品的主要特性和功能,抽象工厂模式有多个抽象产品。
  • 具体产品(ConcreteProduct):实现了抽象产品角色所定义的接口,由具体工厂来创建,它同具体工厂之间是多对一的关系。

代码案例:

java 复制代码
// 抽象产品接口
interface Product {
    void show();
}

// 具体产品类A
class ConcreteProductA implements Product {
    @Override
    public void show() {
        System.out.println("This is product A.");
    }
}

// 具体产品类B
class ConcreteProductB implements Product {
    @Override
    public void show() {
        System.out.println("This is product B.");
    }
}

// 抽象工厂接口
interface AbstractFactory {
    Product createProductA();
    Product createProductB();
}

// 具体工厂类,负责创建产品A和产品B
class ConcreteFactory implements AbstractFactory {
    @Override
    public Product createProductA() {
        return new ConcreteProductA();
    }

    @Override
    public Product createProductB() {
        return new ConcreteProductB();
    }
}

// 客户端
public class Client {
    public static void main(String[] args) {
        AbstractFactory factory = new ConcreteFactory();
        Product productA = factory.createProductA();
        productA.show();
        
        Product productB = factory.createProductB();
        productB.show();
    }
}
  • 使用场景

    • 当需要创建的对象是一系列相互关联或相互依赖的产品族时,如电器工厂中的电视机、洗衣机、空调等。
    • 系统中有多个产品族,但每次只使用其中的某一族产品。如有人只喜欢穿某一个品牌的衣服和鞋。
    • 系统中提供了产品的类库,且所有产品的接口相同,客户端不依赖产品实例的创建细节和内部结构。

优缺点

优点:

当一个产品族中的多个对象被设计成一起工作时,它能保证客户端始终只使用同一个产品族中的对象。

缺点:

当产品族中需要增加一个新的产品时,所有的工厂类都需要进行修改。

模式扩展 (利用反射机制来创建对象)

简单工厂+配置文件解除耦合

可以通过工厂模式+配置文件的方式解除工厂对象和产品对象的耦合。

通过使用配置文件,将创建对象的参数存储在外部配置文件中,可以在不修改客户端代码的情况下,通过修改配置文件来改变对象的创建方式。这样就可以实现对创建逻辑的解耦合,客户端不需要知道具体的创建方式,只需要从工厂类获取对象即可。

具体实现步骤如下:

  1. 在配置文件中配置需要创建的对象的类名或者类型。
  2. 在简单工厂类中读取配置文件,并根据配置的信息来创建对应的对象。

假设有一个配置文件 config.properties,内容如下:

go 复制代码
product.type=ConcreteProductA

创建简单工厂类 SimpleFactory.java,用于读取配置文件并根据配置创建对象:

java 复制代码
import java.io.IOException;
import java.io.InputStream;
import java.util.Properties;

public class SimpleFactory { 
    public static Product createProduct() {
        Properties properties = new Properties();
        try (InputStream inputStream = SimpleFactory.class.getResourceAsStream("config.properties")) {
            properties.load(inputStream);
            String productType = properties.getProperty("product.type");
            if ("ConcreteProductA".equals(productType)) {
                return new ConcreteProductA();
            } else if ("ConcreteProductB".equals(productType)) {
                return new ConcreteProductB();
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
        return null;
    }
}

在日常开发中,设计模式中的一些常用模式包括:

  1. 单例模式 (Singleton):用于确保一个类只有一个实例,并提供全局访问点,例如数据库连接池、日志系统等。
  2. 工厂模式 (Factory):用于创建对象的接口,但是由子类决定要实例化的类是哪一个。例如,可以用工厂模式创建各种类型的文件解析器。
  3. 观察者模式 (Observer):用于建立对象之间一对多的依赖关系,当一个对象的状态发生变化时,所有依赖它的对象都会得到通知。例如,GUI界面中的事件监听器。
  4. 策略模式 (Strategy):定义一系列算法,将每个算法封装起来,并使它们可以互换。例如,根据用户的选择使用不同的支付策略。
  5. 装饰器模式 (Decorator):动态地给一个对象添加一些额外的职责。例如,在图像处理中可以使用装饰器来添加滤镜效果。
  6. 模板方法模式 (Template Method):定义一个算法的骨架,允许子类为一个或多个步骤提供实现。例如,在构建流程中的各个阶段都有固定的步骤,但是具体实现可能不同。
相关推荐
whyTeaFo1 天前
MIT 6.1810: xv6 book Chapter3: Page tables 笔记
笔记
请为小H留灯1 天前
IDEA / PyCharm 如何实现“一个项目一个窗口”?多项目并行开发设置
java·pycharm·intellij-idea·实战项目
苦逼的猿宝1 天前
宠物咖啡馆平台的设计与实现(源码+论文)
java·毕业设计·springboot·计算机毕业设计
吃好睡好便好1 天前
矩阵的乘法运算
数据结构·人工智能·学习·线性代数·算法·matlab·矩阵
沐知全栈开发1 天前
JavaScript 注释
开发语言
程序员buddha1 天前
Spring Boot框架,类注入成 Bean的方式
java·spring boot·后端
城管不管1 天前
什么是Prompt?
android·java·数据库·语言模型·llm·prompt
光电的一只菜鸡1 天前
shell脚本开发技巧
开发语言·ios·swift
AI大模型1 天前
被AI抢饭碗的Java程序员,后来都怎样了?
java·后端·ai编程
苦逼的猿宝1 天前
医院管理系统.(源码+论文)
java·毕业设计·springboot·计算机毕业设计