工厂模式是一种创建型设计模式, 旨在将对象的创建过程和使用过程分离. 这样可以在不改变客户端代码的前提下, 灵活创建不同类型的对象

工厂模式实现

  1. 简单工厂模式

简单工厂模式使用一个工厂类根据传入的参数决定创建哪种具体产品类的实例. 它不属于设计模式的23种, 但它为理解工厂模式奠定了基础

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

// 具体产品A
class ConcreateProductA implements Product {
public void use() {
System.out.println("Using product A");
}
}

// 具体产品B
class ConcreateProductB implements Product {
public void use() {
System.out.println("Using product B");
}
}

// 简单工厂类
class SimpleFactory {
public static Product createProduct(String type) {
if (type.equals("A")) {
return new ConcreateProductA();
} else if (type.equals("B")) {
return new ConcreateProductB();
} else {
throw new IllegalArgumentException("Unknown product type");
}
}
}

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

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

优点: 封装了创建对象的流程, 可以通过参数直接获取对象, 把对象的创建和业务逻辑层分开, 这样以后就避免了修改客户端代码. 如果要实现新产品直接修改工厂类, 而不需要在源代码中修改, 这样就降低了客户代码修改的可能性, 更容易拓展

缺点: 增加新产品时还需要修改工厂类的代码, 违背了开闭原则

  1. 工厂方法模式

工厂方法模式使用工厂接口定义一个创建对象的接口, 但由子类决定实例化哪个类, 这样工厂方法模式使得一个类的实例延迟到其子类

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

// 具体产品A
class ConcreateProductA implements Product {
public void use() {
System.out.println("Using product A");
}
}

// 具体产品B
class ConcreateProductB implements Product {
public void use() {
System.out.println("Using product B");
}
}

// 工厂接口
interface Factory {
Product createProduct();
}

// 具体工厂A
class ConcreteFactoryA implements Factory {
public Product createProduct() {
return new ConcreteProductA();
}
}

// 具体工厂A
class ConcreteFactoryB implements Factory {
public Product createProduct() {
return new ConcreteProductB();
}
}

// 客户端代码
public class Client {
public static void main(String[] args) {
Factory factoryA = new ConcreteFactoryA();
Product productA = factoryA.createProduct();
productA.use();

Factory factoryB = new ConcreteFactoryB();
Product productB = factoryB.createProduct();
productB.use();
}
}

优点:

  • 用户只需要知道具体工厂的名称就能得到所要的产品, 不需要知道产品的具体创建过程
  • 在系统增加新的产品时只需要添加具体产品类和对应的具体工厂类, 无须对原工厂进行任何修改, 满足开闭原则

缺点: 每增加一个产品就要增加一个具体产品类和具体工厂类, 增加了系统复杂度

  1. 抽象工厂模式

抽象工厂模式提供一个创建一系列相关或相互依赖对象的接口, 而无需指定它们具体的类. 通过定义多个工厂接口来实现不同产品族的创建

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

// 产品B接口
interface ProductB {
void eat();
}

// 具体产品A1
class ConcreteProductA1 implements ProductA {
public void use() {
System.out.println("Using product A1");
}
}

// 具体产品A2
class ConcreteProductA2 implements ProductA {
public void use() {
System.out.println("Using product A2");
}
}

// 具体产品B1
class ConcreteProductB1 implements ProductB {
public void eat() {
System.out.println("Eating product B1");
}
}

// 具体产品B2
class ConcreteProductB2 implements ProductB {
public void eat() {
System.out.println("Eating product B2");
}
}

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

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

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

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

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

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

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

工厂方法模式与抽象工厂模式的区别

  1. 复杂性和用途
    • 工厂方法模式: 创建一个具体产品对象, 适合于一个产品等级结构
    • 抽象工厂模式: 创建一系列相关或相互依赖的对象, 适合于多个产品等级结构
  2. 类结构
    • 工厂方法模式: 只有一个抽象产品类和多个具体产品类, 以及一个抽象工厂类和多个具体工厂类
    • 抽象工厂模式: 有多个抽象产品类和多个具体产品类, 以及一个抽象工厂类和多个具体工厂类
  3. 拓展性:
    • 工厂方法模式: 增加新的产品需要增加新的具体产品类和具体工厂类
    • 抽象工厂模式: 增加新的产品族需要增加新的具体工厂类, 增加新的产品等级需要增加修改所有的工厂类

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

缺点: 当产品族中需要添加一个新产品时, 所有的工厂类都需要修改