设计模式之三种工厂模式


共计 5742 个字符,预计需要花费 15 分钟才能阅读完成。

前言

工厂模式是一种创建对象的设计模式,它提供了一个统一的接口来实例化对象,而不需要通过直接调用构造函数来创建。工厂模式可以根据不同的条件返回不同类的实例,从而实现对象的灵活创建。

常见的工厂模式包括:简单工厂模式、工厂方法模式和抽象工厂模式。

详解

1. 简单工厂模式

简单工厂模式,就像它的名字一样,非常简单。只需要创建一个工厂类,根据传入的参数或条件,工厂类决定实例化哪个具体类的对象并返回。

1.1 模式结构

  • Factory:工厂角色 - 工厂角色负责实现创建所有实例的内部逻辑
  • Product:抽象产品角色 - 抽象产品角色是所创建的所有对象的父类,负责描述所有实例所共有的公共接口
  • ConcreteProduct:具体产品角色 - 具体产品角色是创建目标,所有创建的对象都充当这个角色的某个具体类的实例。

设计模式之三种工厂模式

/>

1.2 代码分析

// 产品接口
interface Product {
    void use();
}

// 具体产品A
class ConcreteProductA implements Product {
    @Override
    public void use() {
        System.out.println("使用具体产品A");
    }
}

// 具体产品B
class ConcreteProductB implements Product {
    @Override
    public void use() {
        System.out.println("使用具体产品B");
    }
}

// 简单工厂类
class SimpleFactory {
    public static Product createProduct(String type) {
        if (type.equalsIgnoreCase("A")) {
            return new ConcreteProductA();
        } else if (type.equalsIgnoreCase("B")) {
            return new ConcreteProductB();
        }
        throw new IllegalArgumentException("Invalid product type: " + type);
    }
}

// 客户端代码
public class Client {
    public static void main(String[] args) {
        Product productA = SimpleFactory.createProduct("A");
        productA.use();

        Product productB = SimpleFactory.createProduct("B");
        productB.use();
    }
}

1.3 优点

  • 工厂类含有必要的判断逻辑,可以决定在什么时候创建哪一个产品类的实例,客户端可以免除直接创建产品对象的责任,而仅仅“消费”产品;简单工厂模式通过这种做法实现了对责任的分割,它提供了专门的工厂类用于创建对象。
  • 客户端无须知道所创建的具体产品类的类名,只需要知道具体产品类所对应的参数即可,对于一些复杂的类名,通过简单工厂模式可以减少使用者的记忆量。
  • 通过引入配置文件,可以在不修改任何客户端代码的情况下更换和增加新的具体产品类,在一定程度上提高了系统的灵活性。

1.4 缺点

  • 由于工厂类集中了所有产品创建逻辑,一旦不能正常工作,整个系统都要受到影响。
  • 使用简单工厂模式将会增加系统中类的个数,在一定程序上增加了系统的复杂度和理解难度。
  • 系统扩展困难,一旦添加新产品就不得不修改工厂逻辑,在产品类型较多时,有可能造成工厂逻辑过于复杂,不利于系统的扩展和维护。
  • 简单工厂模式由于使用了静态工厂方法,造成工厂角色无法形成基于继承的等级结构。

1.5 适用

简单工厂适用于需要创建的类比较少,比较确定所需要创建的产品种类。

2. 工厂方法模式

工厂方法模式中,只需要定义一个用于创建对象的接口,但是具体的对象的创建由子类来决定。

解决了工厂模式中每新增一个产品,都需要修改工厂对象,在工厂方法模式只需要新增具体的工厂类和产品类即可。

2.1 模式结构

工厂方法模式包含如下角色:

  • Product:抽象产品
  • ConcreteProduct:具体产品
  • Factory:抽象工厂
  • ConcreteFactory:具体工厂

设计模式之三种工厂模式

/>

2.2 代码分析

// 定义产品接口
interface Product {
    void doSomething();
}

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

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

// 工厂抽象类
abstract class Factory {
    // 工厂方法,由子类实现
    abstract Product createProduct();

    // 一些公共逻辑
    void commonMethod() {
        System.out.println("Common Method");
    }

    // 客户端代码调用的方法
    void doSomething() {
        // 创建产品
        Product product = createProduct();

        // 调用产品方法
        product.doSomething();

        // 执行其他逻辑
        commonMethod();
    }
}

// 具体工厂类A
class ConcreteFactoryA extends Factory {
    @Override
    Product createProduct() {
        return new ConcreteProductA();
    }
}

// 具体工厂类B
class ConcreteFactoryB extends Factory {
    @Override
    Product createProduct() {
        return new ConcreteProductB();
    }
}

// 客户端代码
public class Main {
    public static void main(String[] args) {
        // 创建具体工厂A
        Factory factoryA = new ConcreteFactoryA();
        // 客户端通过工厂A创建产品
        factoryA.doSomething();

        // 创建具体工厂B
        Factory factoryB = new ConcreteFactoryB();
        // 客户端通过工厂B创建产品
        factoryB.doSomething();
    }
}

2.3 优点

  • 在工厂方法模式中,工厂方法用来创建客户所需要的产品,同时还向客户隐藏了哪种具体产品类将被实例化这一细节,用户只需要关心所需产品对应的工厂,无须关心创建细节,甚至无须知道具体产品类的类名。
  • 基于工厂角色和产品角色的多态性设计是工厂方法模式的关键。它能够使工厂可以自主确定创建何种产品对象,而如何创建这个对象的细节则完全封装在具体工厂内部。工厂方法模式之所以又被称为多态工厂模式,是因为所有的具体工厂类都具有同一抽象父类。
  • 使用工厂方法模式的另一个优点是在系统中加入新产品时,无须修改抽象工厂和抽象产品提供的接口,无须修改客户端,也无须修改其他的具体工厂和具体产品,而只要添加一个具体工厂和具体产品就可以了。这样,系统的可扩展性也就变得非常好,完全符合“开闭原则”。

2.4 缺点

  • 在添加新产品时,需要编写新的具体产品类,而且还要提供与之对应的具体工厂类,系统中类的个数将成对增加,在一定程度上增加了系统的复杂度,有更多的类需要编译和运行,会给系统带来一些额外的开销。
  • 由于考虑到系统的可扩展性,需要引入抽象层,在客户端代码中均使用抽象层进行定义,增加了系统的抽象性和理解难度,且在实现时可能需要用到DOM、反射等技术,增加了系统的实现难度。

2.5 适用

工厂模式方法适用于当一个类不知道它所必须创建的对象的类时,比如日志工厂,使用工厂模式方法可以适应以后出现的日志实现。

如果你说上面简单工厂为什么也能实现根据类名创建对应的 Conntion 类,因为它是使用的反射的方法。

3. 抽象工厂模式

抽象工厂模式是一种创建型设计模式,它提供了一种方法来创建相关或依赖对象的系列,而无需指定具体类。在抽象工厂模式中,客户端代码通过使用抽象接口或抽象类创建一组相关的产品对象,而不是通过直接实例化具体类来创建这些对象。

3.1 模式结构

  • AbstractFactory:抽象工厂
  • ConcreteFactory:具体工厂
  • AbstractProduct:抽象产品
  • Product:具体产品

设计模式之三种工厂模式

/>

3.2 代码分析

// 抽象产品A
interface AbstractProductA {
    void operationA();
}

// 具体产品A1
class ConcreteProductA1 implements AbstractProductA {
    @Override
    public void operationA() {
        System.out.println("具体产品A1的操作");
    }
}

// 具体产品A2
class ConcreteProductA2 implements AbstractProductA {
    @Override
    public void operationA() {
        System.out.println("具体产品A2的操作");
    }
}

// 抽象产品B
interface AbstractProductB {
    void operationB();
}

// 具体产品B1
class ConcreteProductB1 implements AbstractProductB {
    @Override
    public void operationB() {
        System.out.println("具体产品B1的操作");
    }
}

// 具体产品B2
class ConcreteProductB2 implements AbstractProductB {
    @Override
    public void operationB() {
        System.out.println("具体产品B2的操作");
    }
}

// 抽象工厂
interface AbstractFactory {
    AbstractProductA createProductA();
    AbstractProductB createProductB();
}

// 具体工厂1
class ConcreteFactory1 implements AbstractFactory {
    @Override
    public AbstractProductA createProductA() {
        return new ConcreteProductA1();
    }

    @Override
    public AbstractProductB createProductB() {
        return new ConcreteProductB1();
    }
}

// 具体工厂2
class ConcreteFactory2 implements AbstractFactory {
    @Override
    public AbstractProductA createProductA() {
        return new ConcreteProductA2();
    }

    @Override
    public AbstractProductB createProductB() {
        return new ConcreteProductB2();
    }
}

// 客户端代码
public class Client {
    public static void main(String[] args) {
        // 创建具体工厂1
        AbstractFactory factory1 = new ConcreteFactory1();
        // 使用工厂1创建产品A和产品B
        AbstractProductA productA1 = factory1.createProductA();
        AbstractProductB productB1 = factory1.createProductB();
        productA1.operationA();  // 输出:具体产品A1的操作
        productB1.operationB();  // 输出:具体产品B1的操作

        // 创建具体工厂2
        AbstractFactory factory2 = new ConcreteFactory2();
        // 使用工厂2创建产品A和产品B
        AbstractProductA productA2 = factory2.createProductA();
        AbstractProductB productB2 = factory2.createProductB();
        productA2.operationA();  // 输出:具体产品A2的操作
        productB2.operationB();  // 输出:具体产品B2的操作
    }
}

3.3 优点

  • 抽象工厂模式隔离了具体类的生成,使得客户并不需要知道什么被创建。由于这种隔离,更换一个具体工厂就变得相对容易。所有的具体工厂都实现了抽象工厂中定义的那些公共接口,因此只需改变具体工厂的实例,就可以在某种程度上改变整个软件系统的行为。另外,应用抽象工厂模式可以实现高内聚低耦合的设计目的,因此抽象工厂模式得到了广泛的应用。
  • 当一个产品族中的多个对象被设计成一起工作时,它能够保证客户端始终只使用同一个产品族中的对象。这对一些需要根据当前环境来决定其行为的软件系统来说,是一种非常实用的设计模式。
  • 增加新的具体工厂和产品族很方便,无须修改已有系统,符合“开闭原则”。

3.4 缺点

  • 在添加新的产品对象时,难以扩展抽象工厂来生产新种类的产品,这是因为在抽象工厂角色中规定了所有可能被创建的产品集合,要支持新种类的产品就意味着要对该接口进行扩展,而这将涉及到对抽象工厂角色及其所有子类的修改,显然会带来较大的不便。
  • 开闭原则的倾斜性(增加新的工厂和产品族容易,增加新的产品等级结构麻烦)。

3.5 适用

适用于系统中有多于一个的产品族,而每次只使用其中某一产品族,并且属于同一个产品族的产品将在一起使用,这一约束必须在系统的设计中体现出来。

比如在很多软件系统中需要更换界面主题,要求界面中的按钮、文本框、背景色等一起发生改。

提醒:本文发布于494天前,文中所关联的信息可能已发生改变,请知悉!

Tips:清朝云网络工作室

阅读剩余
THE END