设计模式-工厂模式详解

5 阅读5分钟

工厂模式介绍

工厂模式的初衷是为了将创建对象和使用对象的逻辑进行分离,将创建对象的逻辑封装于工厂类中,使得客户端无需关注对象的创建逻辑(无需关注具体创建的是哪一个类的对象),只需关注如何使用即可。

工厂模式属于设计模式中的创建型模式。

它划分为3种:

  • 简单工厂模式
  • 工厂方法模式
  • 抽象工厂模式

简单工厂模式

简单工厂模式其实不属于23种正式的设计模式中。

在简单工厂模式中,一共有4种角色:

  • 工厂类:负责创建产品类的实例,提供一个静态方法供客户端调用
  • 抽象产品:定义产品类的公共接口
  • 具体产品类:实现抽象产品接口的具体产品类
  • 客户端:使用工厂类获取产品类的实例,并且使用这些实例

示例代码:

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

// 具体产品1
class ConcreteProduct1 implements Product {
    public void use() {
        System.out.println("产品1");
    }
}

// 具体产品2
class ConcreteProduct2 implements Product {
    public void use() {
        System.out.println("产品2");
    }
}

// 简单工厂类,此处可以根据类型返回对应的对象,但缺点是违背了开闭原则
class SimpleFactory {
    public static Product createProduct(String type) {
        switch (type) {
            case "1":
                return new ConcreteProduct1();
            case "2":
                return new ConcreteProduct2();
            default:
                return null;
        }
    }
}

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

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

这里先介绍一下开闭原则。

开闭原则:对扩展开放,对修改关闭。简单点来说,就是我们在实现一个新功能的时候,最好是直接新增一些代码,而不是需要在原代码处做修改。如果你在项目中使用过策略模式,对开闭原则应该就能有比较深刻的体会了。

从上面的代码也可以看出,当你想要再新增一种产品的时候,你不得不修改SimpleFactory中的createProduct方法,也就是说,实现新功能的时候我们需要修改原代码,显然,这违背了开闭原则。

在日常开发中,我们可能常常会看到一些程序员在项目中使用简单工厂模式,因为它简单,易于理解和实现,但是因为其违背开闭原则,所以笔者不推荐在实际项目中使用。

工厂方法模式

为了解决简单工厂模式的扩展问题,工厂方法模式出现了。

在工厂方法模式中,有5种角色:

  • 抽象工厂:定义工厂类的公共接口
  • 具体工厂:实现抽象工厂的具体实现类,返回具体产品类的实例
  • 抽象产品:定义产品类的公共接口
  • 具体产品:实现抽象产品接口的具体产品类
  • 客户端:使用工厂类获取产品类的实例,并且使用这些实例

代码实现:

// 抽象产品
interface Product {
    void use();
}

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

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

// 抽象工厂
abstract class Creator {
    public abstract Product factoryMethod();
}

// 具体工厂A
class ConcreteCreatorA extends Creator {
    public Product factoryMethod() {
        return new ConcreteProductA();
    }
}

// 具体工厂B
class ConcreteCreatorB extends Creator {
    public Product factoryMethod() {
        return new ConcreteProductB();
    }
}

// 客户端
public class Client {
    public static void main(String[] args) {
        Creator creatorA = new ConcreteCreatorA();
        Product productA = creatorA.factoryMethod();
        productA.use();

        Creator creatorB = new ConcreteCreatorB();
        Product productB = creatorB.factoryMethod();
        productB.use();
    }
}

如果此时我们想新增一种产品,只需要新增一个具体产品类,再新增一个具体工厂类即可,无需修改原有代码,满足开闭原则。

缺点在于需要创建多个具体工厂,增加了系统复杂性,并且客户端需要了解具体工厂所需的参数。同时,工厂方法模式无法解决产品族的问题,可以看到代码示例中,只有一类产品,如果有多种类别的产品,工厂方法模式就无法解决了。

抽象工厂模式

抽象工厂模式是为了解决工厂方法模式所无法处理的产品族的问题而出现的(产品族的含义是,同一个系列的不同类别的产品,以UI设计为例,windows的按钮和文本框属于一个产品族,linux的按钮和文本框也属于一个产品族,按钮和文本框是不同类别的产品)。与工厂方法模式不同的是,工厂方法模式中,每个具体工厂只生产一种具体产品,而抽象工厂模式中,每个具体工厂生产多种相关的具体产品。当需要添加产品族时,只需要新增一个具体的工厂类和对应的具体产品即可,符合开闭原则。

但是如果需要新增产品类别的话,就要修改抽象工厂以及所有的具体工厂,违反开闭原则。所以通常抽象工厂模式适用于产品类别已经确定,但是产品族可能需要拓展的情况。

抽象工厂模式中的5类角色与工厂方法模式一致,这里不做赘述。

示例代码如下:

// 抽象产品A
interface ProductA {
    void use();
}

// 抽象产品B
interface ProductB {
    void use();
}

// 具体产品A1
class ProductA1 implements ProductA {
    public void use() {
        System.out.println("使用产品A1");
    }
}

// 具体产品A2
class ProductA2 implements ProductA {
    public void use() {
        System.out.println("使用产品A2");
    }
}

// 具体产品B1
class ProductB1 implements ProductB {
    public void use() {
        System.out.println("使用产品B1");
    }
}

// 具体产品B2
class ProductB2 implements ProductB {
    public void use() {
        System.out.println("使用产品B2");
    }
}

// 抽象工厂
interface AbstractFactory {
    ProductA createProductA();
    ProductB createProductB();
}

// 具体工厂1
class ConcreteFactory1 implements AbstractFactory {
    public ProductA createProductA() {
        return new ProductA1();
    }

    public ProductB createProductB() {
        return new ProductB1();
    }
}

// 具体工厂2
class ConcreteFactory2 implements AbstractFactory {
    public ProductA createProductA() {
        return new ProductA2();
    }

    public ProductB createProductB() {
        return new ProductB2();
    }
}

// 客户端
public class Client {
    public static void main(String[] args) {
        AbstractFactory factory1 = new ConcreteFactory1();
        ProductA productA1 = factory1.createProductA();
        ProductB productB1 = factory1.createProductB();
        productA1.use();
        productB1.use();

        AbstractFactory factory2 = new ConcreteFactory2();
        ProductA productA2 = factory2.createProductA();
        ProductB productB2 = factory2.createProductB();
        productA2.use();
        productB2.use();
    }
}

以这里进行分析,ProductA1和ProductB1属于同一个产品族,ProductA是一个产品类别,ProductB是一个产品类别。

简而言之,工厂方法是“一个产品,多种实现”;抽象工厂是“多种产品,按族实现”。