什么时候使用工厂模式❓

当创建逻辑比较复杂,是一个大工程的时候,就可以去考虑使用工厂模式,封装对象的创建过程,将对象的创建和使用分离,比如以下两张情况

  • 类似规则配置解析的例子,代码中存在if-else 分支判断,动态的根据 不同的类型创建不同的对象。针对这种情况,我们就考虑使用工厂模式,将这一大坨if - else 创建对象的代码抽离出来,放到工厂类中

  • 还有一种情况,尽管不需要根据不同的类型创建不同的对象,但是,单个对象本身的创建过程比较复杂,比如 要组合其他的类对象,做各种初始化的操作,在这种情况下,我们也可以考虑使用工厂模式,将对象的创建过程封装到工厂类中。

对于第一种情况,当每个对象的创建逻辑都比较简单的时候,推荐使用简单工厂模式,将对个对象的创建逻辑放到一个工厂类中,当美国个对象的创建逻辑都比较复杂的时候,为了避免设计一个过于庞大的简单工厂类,就推荐使用工厂方法模式,将创建逻辑拆分的更细,美国个对象的创建逻辑独立到各自的工厂类中。同理,对于第二种情况,因为单个对象本身的创建逻辑就比较复杂,所以,建议使用工厂方法模式

除了刚刚提到的几种情况之外,如果创建对象的逻辑并复杂,那我们就直接通过NEW 来创建对象就可以了 ,不需要使用工厂模式!

现在上升一个思维模式来看工厂模式,他的作用无外乎下面几个。这也是判断要不要使用工厂模式的最本质的参考标准。

  • 封装变化:创建逻辑有可能变化,封装成工厂类之后,创建逻辑的变更对到用着更透明。

  • 代码复用:创建代码抽离到独立的工厂类之后可以复用

  • 隔离复杂性:封装复杂的创建逻辑,调用者无需了解如何创建对象。

  • 控制复杂度:将创建代码抽离出来,让原本的函数或者类更加职责单一,代码更简洁。

代码示例

简单工厂

// 示例:图形绘制工具​

// 产品接口
public interface IShape
{
    void Draw();
}

// 具体产品
public class Circle : IShape
{
    public void Draw() => Console.WriteLine("绘制圆形");
}

public class Rectangle : IShape
{
    public void Draw() => Console.WriteLine("绘制矩形");
}

// 简单工厂
public class ShapeFactory
{
    public IShape CreateShape(string shapeType)
    {
        switch (shapeType.ToLower())
        {
            case "circle":
                return new Circle();
            case "rectangle":
                return new Rectangle();
            default:
                throw new ArgumentException("不支持的图形类型");
        }
    }
}

// 使用
var factory = new ShapeFactory();
IShape circle = factory.CreateShape("circle");
circle.Draw(); // 输出: 绘制圆形

特点​​

  • 工厂类集中了所有产品的创建逻辑。

  • 违反 ​​开闭原则​​(新增产品需修改工厂类代码)。

工厂方法(Factory Method)​

// 示例:日志记录器​

// 产品接口
public interface ILogger
{
    void Log(string message);
}

// 具体产品
public class FileLogger : ILogger
{
    public void Log(string message) => Console.WriteLine($"文件日志: {message}");
}

public class DatabaseLogger : ILogger
{
    public void Log(string message) => Console.WriteLine($"数据库日志: {message}");
}

// 工厂接口
public interface ILoggerFactory
{
    ILogger CreateLogger();
}

// 具体工厂
public class FileLoggerFactory : ILoggerFactory
{
    public ILogger CreateLogger() => new FileLogger();
}

public class DatabaseLoggerFactory : ILoggerFactory
{
    public ILogger CreateLogger() => new DatabaseLogger();
}

// 使用
ILoggerFactory factory = new FileLoggerFactory();
ILogger logger = factory.CreateLogger();
logger.Log("测试消息"); // 输出: 文件日志: 测试消息

特点​​

  • 符合 ​​开闭原则​​(新增产品只需添加新工厂类)。

  • 每个工厂类只负责一种产品,职责单一。

抽象工厂(Abstract Factory)​

​核心思想​​:提供一个接口,用于创建 ​​相关或依赖的一组对象​​(产品族)。
​适用场景​​:需要创建多个关联产品,且产品族可能变化。要创建多个关联产品,且产品族可能变化。

// 产品接口
public interface IButton
{
    void Render();
}

public interface ITextBox
{
    void Display();
}

// 具体产品 - 浅色主题
public class LightButton : IButton
{
    public void Render() => Console.WriteLine("浅色按钮");
}

public class LightTextBox : ITextBox
{
    public void Display() => Console.WriteLine("浅色文本框");
}

// 具体产品 - 深色主题
public class DarkButton : IButton
{
    public void Render() => Console.WriteLine("深色按钮");
}

public class DarkTextBox : ITextBox
{
    public void Display() => Console.WriteLine("深色文本框");
}

// 抽象工厂接口
public interface IThemeFactory
{
    IButton CreateButton();
    ITextBox CreateTextBox();
}

// 具体工厂 - 浅色主题工厂
public class LightThemeFactory : IThemeFactory
{
    public IButton CreateButton() => new LightButton();
    public ITextBox CreateTextBox() => new LightTextBox();
}

// 具体工厂 - 深色主题工厂
public class DarkThemeFactory : IThemeFactory
{
    public IButton CreateButton() => new DarkButton();
    public ITextBox CreateTextBox() => new DarkTextBox();
}

// 使用
IThemeFactory factory = new DarkThemeFactory();
IButton button = factory.CreateButton();
ITextBox textBox = factory.CreateTextBox();

button.Render();    // 输出: 深色按钮
textBox.Display();  // 输出: 深色文本框