前言
工厂设计模式(Factory Pattern)是最常用的设计模式之一,属于创建型模式。其核心思想是通过引入一个工厂类来实例化对象,而不是直接在客户端代码中使用 new
关键字来创建对象。这种方式能够将对象的创建过程封装起来,使得代码更加灵活、可扩展、易于维护。
工厂模式主要适用于以下场景:
当一个类不知道它所需要的对象的确切类型时。
当一个类希望将创建对象的任务委托给子类时。
当类的创建过程比较复杂时。
工厂模式的种类
工厂设计模式包括以下几种类型,每种模式的适用场景略有不同:
简单工厂模式:通过一个工厂类来决定创建哪种类型的产品对象。
工厂方法模式:由子类来决定实例化哪个具体产品。
抽象工厂模式:提供一个接口用于创建一系列相关产品,而无需指定它们的具体类。
1. 简单工厂模式
1.1 模式概述
简单工厂模式是最基础的工厂模式,其核心思想是通过一个工厂类来决定创建哪种类型的产品对象。客户端并不直接实例化产品类,而是通过工厂类来获得实例。
1.2 类图
简单工厂模式的时序图如下所示:
下面我们围绕这个时序图来讲解
1.3 代码示例
假设我们有两种类型的产品,ConcreteProductA
和 ConcreteProductB
,我们需要根据客户端的需求动态创建相应的产品对象。
// 产品接口
public interface Product {
void operation(); //具体实现
}
// 具体产品A
public class ConcreteProductA implements Product {
@Override
public void operation() {
System.out.println("ConcreteProductA operation"); //对产品A不同的实现
}
}
// 具体产品B
public class ConcreteProductB implements Product {
@Override
public void operation() {
System.out.println("ConcreteProductB operation");//对产品B不同的实现
}
}
// 简单工厂类
public class SimpleFactory {
/**
* 根据不同的type执行我们不同的产品类型
*/
public static Product createProduct(String type) {
if ("productA".equalsIgnoreCase(type)) {
return new ConcreteProductA();
} else if ("productB".equalsIgnoreCase(type)) {
return new ConcreteProductB();
} else {
throw new IllegalArgumentException("Unknown product type");
}
}
}
// 调用代码
public class Client {
public static void main(String[] args) {
Product productA = SimpleFactory.createProduct("A");
productA.operation(); // 输出:ConcreteProductA operation
Product productB = SimpleFactory.createProduct("B");
productB.operation(); // 输出:ConcreteProductB operation
}
}
//定义枚举方便维护
public enum ProductType{
productA,
productB //枚举中定义产品类型
}
1.4 优缺点
优点:
封装性好:客户端代码不需要直接创建产品对象,工厂类负责创建产品实例,客户端只需要知道如何获取产品即可。
降低耦合度:客户端和产品类之间的依赖关系被削弱,工厂类充当了中介角色。
缺点:
扩展困难:如果产品种类较多,工厂类的代码会变得非常复杂,因为每增加一种产品,工厂类就需要增加一条判断逻辑,违背了开闭原则。
违反单一职责原则:工厂类负责多个产品的实例化,增加了职责。
2. 工厂方法模式
2.1 模式概述
工厂方法模式通过定义一个创建对象的接口,但由子类来决定实例化哪个类。这种模式通过子类来具体化创建产品的方式,使得创建过程更加灵活。客户端代码不需要依赖具体的类,而是依赖于工厂接口来创建产品。
2.2 类图
工厂方法模式的时序图图如下:
2.3 代码示例
在工厂方法模式中,我们定义一个抽象工厂接口,并在子类中实现具体的产品创建方法。
// 产品接口
public interface Product {
void operation();
}
// 具体产品A
public class ConcreteProductA implements Product {
@Override
public void operation() {
System.out.println("ConcreteProductA operation");
}
}
// 具体产品B
public class ConcreteProductB implements Product {
@Override
public void operation() {
System.out.println("ConcreteProductB operation");
}
}
// 抽象工厂类
public interface Creator {
Product factoryMethod();
}
// 具体工厂A
public class ConcreteCreatorA implements Creator {
@Override
public Product factoryMethod() {
return new ConcreteProductA();
}
}
// 具体工厂B
public class ConcreteCreatorB implements Creator {
@Override
public Product factoryMethod() {
return new ConcreteProductB();
}
}
// 客户端代码
public class Client {
public static void main(String[] args) {
Creator creatorA = new ConcreteCreatorA();
Product productA = creatorA.factoryMethod();
productA.operation(); // 输出:ConcreteProductA operation
Creator creatorB = new ConcreteCreatorB();
Product productB = creatorB.factoryMethod();
productB.operation(); // 输出:ConcreteProductB operation
}
}
2.4 优缺点
优点:
符合开闭原则:新增产品时,客户端只需要使用新的工厂类,而无需修改现有代码。
解耦合:客户端代码只依赖工厂接口,而不需要依赖具体的产品类,降低了系统的耦合度。
缺点:
工厂类增多:每增加一个具体产品,都需要创建一个新的工厂类,可能导致系统中的类数量激增,增加系统的复杂度。
3. 抽象工厂模式
3.1 模式概述
抽象工厂模式是工厂模式的一种扩展,它不仅创建单一产品,还可以创建一系列相关的产品对象。抽象工厂提供了一个接口,允许客户端创建一组产品对象,而无需指定它们具体的类。这样可以确保一组产品对象在同一工厂下被创建。
3.2 类图
抽象工厂模式的时序图图如下:
3.3 代码示例
// 产品A接口
public interface ProductA {
void operationA();
}
// 产品B接口
public interface ProductB {
void operationB();
}
// 具体产品A1
public class ConcreteProductA1 implements ProductA {
@Override
public void operationA() {
System.out.println("ConcreteProductA1 operationA");
}
}
// 具体产品A2
public class ConcreteProductA2 implements ProductA {
@Override
public void operationA() {
System.out.println("ConcreteProductA2 operationA");
}
}
// 具体产品B1
public class ConcreteProductB1 implements ProductB {
@Override
public void operationB() {
System.out.println("ConcreteProductB1 operationB");
}
}
// 具体产品B2
public class ConcreteProductB2 implements ProductB {
@Override
public void operationB() {
System.out.println("ConcreteProductB2 operationB");
}
}
// 抽象工厂
public interface AbstractFactory {
ProductA createProductA();
ProductB createProductB();
}
// 具体工厂1
public class ConcreteFactory1 implements AbstractFactory {
@Override
public ProductA createProductA() {
return new ConcreteProductA1();
}
@Override
public ProductB createProductB() {
return new ConcreteProductB1();
}
}
// 具体工厂2
public class ConcreteFactory2 implements AbstractFactory {
@Override
public ProductA createProductA() {
return new ConcreteProductA2();
}
@Override
public ProductB createProductB() {
return new ConcreteProductB2();
}
}
// 客户端代码
public class Client {
public static void main(String[] args) {
AbstractFactory factory1 = new ConcreteFactory1();
ProductA productA1 = factory1.createProductA();
productA1.operationA(); // 输出:ConcreteProductA1 operationA
ProductB productB1 = factory1.createProductB();
productB1.operationB(); // 输出:ConcreteProductB1 operationB
AbstractFactory factory2 = new ConcreteFactory2();
ProductA productA2 = factory2.createProductA();
productA2.operationA(); // 输出:ConcreteProductA2 operationA
ProductB productB2 = factory2.createProductB();
productB2.operationB(); // 输出:ConcreteProductB2 operationB
}
}
3.4 优缺点
优点:
产品族的创建:可以确保同一产品族的产品一起被创建,避免了单个产品在不同的工厂中不兼容的情况。
符合开闭原则:在添加新产品时,只需要新增相应的具体产品和工厂类,而无需修改现有的代码。
缺点:
增加了类的数量:每种产品系列都会引入多个工厂类,导致系统的复杂度增加。
扩展困难:若要增加一个新的产品系列,需要修改抽象工厂的接口,违反了开闭原则。
总结
根据实际需求选择不同的工厂模式,能够提高系统的灵活性、可扩展性和可维护性。不同的工厂模式适用于不同的场景,简单工厂适合少量产品,工厂方法和抽象工厂适合产品种类多且需要灵活扩展的情况。