工厂模式 详解 设计模式

工厂模式

其主要目的是封装对象的创建过程 ,使客户端代码和具体的对象实现解耦。这样子就不用每次都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):定义一个算法的骨架,允许子类为一个或多个步骤提供实现。例如,在构建流程中的各个阶段都有固定的步骤,但是具体实现可能不同。
相关推荐
morris1311 分钟前
【SpringBoot】Xss的常见攻击方式与防御手段
java·spring boot·xss·csp
也无晴也无风雨10 分钟前
代码中的设计模式-策略模式
设计模式·bash·策略模式
Source.Liu18 分钟前
【用Rust写CAD】第二章 第四节 函数
开发语言·rust
monkey_meng18 分钟前
【Rust中的迭代器】
开发语言·后端·rust
余衫马21 分钟前
Rust-Trait 特征编程
开发语言·后端·rust
monkey_meng24 分钟前
【Rust中多线程同步机制】
开发语言·redis·后端·rust
七星静香26 分钟前
laravel chunkById 分块查询 使用时的问题
java·前端·laravel
Jacob程序员26 分钟前
java导出word文件(手绘)
java·开发语言·word
ZHOUPUYU27 分钟前
IntelliJ IDEA超详细下载安装教程(附安装包)
java·ide·intellij-idea
stewie630 分钟前
在IDEA中使用Git
java·git