01. 工厂模式(Factory Pattern)
分类 : 创建型模式
热门度 : ★★★★★
难度: ★★☆☆☆
📖 概念
工厂模式是一种创建型设计模式,它提供了一种创建对象的最佳方式,而不必暴露创建逻辑给客户端。通过使用一个共同的接口来指向新创建的对象,将对象的实例化延迟到子类或工厂类中。
工厂模式包含三种形式:简单工厂 、工厂方法 和抽象工厂(抽象工厂单独作为模式02讲解)。
🎯 意图
定义一个创建对象的接口,让子类决定实例化哪一个类。工厂方法使一个类的实例化延迟到其子类,从而实现创建者与具体产品之间的解耦。
🔑 关键角色
| 角色 | 说明 |
|---|---|
| 抽象产品(Product) | 定义产品对象的通用接口,所有具体产品都实现此接口 |
| 具体产品(Concrete Product) | 实现抽象产品接口的具体类 |
| 工厂(Factory) | 负责创建具体产品实例的类或方法 |
| 客户端(Client) | 使用工厂来获取产品实例,不直接实例化具体产品 |
⚠️ 注意事项
- 简单工厂违反开闭原则,每次新增产品都需要修改工厂类
- 工厂方法模式通过继承来创建对象,抽象工厂通过组合来创建对象族
- 避免工厂类过于复杂,如果产品类型过多,考虑使用注册表或反射机制
- 工厂模式会增加系统中类的数量,需要权衡复杂度
🔄 实现流程
客户端 → 调用工厂方法并传入参数
→ 工厂根据参数判断应创建哪个具体产品
→ 实例化具体产品对象
→ 返回抽象产品类型给客户端
→ 客户端通过统一接口使用产品
💡 常见使用场景
场景1: 日志系统(Logger System)
根据配置创建不同类型的日志记录器(文件日志、数据库日志、控制台日志),客户端无需关心具体实现。
csharp
using System;
// 抽象产品
public interface ILogger
{
void Log(string message);
}
// 具体产品 - 文件日志
public class FileLogger : ILogger
{
public void Log(string message)
{
Console.WriteLine($"[FILE] {DateTime.Now:yyyy-MM-dd HH:mm:ss} - {message}");
}
}
// 具体产品 - 数据库日志
public class DatabaseLogger : ILogger
{
public void Log(string message)
{
Console.WriteLine($"[DB] {DateTime.Now:yyyy-MM-dd HH:mm:ss} - {message}");
}
}
// 具体产品 - 控制台日志
public class ConsoleLogger : ILogger
{
public void Log(string message)
{
Console.WriteLine($"[CONSOLE] {DateTime.Now:yyyy-MM-dd HH:mm:ss} - {message}");
}
}
// 工厂
public static class LoggerFactory
{
public static ILogger CreateLogger(string type)
{
return type.ToLower() switch
{
"file" => new FileLogger(),
"database" or "db" => new DatabaseLogger(),
"console" => new ConsoleLogger(),
_ => throw new ArgumentException($"Unknown logger type: {type}")
};
}
}
// 客户端调用
public class Program
{
public static void Main()
{
ILogger logger = LoggerFactory.CreateLogger("file");
logger.Log("Application started");
}
}
场景2: 数据库连接工厂(Database Connection Factory)
根据不同的数据库类型创建对应的连接对象,统一管理数据库连接的创建。
csharp
using System;
// 抽象产品(避免与 System.Data.IDbConnection 冲突,加自定义前缀)
public interface IMyDbConnection
{
void Open();
void Close();
string ConnectionString { get; }
}
// 具体产品 - SQL Server
public class SqlServerConnection : IMyDbConnection
{
public string ConnectionString { get; private set; }
public SqlServerConnection(string connectionString)
{
ConnectionString = connectionString;
}
public void Open() => Console.WriteLine("SQL Server connection opened.");
public void Close() => Console.WriteLine("SQL Server connection closed.");
}
// 具体产品 - MySQL
public class MySqlConnection : IMyDbConnection
{
public string ConnectionString { get; private set; }
public MySqlConnection(string connectionString)
{
ConnectionString = connectionString;
}
public void Open() => Console.WriteLine("MySQL connection opened.");
public void Close() => Console.WriteLine("MySQL connection closed.");
}
// 具体产品 - PostgreSQL
public class PostgreSqlConnection : IMyDbConnection
{
public string ConnectionString { get; private set; }
public PostgreSqlConnection(string connectionString)
{
ConnectionString = connectionString;
}
public void Open() => Console.WriteLine("PostgreSQL connection opened.");
public void Close() => Console.WriteLine("PostgreSQL connection closed.");
}
// 工厂
public static class DbConnectionFactory
{
public static IMyDbConnection Create(string dbType, string connectionString)
{
return dbType.ToLower() switch
{
"sqlserver" => new SqlServerConnection(connectionString),
"mysql" => new MySqlConnection(connectionString),
"postgresql" => new PostgreSqlConnection(connectionString),
_ => throw new ArgumentException($"Unsupported database type: {dbType}")
};
}
}
// 客户端调用
public class Program
{
public static void Main()
{
var conn = DbConnectionFactory.Create("mysql", "Server=localhost;Database=test");
conn.Open();
// 执行数据库操作...
conn.Close();
}
}
场景3: 支付处理工厂(Payment Processing Factory)
根据不同支付方式创建对应的支付处理器,实现支付系统的可扩展性。
csharp
using System;
// 抽象产品
public interface IPaymentProcessor
{
bool ProcessPayment(decimal amount);
string GetPaymentMethod();
}
// 具体产品 - 信用卡支付
public class CreditCardPayment : IPaymentProcessor
{
private string _cardNumber;
public CreditCardPayment(string cardNumber) { _cardNumber = cardNumber; }
public bool ProcessPayment(decimal amount)
{
Console.WriteLine($"Processing credit card payment of ¥{amount:F2} with card {_cardNumber[^4..]}");
return true;
}
public string GetPaymentMethod() => "Credit Card";
}
// 具体产品 - 微信支付
public class WeChatPayment : IPaymentProcessor
{
private string _openId;
public WeChatPayment(string openId) { _openId = openId; }
public bool ProcessPayment(decimal amount)
{
Console.WriteLine($"Processing WeChat payment of ¥{amount:F2} for user {_openId}");
return true;
}
public string GetPaymentMethod() => "WeChat Pay";
}
// 具体产品 - 支付宝
public class AlipayPayment : IPaymentProcessor
{
private string _accountId;
public AlipayPayment(string accountId) { _accountId = accountId; }
public bool ProcessPayment(decimal amount)
{
Console.WriteLine($"Processing Alipay payment of ¥{amount:F2} for account {_accountId}");
return true;
}
public string GetPaymentMethod() => "Alipay";
}
// 工厂
public static class PaymentProcessorFactory
{
public static IPaymentProcessor Create(string paymentMethod, string accountInfo)
{
return paymentMethod.ToLower() switch
{
"creditcard" => new CreditCardPayment(accountInfo),
"wechat" => new WeChatPayment(accountInfo),
"alipay" => new AlipayPayment(accountInfo),
_ => throw new ArgumentException($"Unsupported payment method: {paymentMethod}")
};
}
}
// 客户端调用
public class Program
{
public static void Main()
{
var payment = PaymentProcessorFactory.Create("wechat", "user_12345");
payment.ProcessPayment(99.99m);
Console.WriteLine($"Paid via {payment.GetPaymentMethod()}");
}
}
✅ 优点
- 解耦:客户端不需要知道具体产品类名,只需知道参数即可
- 扩展性:新增产品时,工厂方法模式只需增加新的工厂子类
- 复用性:工厂方法可以被多次调用,避免重复的创建逻辑
- 符合单一职责原则:将对象的创建逻辑集中管理
❌ 缺点
- 类数量增加:每增加一个产品就需要增加一个具体工厂类
- 简单工厂违反开闭原则:修改工厂逻辑需要修改原有代码
- 增加了系统的抽象性和理解难度
📊 与其他模式对比
| 模式 | 区别 |
|---|---|
| 抽象工厂 | 创建一系列相关对象族,工厂模式创建单一产品 |
| 建造者模式 | 关注分步构建复杂对象,工厂关注一步创建 |
| 原型模式 | 通过克隆创建对象,工厂通过new创建对象 |
| 单例模式 | 保证唯一实例,工厂可以创建多个不同实例 |