工厂模式(Factory Pattern)是一种创建对象的设计模式,属于 创建型模式(Creational Pattern)之一。其主要目的是通过定义一个工厂方法来创建对象,而不是直接通过 new
关键字实例化对象,从而将对象的创建过程与使用过程分离。这种方式能够减少代码中的耦合度,提高代码的可维护性、可扩展性,并符合面向对象设计的 单一职责原则和开放封闭原则。
工厂模式的核心思想是让子类决定实例化哪一个类,而父类提供创建对象的接口。它将对象的创建推迟到子类中执行。
1. 工厂模式的结构
工厂模式主要由以下几部分组成:
-
抽象产品(Product): 定义了产品的抽象接口,所有具体产品都会实现这个接口。
-
具体产品(ConcreteProduct): 实现了抽象产品接口的具体类,提供具体的实现。
-
抽象工厂(Creator): 定义了一个工厂方法,返回一个产品对象。此方法可以是抽象方法,也可以是具体方法,具体由子类实现。
-
具体工厂(ConcreteCreator): 实现了抽象工厂中的工厂方法,并返回具体的产品对象。
2. 工厂模式的分类
工厂模式可以根据工厂方法的数量和使用方式,分为以下几种类型:
-
简单工厂模式(Simple Factory): 又称静态工厂方法模式,它通过一个工厂类来创建对象。这个工厂类决定了具体产品的类型。简单工厂模式并不严格属于设计模式,因为它不符合开闭原则(即扩展时需要修改工厂类)。但它的实现比较简单,适用于产品类型固定的场景。
优点:
- 客户端只依赖工厂类提供的接口,而不需要了解对象的具体类。
- 代码可读性高,易于理解。
缺点:
- 违反了开闭原则,如果产品需要扩展,必须修改工厂类。
- 增加了工厂类的复杂度,尤其在产品种类较多时,工厂类会变得庞大。
示例代码:
// 抽象产品 public interface Product {void doSomething(); }// 具体产品A public class ProductA implements Product {@Overridepublic void doSomething() {System.out.println("Product A is doing something.");} }// 具体产品B public class ProductB implements Product {@Overridepublic void doSomething() {System.out.println("Product B is doing something.");} }// 工厂类 public class SimpleFactory {public static Product createProduct(String type) {if ("A".equals(type)) {return new ProductA();} else if ("B".equals(type)) {return new ProductB();} else {return null;}} }// 客户端代码 public class Client {public static void main(String[] args) {Product product = SimpleFactory.createProduct("A");product.doSomething();} }
-
工厂方法模式(Factory Method): 也叫做多态工厂方法,它通过定义一个抽象工厂类,允许子类去决定实例化哪一个具体产品。每个具体工厂类负责创建一个具体的产品。工厂方法模式使得扩展产品种类变得更加容易,符合 开闭原则。
优点:
- 每个工厂只负责创建一个具体的产品,符合单一职责原则。
- 增加新产品时,只需增加新的具体产品类和具体工厂类,而无需修改现有代码。
缺点:
- 需要为每个产品创建一个工厂类,增加了类的数量和复杂度。
示例代码:
// 抽象产品 public interface Product {void doSomething(); }// 具体产品A public class ProductA implements Product {@Overridepublic void doSomething() {System.out.println("Product A is doing something.");} }// 具体产品B public class ProductB implements Product {@Overridepublic void doSomething() {System.out.println("Product B is doing something.");} }// 抽象工厂 public abstract class Creator {public abstract Product factoryMethod(); }// 具体工厂A public class ConcreteCreatorA extends Creator {@Overridepublic Product factoryMethod() {return new ProductA();} }// 具体工厂B public class ConcreteCreatorB extends Creator {@Overridepublic Product factoryMethod() {return new ProductB();} }// 客户端代码 public class Client {public static void main(String[] args) {Creator creator = new ConcreteCreatorA();Product product = creator.factoryMethod();product.doSomething();} }
-
抽象工厂模式(Abstract Factory): 抽象工厂模式在工厂方法模式的基础上进一步抽象,提供了一个接口,用于创建一系列相关或相互依赖的产品对象,而无需指定具体产品类。抽象工厂通常用于产品家族较大,且产品间有一定关联性的场景。
优点:
- 可以创建一系列相关的产品对象,避免了将这些产品对象散布在各个地方。
- 增加新的产品族时,不需要修改现有代码,符合开闭原则。
缺点:
- 代码结构复杂,尤其是在产品家族较多时,增加了工厂类的复杂度。
- 每新增一个产品族,就必须新增一个具体工厂类。
示例代码:
// 抽象产品A public interface ProductA {void doSomethingA(); }// 具体产品A1 public class ProductA1 implements ProductA {@Overridepublic void doSomethingA() {System.out.println("Product A1 is doing something.");} }// 具体产品A2 public class ProductA2 implements ProductA {@Overridepublic void doSomethingA() {System.out.println("Product A2 is doing something.");} }// 抽象产品B public interface ProductB {void doSomethingB(); }// 具体产品B1 public class ProductB1 implements ProductB {@Overridepublic void doSomethingB() {System.out.println("Product B1 is doing something.");} }// 具体产品B2 public class ProductB2 implements ProductB {@Overridepublic void doSomethingB() {System.out.println("Product B2 is doing something.");} }// 抽象工厂 public interface AbstractFactory {ProductA createProductA();ProductB createProductB(); }// 具体工厂1 public class ConcreteFactory1 implements AbstractFactory {@Overridepublic ProductA createProductA() {return new ProductA1();}@Overridepublic ProductB createProductB() {return new ProductB1();} }// 具体工厂2 public class ConcreteFactory2 implements AbstractFactory {@Overridepublic ProductA createProductA() {return new ProductA2();}@Overridepublic ProductB createProductB() {return new ProductB2();} }// 客户端代码 public class Client {public static void main(String[] args) {AbstractFactory factory = new ConcreteFactory1();ProductA productA = factory.createProductA();productA.doSomethingA();ProductB productB = factory.createProductB();productB.doSomethingB();} }
3. 工厂模式+配置文件
在实际的系统设计中,工厂模式与配置文件的结合使用,能够提高系统的灵活性与可扩展性,尤其是在需要根据外部配置动态创建不同对象的场景中。这种设计方式能够使得代码更加灵活、易于维护和扩展。
工厂模式 + 配置文件的实现方式
假设我们需要根据配置来决定使用哪种数据库连接。可以使用工厂模式来封装数据库连接的创建逻辑,并通过配置类来读取外部的数据库类型配置,从而动态创建不同的数据库连接对象。
示例代码:
- 定义产品接口(DatabaseConnection)
public interface DatabaseConnection {void connect();
}
- 定义具体产品(MySQLConnection, PostgreSQLConnection)
public class MySQLConnection implements DatabaseConnection{@Overridepublic void connect() {System.out.println("正在连接MySQL...");}
}
public class PostgreSQLConnection implements DatabaseConnection{@Overridepublic void connect() {System.out.println("PostqreSQL正在连接中...");}
}
- config.properties文件
MySQL=com.study.factoryPattern.factoryAndConfigurationFile.MySQLConnection
PostgreSQL=com.study.factoryPattern.factoryAndConfigurationFile.PostgreSQLConnection
- 工厂类(DatabaseConnectionFactory)
public class Factory {private static Map<String,DatabaseConnection> dataBaseConnections = new HashMap<>();static {//导入配置文件,并创建单例,储存在map中Properties properties = new Properties();InputStream resourceAsStream = Factory.class.getClassLoader().getResourceAsStream("config.properties");try {properties.load(resourceAsStream);Set<Object> keys = properties.keySet();for (Object key : keys) {String className = properties.getProperty((String) key);Class clazz = Class.forName(className);DatabaseConnection instance = (DatabaseConnection) clazz.newInstance();dataBaseConnections.put((String) key, instance);}} catch (Exception e) {throw new RuntimeException(e);}}public static DatabaseConnection createConnection(String name){return dataBaseConnections.get(name);}
}
- 客户端代码
public class Client {public static void main(String[] args) {// DatabaseConnection mySQL = Factory.createConnection("MySQL");DatabaseConnection mySQL = Factory.createConnection("PostgreSQL");mySQL.connect();}
}