定义
工厂方法模式是一种创建型设计模式,它定义了一个创建对象的接口,但让子类决定实例化哪一个类。工厂方法模式将对象的创建延迟到子类。
适用场景
- 产品种类较多:当产品种类较多,且创建逻辑较复杂时,使用工厂方法模式可以更好地管理和扩展。
- 创建逻辑需要变化:当对象的创建逻辑需要根据不同的情况变化时,可以使用工厂方法模式。
- 支持多态:当客户端需要根据不同的情况创建不同类型的对象时,可以使用工厂方法模式。
正确用法
假设我们有一个简单的场景,需要根据不同的类型创建不同的产品对象,但这次我们使用工厂方法模式来实现。
// 产品接口
public interface IProduct
{
void Show();
}
// 具体产品A
public class ProductA : IProduct
{
public void Show() => Console.WriteLine("Product A");
}
// 具体产品B
public class ProductB : IProduct
{
public void Show() => Console.WriteLine("Product B");
}
// 创建者接口
public interface ICreator
{
IProduct FactoryMethod();
}
// 具体创建者A
public class ConcreteCreatorA : ICreator
{
public IProduct FactoryMethod() => new ProductA();
}
// 具体创建者B
public class ConcreteCreatorB : ICreator
{
public IProduct FactoryMethod() => new ProductB();
}
// 客户端代码
class Program
{
static void Main(string[] args)
{
ICreator creatorA = new ConcreteCreatorA();
IProduct productA = creatorA.FactoryMethod();
productA.Show(); // 输出: Product A
ICreator creatorB = new ConcreteCreatorB();
IProduct productB = creatorB.FactoryMethod();
productB.Show(); // 输出: Product B
}
}
然而在实际开发过程中,工厂方法模式常用于处理需要根据不同条件创建不同类型对象的场景。以下是一些实际开发中的例子,展示了如何使用工厂方法模式来解决问题。
类图:
解释
- 产品接口 (
IProduct
):定义了产品的公共方法 Show。 - 具体产品 (
ProductA
和ProductB
):实现了IProduct
接口,提供了具体的 Show 方法实现。 - 创建者接口 (
ICreator
):定义了工厂方法FactoryMethod
,用于创建产品对象。 - 具体创建者 (
ConcreteCreatorA
和ConcreteCreatorB
):实现了ICreator
接口,具体实现了FactoryMethod
方法,分别返回ProductA
和ProductB
对象。 - 客户端代码 (
Program
):创建了具体的创建者对象ConcreteCreatorA
和ConcreteCreatorB
,并通过它们的FactoryMethod
方法创建具体的产品对象,并调用 Show 方法显示产品信息。
1. 数据库连接管理
假设我们需要根据配置文件中的数据库类型(如 MySQL、SQL Server)来创建相应的数据库连接对象。
// 数据库连接接口
public interface IDatabaseConnection
{
void Connect();
void Disconnect();
}
// MySQL数据库连接
public class MySqlConnection : IDatabaseConnection
{
public void Connect() => Console.WriteLine("Connecting to MySQL database...");
public void Disconnect() => Console.WriteLine("Disconnecting from MySQL database...");
}
// SQL Server数据库连接
public class SqlServerConnection : IDatabaseConnection
{
public void Connect() => Console.WriteLine("Connecting to SQL Server database...");
public void Disconnect() => Console.WriteLine("Disconnecting from SQL Server database...");
}
// 创建者接口
public interface IDatabaseConnectionFactory
{
IDatabaseConnection CreateConnection();
}
// MySQL连接工厂
public class MySqlConnectionFactory : IDatabaseConnectionFactory
{
public IDatabaseConnection CreateConnection() => new MySqlConnection();
}
// SQL Server连接工厂
public class SqlServerConnectionFactory : IDatabaseConnectionFactory
{
public IDatabaseConnection CreateConnection() => new SqlServerConnection();
}
// 配置类
public class Configuration
{
public string DatabaseType { get; set; }
}
// 客户端代码
class Program
{
static void Main(string[] args)
{
Configuration config = new Configuration { DatabaseType = "MySQL" };
IDatabaseConnectionFactory factory;
if (config.DatabaseType == "MySQL")
{
factory = new MySqlConnectionFactory();
}
else if (config.DatabaseType == "SQLServer")
{
factory = new SqlServerConnectionFactory();
}
else
{
throw new ArgumentException("Unsupported database type");
}
IDatabaseConnection connection = factory.CreateConnection();
connection.Connect();
connection.Disconnect();
}
}
2. 日志记录
假设我们需要根据配置文件中的日志级别(如 DEBUG、INFO、ERROR)来创建相应的日志记录器。
// 日志记录接口
public interface ILogger
{
void Log(string message);
}
// DEBUG日志记录器
public class DebugLogger : ILogger
{
public void Log(string message) => Console.WriteLine($"DEBUG: {message}");
}
// INFO日志记录器
public class InfoLogger : ILogger
{
public void Log(string message) => Console.WriteLine($"INFO: {message}");
}
// ERROR日志记录器
public class ErrorLogger : ILogger
{
public void Log(string message) => Console.WriteLine($"ERROR: {message}");
}
// 创建者接口
public interface ILoggerFactory
{
ILogger CreateLogger();
}
// DEBUG日志记录器工厂
public class DebugLoggerFactory : ILoggerFactory
{
public ILogger CreateLogger() => new DebugLogger();
}
// INFO日志记录器工厂
public class InfoLoggerFactory : ILoggerFactory
{
public ILogger CreateLogger() => new InfoLogger();
}
// ERROR日志记录器工厂
public class ErrorLoggerFactory : ILoggerFactory
{
public ILogger CreateLogger() => new ErrorLogger();
}
// 配置类
public class Configuration
{
public string LogLevel { get; set; }
}
// 客户端代码
class Program
{
static void Main(string[] args)
{
Configuration config = new Configuration { LogLevel = "DEBUG" };
ILoggerFactory factory;
if (config.LogLevel == "DEBUG")
{
factory = new DebugLoggerFactory();
}
else if (config.LogLevel == "INFO")
{
factory = new InfoLoggerFactory();
}
else if (config.LogLevel == "ERROR")
{
factory = new ErrorLoggerFactory();
}
else
{
throw new ArgumentException("Unsupported log level");
}
ILogger logger = factory.CreateLogger();
logger.Log("This is a log message.");
}
}
3. 用户界面组件创建
假设我们需要根据用户的选择(如 Windows、MacOS)来创建相应的用户界面组件。
// 用户界面组件接口
public interface IUIComponent
{
void Render();
}
// Windows用户界面组件
public class WindowsUIComponent : IUIComponent
{
public void Render() => Console.WriteLine("Rendering Windows UI component...");
}
// MacOS用户界面组件
public class MacOSUIComponent : IUIComponent
{
public void Render() => Console.WriteLine("Rendering MacOS UI component...");
}
// 创建者接口
public interface IUIComponentFactory
{
IUIComponent CreateComponent();
}
// Windows用户界面组件工厂
public class WindowsUIComponentFactory : IUIComponentFactory
{
public IUIComponent CreateComponent() => new WindowsUIComponent();
}
// MacOS用户界面组件工厂
public class MacOSUIComponentFactory : IUIComponentFactory
{
public IUIComponent CreateComponent() => new MacOSUIComponent();
}
// 配置类
public class Configuration
{
public string OS { get; set; }
}
// 客户端代码
class Program
{
static void Main(string[] args)
{
Configuration config = new Configuration { OS = "Windows" };
IUIComponentFactory factory;
if (config.OS == "Windows")
{
factory = new WindowsUIComponentFactory();
}
else if (config.OS == "MacOS")
{
factory = new MacOSUIComponentFactory();
}
else
{
throw new ArgumentException("Unsupported operating system");
}
IUIComponent component = factory.CreateComponent();
component.Render();
}
}
总结一下:
- 解耦对象的创建和使用:将对象的创建和使用分离,客户端不需要知道具体的产品类,只需要知道创建者的接口。
- 支持多态:客户端可以通过创建者的接口来创建不同类型的对象,支持多态性。
- 易于扩展:增加新的产品时,只需要添加新的具体创建者类,不需要修改现有的代码。
优点
- 符合开闭原则:增加新的产品时,只需要添加新的具体创建者类,不需要修改现有的代码,符合开闭原则。
- 灵活性高:每个具体创建者类都可以独立地创建不同的产品,灵活性高。
- 支持多态:客户端可以通过创建者的接口来创建不同类型的对象,支持多态性。
缺点
- 类的数量增加:每增加一个新的产品,就需要增加一个新的具体创建者类,类的数量会增加。
- 代码复杂度增加:相对于简单工厂模式,工厂方法模式的代码结构更复杂,需要更多的类和接口。
- 客户端需要知道具体创建者:客户端需要知道具体创建者的类,以便创建所需的产品。