工厂模式
基础概念
什么是工厂模式?
答案: 工厂模式(Factory Pattern)是一种创建型设计模式,提供了一种创建对象的最佳方式。在工厂模式中,我们在创建对象时不会对客户端暴露创建逻辑,而是通过使用一个共同的接口来指向新创建的对象。
使用场景:
- 对象创建逻辑复杂
- 需要根据不同条件创建不同对象
- 解耦对象的创建和使用
优点:
- 解耦,将对象的创建和使用分离
- 符合开闭原则,扩展性好
- 符合单一职责原则
缺点:
- 增加系统复杂度
- 增加类的数量
简单工厂模式
简单工厂的实现?
答案:
java
// 产品接口
public interface Product {
void use();
}
// 具体产品A
public class ProductA implements Product {
@Override
public void use() {
System.out.println("使用产品A");
}
}
// 具体产品B
public class ProductB implements Product {
@Override
public void use() {
System.out.println("使用产品B");
}
}
// 简单工厂
public class SimpleFactory {
public static Product createProduct(String type) {
switch (type) {
case "A":
return new ProductA();
case "B":
return new ProductB();
default:
throw new IllegalArgumentException("未知产品类型: " + type);
}
}
}
// 使用
public class Client {
public static void main(String[] args) {
Product productA = SimpleFactory.createProduct("A");
productA.use();
Product productB = SimpleFactory.createProduct("B");
productB.use();
}
}优点:
- 实现简单
- 客户端无需知道具体产品类名
缺点:
- 违反开闭原则,新增产品需要修改工厂类
- 工厂类职责过重
简单工厂的实际应用?
答案:
示例1:支付工厂
java
// 支付接口
public interface Payment {
void pay(BigDecimal amount);
}
// 支付宝支付
public class AlipayPayment implements Payment {
@Override
public void pay(BigDecimal amount) {
System.out.println("支付宝支付: " + amount);
}
}
// 微信支付
public class WechatPayment implements Payment {
@Override
public void pay(BigDecimal amount) {
System.out.println("微信支付: " + amount);
}
}
// 银行卡支付
public class BankCardPayment implements Payment {
@Override
public void pay(BigDecimal amount) {
System.out.println("银行卡支付: " + amount);
}
}
// 支付工厂
public class PaymentFactory {
public static Payment createPayment(String type) {
switch (type) {
case "alipay":
return new AlipayPayment();
case "wechat":
return new WechatPayment();
case "bankcard":
return new BankCardPayment();
default:
throw new IllegalArgumentException("不支持的支付方式: " + type);
}
}
}
// 使用
Payment payment = PaymentFactory.createPayment("alipay");
payment.pay(new BigDecimal("100.00"));示例2:日志工厂
java
public interface Logger {
void log(String message);
}
public class FileLogger implements Logger {
@Override
public void log(String message) {
System.out.println("写入文件: " + message);
}
}
public class ConsoleLogger implements Logger {
@Override
public void log(String message) {
System.out.println("控制台输出: " + message);
}
}
public class DatabaseLogger implements Logger {
@Override
public void log(String message) {
System.out.println("写入数据库: " + message);
}
}
public class LoggerFactory {
public static Logger createLogger(String type) {
switch (type) {
case "file":
return new FileLogger();
case "console":
return new ConsoleLogger();
case "database":
return new DatabaseLogger();
default:
return new ConsoleLogger(); // 默认控制台
}
}
}工厂方法模式
工厂方法的实现?
答案:
java
// 产品接口
public interface Product {
void use();
}
// 具体产品A
public class ProductA implements Product {
@Override
public void use() {
System.out.println("使用产品A");
}
}
// 具体产品B
public class ProductB implements Product {
@Override
public void use() {
System.out.println("使用产品B");
}
}
// 工厂接口
public interface Factory {
Product createProduct();
}
// 具体工厂A
public class FactoryA implements Factory {
@Override
public Product createProduct() {
return new ProductA();
}
}
// 具体工厂B
public class FactoryB implements Factory {
@Override
public Product createProduct() {
return new ProductB();
}
}
// 使用
public class Client {
public static void main(String[] args) {
Factory factoryA = new FactoryA();
Product productA = factoryA.createProduct();
productA.use();
Factory factoryB = new FactoryB();
Product productB = factoryB.createProduct();
productB.use();
}
}优点:
- 符合开闭原则,新增产品只需新增工厂类
- 符合单一职责原则,每个工厂只负责创建一种产品
缺点:
- 类的数量增加
- 增加系统复杂度
工厂方法的实际应用?
答案:
示例1:数据库连接工厂
java
// 数据库连接接口
public interface Connection {
void connect();
void execute(String sql);
}
// MySQL连接
public class MySQLConnection implements Connection {
@Override
public void connect() {
System.out.println("连接MySQL数据库");
}
@Override
public void execute(String sql) {
System.out.println("MySQL执行: " + sql);
}
}
// Oracle连接
public class OracleConnection implements Connection {
@Override
public void connect() {
System.out.println("连接Oracle数据库");
}
@Override
public void execute(String sql) {
System.out.println("Oracle执行: " + sql);
}
}
// 连接工厂接口
public interface ConnectionFactory {
Connection createConnection();
}
// MySQL工厂
public class MySQLConnectionFactory implements ConnectionFactory {
@Override
public Connection createConnection() {
return new MySQLConnection();
}
}
// Oracle工厂
public class OracleConnectionFactory implements ConnectionFactory {
@Override
public Connection createConnection() {
return new OracleConnection();
}
}
// 使用
ConnectionFactory factory = new MySQLConnectionFactory();
Connection connection = factory.createConnection();
connection.connect();
connection.execute("SELECT * FROM users");示例2:消息发送工厂
java
// 消息接口
public interface Message {
void send(String content, String recipient);
}
// 邮件消息
public class EmailMessage implements Message {
@Override
public void send(String content, String recipient) {
System.out.println("发送邮件到 " + recipient + ": " + content);
}
}
// 短信消息
public class SmsMessage implements Message {
@Override
public void send(String content, String recipient) {
System.out.println("发送短信到 " + recipient + ": " + content);
}
}
// 微信消息
public class WechatMessage implements Message {
@Override
public void send(String content, String recipient) {
System.out.println("发送微信到 " + recipient + ": " + content);
}
}
// 消息工厂接口
public interface MessageFactory {
Message createMessage();
}
// 邮件工厂
public class EmailMessageFactory implements MessageFactory {
@Override
public Message createMessage() {
return new EmailMessage();
}
}
// 短信工厂
public class SmsMessageFactory implements MessageFactory {
@Override
public Message createMessage() {
return new SmsMessage();
}
}
// 微信工厂
public class WechatMessageFactory implements MessageFactory {
@Override
public Message createMessage() {
return new WechatMessage();
}
}优化:反射+配置
如何使用反射优化工厂?
答案:
java
// 配置文件 factory.properties
product.A=com.example.ProductA
product.B=com.example.ProductB
// 工厂类
public class ReflectionFactory {
private static Properties properties = new Properties();
static {
try {
properties.load(ReflectionFactory.class.getClassLoader()
.getResourceAsStream("factory.properties"));
} catch (IOException e) {
e.printStackTrace();
}
}
public static Product createProduct(String type) {
String className = properties.getProperty("product." + type);
if (className == null) {
throw new IllegalArgumentException("未知产品类型: " + type);
}
try {
Class<?> clazz = Class.forName(className);
return (Product) clazz.newInstance();
} catch (Exception e) {
throw new RuntimeException("创建产品失败", e);
}
}
}优点:
- 新增产品只需修改配置文件
- 无需修改代码
Spring中的工厂模式
BeanFactory?
答案:
Spring的BeanFactory就是工厂模式的典型应用。
java
// BeanFactory接口
public interface BeanFactory {
Object getBean(String name);
<T> T getBean(String name, Class<T> requiredType);
<T> T getBean(Class<T> requiredType);
}
// 使用
ApplicationContext context = new ClassPathXmlApplicationContext("beans.xml");
UserService userService = context.getBean(UserService.class);Spring工厂的特点:
- 支持单例和原型模式
- 支持依赖注入
- 支持AOP
- 支持生命周期管理
FactoryBean?
答案:
FactoryBean是Spring提供的工厂Bean接口。
java
public interface FactoryBean<T> {
T getObject() throws Exception; // 返回创建的对象
Class<?> getObjectType(); // 返回对象类型
boolean isSingleton(); // 是否单例
}
// 实现
@Component
public class UserFactoryBean implements FactoryBean<User> {
@Override
public User getObject() throws Exception {
User user = new User();
user.setName("张三");
user.setAge(20);
return user;
}
@Override
public Class<?> getObjectType() {
return User.class;
}
@Override
public boolean isSingleton() {
return true;
}
}
// 使用
@Autowired
private User user; // 注入的是getObject()返回的对象
@Autowired
private UserFactoryBean userFactoryBean; // 注入的是FactoryBean本身应用场景:
- 创建复杂对象
- 需要初始化配置的对象
- 代理对象
实际案例
文件解析器工厂
答案:
java
// 解析器接口
public interface FileParser {
void parse(String filePath);
}
// Excel解析器
public class ExcelParser implements FileParser {
@Override
public void parse(String filePath) {
System.out.println("解析Excel文件: " + filePath);
}
}
// CSV解析器
public class CsvParser implements FileParser {
@Override
public void parse(String filePath) {
System.out.println("解析CSV文件: " + filePath);
}
}
// JSON解析器
public class JsonParser implements FileParser {
@Override
public void parse(String filePath) {
System.out.println("解析JSON文件: " + filePath);
}
}
// 解析器工厂
public class FileParserFactory {
public static FileParser createParser(String fileName) {
String extension = fileName.substring(fileName.lastIndexOf(".") + 1);
switch (extension.toLowerCase()) {
case "xlsx":
case "xls":
return new ExcelParser();
case "csv":
return new CsvParser();
case "json":
return new JsonParser();
default:
throw new IllegalArgumentException("不支持的文件类型: " + extension);
}
}
}
// 使用
FileParser parser = FileParserFactory.createParser("data.xlsx");
parser.parse("data.xlsx");HTTP客户端工厂
答案:
java
// HTTP客户端接口
public interface HttpClient {
String get(String url);
String post(String url, String body);
}
// OkHttp客户端
public class OkHttpClient implements HttpClient {
@Override
public String get(String url) {
return "OkHttp GET: " + url;
}
@Override
public String post(String url, String body) {
return "OkHttp POST: " + url;
}
}
// Apache HttpClient
public class ApacheHttpClient implements HttpClient {
@Override
public String get(String url) {
return "Apache GET: " + url;
}
@Override
public String post(String url, String body) {
return "Apache POST: " + url;
}
}
// 工厂
public class HttpClientFactory {
private static final String CLIENT_TYPE = System.getProperty("http.client.type", "okhttp");
public static HttpClient createClient() {
switch (CLIENT_TYPE) {
case "okhttp":
return new OkHttpClient();
case "apache":
return new ApacheHttpClient();
default:
return new OkHttpClient();
}
}
}
// 使用
HttpClient client = HttpClientFactory.createClient();
String response = client.get("https://api.example.com/users");对比总结
| 模式 | 优点 | 缺点 | 适用场景 |
|---|---|---|---|
| 简单工厂 | 实现简单 | 违反开闭原则 | 产品种类少且固定 |
| 工厂方法 | 符合开闭原则 | 类数量增加 | 产品种类多且可扩展 |
| 抽象工厂 | 产品族扩展方便 | 产品等级扩展困难 | 多个产品族 |
练习题
- 简单工厂和工厂方法的区别?
- 如何选择使用哪种工厂模式?
- Spring的BeanFactory和FactoryBean有什么区别?
- 工厂模式如何体现开闭原则?
- 如何使用工厂模式实现策略模式?