架构师总结:掌握这7种设计模式,轻松应对99%Java 开发场景-工厂
引言:为什么是这7种模式?
在浩瀚的23种GoF设计模式中,这7种被精选出来,是因为它们覆盖了面向对象设计的核心原则(如SOLID),并解决了Java企业级开发中最常见、最棘手的几类问题:
- 对象创建与管理:如何优雅、灵活地创建对象?(单例、工厂、建造者)
- 接口兼容与适配:如何让不兼容的接口协同工作?(适配器)
- 行为变化与扩展:如何封装算法,使其独立于客户而变化?(策略)
- 对象间通信:如何建立对象间的松耦合通知机制?(观察者)
- 请求处理与分发:如何将请求的发送者和接收者解耦?(责任链)
掌握它们,就如同一位武士精通了七种核心剑技,足以应对绝大多数战斗场景。下面,我们开始逐一剖析。
模式二:工厂模式 - 对象创建的“流水线”
工厂模式是一个大家族,主要包括:简单工厂、工厂方法和抽象工厂。它们的目标都是解耦对象的创建和使用。
2.1 简单工厂(Simple Factory)
内容精讲:它不是一个标准的设计模式,更像是一种编程习惯。它提供一个创建对象的静态方法,根据传入的参数不同,返回不同的产品实例。
代码实现:
假设我们有一个日志记录器(Logger)系统,可以记录到文件或数据库。
java
// 1. 产品接口
public interface Logger {
void log(String message);
}
// 2. 具体产品
public class FileLogger implements Logger {
@Override
public void log(String message) {
System.out.println("Logging to FILE: " + message);
}
}
public class DatabaseLogger implements Logger {
@Override
public void log(String message) {
System.out.println("Logging to DATABASE: " + message);
}
}
// 3. 简单工厂
public class LoggerFactory {
// 通常使用静态方法,因此也叫静态工厂
public static Logger getLogger(String type) {
if ("file".equalsIgnoreCase(type)) {
return new FileLogger();
} else if ("database".equalsIgnoreCase(type)) {
return new DatabaseLogger();
} else {
throw new IllegalArgumentException("Invalid logger type: " + type);
}
}
}
// 4. 客户端使用
public class Client {
public static void main(String[] args) {
Logger logger = LoggerFactory.getLogger("file");
logger.log("This is a test message.");
}
}优缺点:
- 优点:客户端无需知道具体产品的类名,只需要知道参数即可。
- 缺点:工厂职责过重,一旦需要增加新产品(如ConsoleLogger),就必须修改LoggerFactory的代码,违反了开闭原则。
2.2 工厂方法模式(Factory Method)
内容精讲:定义一个用于创建对象的接口(工厂接口),但让子类决定实例化哪一个产品类。工厂方法使一个类的实例化延迟到其子类。
设计原则:依赖倒置原则(DIP)——客户端代码应该依赖抽象(工厂接口和产品接口),而不是具体实现。
代码实现:
我们将简单工厂演进为工厂方法。
java
// 1. 产品接口 (不变)
public interface Logger {
void log(String message);
}
// 2. 具体产品 (不变)
public class FileLogger implements Logger { ... }
public class DatabaseLogger implements Logger { ... }
// 3. 工厂接口
public interface LoggerFactory {
Logger createLogger();
}
// 4. 具体工厂
public class FileLoggerFactory implements LoggerFactory {
@Override
public Logger createLogger() {
// 可能包含复杂的初始化逻辑,如读取配置、创建文件等
return new FileLogger();
}
}
public class DatabaseLoggerFactory implements LoggerFactory {
@Override
public Logger createLogger() {
// 可能包含数据库连接等逻辑
return new DatabaseLogger();
}
}
// 5. 客户端使用
public class Client {
public static void main(String[] args) {
// 客户端依赖的是工厂接口和产品接口,与具体实现解耦
LoggerFactory factory = new FileLoggerFactory(); // 可通过配置读取来决定用哪个工厂
Logger logger = factory.createLogger();
logger.log("This is a test message.");
}
}优缺点:
- 优点:完全符合开闭原则。要新增一个ConsoleLogger,只需要新增ConsoleLogger和ConsoleLoggerFactory,无需修改任何现有代码。
- 缺点:类的数量会增多,系统变得更抽象和复杂。
2.3 抽象工厂模式(Abstract Factory)
内容精讲:提供一个创建一系列相关或相互依赖对象的接口,而无需指定它们具体的类。它处理的是“产品族”的概念。
何时使用:系统需要独立于其产品的创建、组合和表示时;系统需要配置多个产品系列中的一个时。
代码实现:
假设我们的日志系统需要配套的连接器(Connector)来连接文件系统或数据库。
java
// 1. 抽象产品族A
public interface Logger {
void log(String message);
}
// 2. 抽象产品族B
public interface Connector {
void connect();
void disconnect();
}
// 3. 具体产品族1: File系列
public class FileLogger implements Logger { ... }
public class FileConnector implements Connector {
@Override
public void connect() { System.out.println("Connected to File System."); }
@Override
public void disconnect() { System.out.println("Disconnected from File System."); }
}
// 4. 具体产品族2: Database系列
public class DatabaseLogger implements Logger { ... }
public class DatabaseConnector implements Connector {
@Override
public void connect() { System.out.println("Connected to Database."); }
@Override
public void disconnect() { System.out.println("Disconnected from Database."); }
}
// 5. 抽象工厂
public interface LoggerFactory {
Logger createLogger();
Connector createConnector(); // 创建配套的连接器
}
// 6. 具体工厂
public class FileLoggerFactory implements LoggerFactory {
@Override
public Logger createLogger() {
return new FileLogger();
}
@Override
public Connector createConnector() {
return new FileConnector();
}
}
public class DatabaseLoggerFactory implements LoggerFactory {
@Override
public Logger createLogger() {
return new DatabaseLogger();
}
@Override
public Connector createConnector() {
return new DatabaseConnector();
}
}
// 7. 客户端使用
public class Client {
public static void main(String[] args) {
LoggerFactory factory = new DatabaseLoggerFactory(); // 一整套Database产品族
Connector connector = factory.createConnector();
connector.connect();
Logger logger = factory.createLogger();
logger.log("Log after connection.");
connector.disconnect();
}
}优缺点:
- 优点:保证客户端始终只使用同一个产品族中的对象;易于交换产品系列(只需更换具体工厂);符合开闭原则(新增产品族容易)和单一职责原则。
- 缺点:难以支持新增产品等级结构(即新增一个产品类型,比如新增一个Monitor产品)。如果需要在抽象工厂中增加一个createMonitor()方法,那么所有具体工厂都需要修改,违反了开闭原则。
2.4 工厂模式总结
- 简单工厂:静态方法,根据参数创建对象。违反开闭原则,适用于对象种类较少且固定的场景。
- 工厂方法:针对一个产品等级结构。将创建逻辑推迟到子类,完全符合开闭原则。
- 抽象工厂:针对多个产品等级结构(产品族)。强调一系列相关产品的创建,开闭原则倾向于“对扩展开放(新增产品族),对修改关闭”,但扩展新产品类型困难。