c# 设计模式--抽象工厂模式 (Abstract Factory)

定义

抽象工厂模式是一种创建型设计模式,它提供了一种创建一系列相关或相互依赖对象的接口,而无需指定它们具体的类。抽象工厂模式强调的是对象族的创建,而不是单一对象的创建。

用例写法

假设我们有一个场景,需要根据不同的平台(如 Windows 和 MacOS)创建不同的用户界面组件(如按钮和文本框)。

csharp 复制代码
// 用户界面组件接口
public interface IButton
{
    void Render();
}

public interface ITextBox
{
    void Render();
}

// Windows用户界面组件
public class WindowsButton : IButton
{
    public void Render() => Console.WriteLine("Rendering Windows Button...");
}

public class WindowsTextBox : ITextBox
{
    public void Render() => Console.WriteLine("Rendering Windows TextBox...");
}

// MacOS用户界面组件
public class MacOSButton : IButton
{
    public void Render() => Console.WriteLine("Rendering MacOS Button...");
}

public class MacOSTextBox : ITextBox
{
    public void Render() => Console.WriteLine("Rendering MacOS TextBox...");
}

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

// Windows用户界面组件工厂
public class WindowsUIComponentFactory : IUIComponentFactory
{
    public IButton CreateButton() => new WindowsButton();
    public ITextBox CreateTextBox() => new WindowsTextBox();
}

// MacOS用户界面组件工厂
public class MacOSUIComponentFactory : IUIComponentFactory
{
    public IButton CreateButton() => new MacOSButton();
    public ITextBox CreateTextBox() => new MacOSTextBox();
}

// 配置类
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");
        }

        IButton button = factory.CreateButton();
        ITextBox textBox = factory.CreateTextBox();

        button.Render();
        textBox.Render();
    }
}

类图:

IButton +void Render() ITextBox +void Render() WindowsButton +void Render() WindowsTextBox +void Render() MacOSButton +void Render() MacOSTextBox +void Render() IUIComponentFactory +IButton CreateButton() +ITextBox CreateTextBox() WindowsUIComponentFactory +IButton CreateButton() +ITextBox CreateTextBox() MacOSUIComponentFactory +IButton CreateButton() +ITextBox CreateTextBox() Configuration -string OS +Configuration() Program +static void Main(string[] args)

解释

  1. 用户界面组件接口 (IButtonITextBox):定义了渲染按钮和文本框的方法。
  2. 具体用户界面组件 (WindowsButtonWindowsTextBoxMacOSButtonMacOSTextBox):实现了具体的按钮和文本框渲染逻辑。
  3. 抽象工厂接口 (IUIComponentFactory):定义了创建按钮和文本框的方法。
  4. 具体工厂类 (WindowsUIComponentFactoryMacOSUIComponentFactory):实现了具体的按钮和文本框创建逻辑。
  5. 配置类 (Configuration):用于存储操作系统的配置信息。
  6. 客户端代码 (Program):根据配置信息选择合适的工厂类,并使用工厂类创建具体的用户界面组件,然后调用其渲染方法。

用途

  1. 创建一系列相关对象:当需要创建一系列相关或相互依赖的对象时,使用抽象工厂模式可以确保这些对象的一致性。
  2. 解耦对象的创建和使用:客户端代码只需要依赖抽象工厂接口,不需要知道具体的产品类,从而降低了耦合度。
  3. 支持多平台:适用于需要在不同平台上创建不同版本的对象的场景。

优点

  1. 易于交换产品族:可以在运行时动态地切换不同的产品族,只需更换工厂对象即可。
  2. 支持开闭原则:增加新的产品族时,只需要添加新的具体工厂类,不需要修改现有的代码,符合开闭原则。
  3. 高度模块化:每个产品族的创建逻辑都封装在对应的工厂类中,模块化程度高。

缺点

  1. 系统复杂度增加:引入了更多的接口和类,系统结构变得更复杂。
  2. 增加代码量:每增加一个新的产品族,都需要增加相应的工厂类和产品类。
  3. 产品族扩展困难:如果需要增加新的产品类型,必须修改所有的工厂类,这违反了开闭原则。

适用场景

  1. 产品族多:当系统中有多个产品族,且每个产品族中的产品需要一起使用时。
  2. 多平台支持:需要在不同平台上创建不同版本的对象时。
  3. 对象创建逻辑复杂:对象的创建逻辑较为复杂,需要集中管理和控制时。

实际开发中的应用

1. 多平台用户界面框架

假设我们正在开发一个多平台用户界面框架,需要根据不同的操作系统创建不同的用户界面组件。

csharp 复制代码
// 用户界面组件接口
public interface IButton
{
    void Render();
}

public interface ITextBox
{
    void Render();
}

// Windows用户界面组件
public class WindowsButton : IButton
{
    public void Render() => Console.WriteLine("Rendering Windows Button...");
}

public class WindowsTextBox : ITextBox
{
    public void Render() => Console.WriteLine("Rendering Windows TextBox...");
}

// MacOS用户界面组件
public class MacOSButton : IButton
{
    public void Render() => Console.WriteLine("Rendering MacOS Button...");
}

public class MacOSTextBox : ITextBox
{
    public void Render() => Console.WriteLine("Rendering MacOS TextBox...");
}

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

// Windows用户界面组件工厂
public class WindowsUIComponentFactory : IUIComponentFactory
{
    public IButton CreateButton() => new WindowsButton();
    public ITextBox CreateTextBox() => new WindowsTextBox();
}

// MacOS用户界面组件工厂
public class MacOSUIComponentFactory : IUIComponentFactory
{
    public IButton CreateButton() => new MacOSButton();
    public ITextBox CreateTextBox() => new MacOSTextBox();
}

// 配置类
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");
        }

        IButton button = factory.CreateButton();
        ITextBox textBox = factory.CreateTextBox();

        button.Render();
        textBox.Render();
    }
}

解释

  1. 用户界面组件接口 (IButtonITextBox):定义了渲染按钮和文本框的方法。
  2. 具体用户界面组件 (WindowsButton、WindowsTextBox、MacOSButton、MacOSTextBox):实现了具体的按钮和文本框渲染逻辑。
  3. 抽象工厂接口 (IUIComponentFactory):定义了创建按钮和文本框的方法。
  4. 具体工厂类 (WindowsUIComponentFactoryMacOSUIComponentFactory):实现了具体的按钮和文本框创建逻辑。
  5. 配置类 (Configuration):用于存储操作系统的配置信息。
  6. 客户端代码 (Program):根据配置信息选择合适的工厂类,并使用工厂类创建具体的用户界面组件,然后调用其渲染方法。

2. 数据库操作框架

假设我们正在开发一个数据库操作框架,需要根据不同的数据库类型创建不同的数据访问对象。

csharp 复制代码
// 数据访问接口
public interface IDbConnection
{
    void Connect();
    void Disconnect();
}

public interface IDbCommand
{
    void Execute();
}

// MySQL数据库操作
public class MySqlConnection : IDbConnection
{
    public void Connect() => Console.WriteLine("Connecting to MySQL database...");
    public void Disconnect() => Console.WriteLine("Disconnecting from MySQL database...");
}

public class MySqlCommand : IDbCommand
{
    public void Execute() => Console.WriteLine("Executing MySQL command...");
}

// SQL Server数据库操作
public class SqlServerConnection : IDbConnection
{
    public void Connect() => Console.WriteLine("Connecting to SQL Server database...");
    public void Disconnect() => Console.WriteLine("Disconnecting from SQL Server database...");
}

public class SqlCommand : IDbCommand
{
    public void Execute() => Console.WriteLine("Executing SQL Server command...");
}

// 抽象工厂接口
public interface IDbFactory
{
    IDbConnection CreateConnection();
    IDbCommand CreateCommand();
}

// MySQL数据库工厂
public class MySqlDbFactory : IDbFactory
{
    public IDbConnection CreateConnection() => new MySqlConnection();
    public IDbCommand CreateCommand() => new MySqlCommand();
}

// SQL Server数据库工厂
public class SqlServerDbFactory : IDbFactory
{
    public IDbConnection CreateConnection() => new SqlServerConnection();
    public IDbCommand CreateCommand() => new SqlCommand();
}

// 配置类
public class Configuration
{
    public string DatabaseType { get; set; }
}

// 客户端代码
class Program
{
    static void Main(string[] args)
    {
        Configuration config = new Configuration { DatabaseType = "MySQL" };

        IDbFactory factory;
        if (config.DatabaseType == "MySQL")
        {
            factory = new MySqlDbFactory();
        }
        else if (config.DatabaseType == "SQLServer")
        {
            factory = new SqlServerDbFactory();
        }
        else
        {
            throw new ArgumentException("Unsupported database type");
        }

        IDbConnection connection = factory.CreateConnection();
        IDbCommand command = factory.CreateCommand();

        connection.Connect();
        command.Execute();
        connection.Disconnect();
    }
}

总结

抽象工厂模式通过提供一个创建一系列相关或相互依赖对象的接口,使得对象的创建更加灵活和一致。虽然它增加了系统的复杂度,但在需要创建多个相关对象的场景中,抽象工厂模式能够显著提高代码的可维护性和扩展性。

相关推荐
格林威几秒前
工业相机图像采集:Grab Timeout 设置建议——拒绝“假死”与“丢帧”的黄金法则
开发语言·人工智能·数码相机·计算机视觉·c#·机器视觉·工业相机
唐青枫19 分钟前
C#.NET SignalR + Redis Backplane 深入解析:多节点部署与跨实例消息同步
c#·.net
FL162386312913 小时前
[C#][winform]segment-anything分割万物部署onnx模型一键抠图演示
开发语言·c#
love530love15 小时前
OpenClaw 手机直连配置全流程
人工智能·windows·python·智能手机·c#·agent·openclaw
bcbobo21cn16 小时前
C# byte类型和byte数组的使用
开发语言·c#·字节数组·byte类型
月巴月巴白勺合鸟月半18 小时前
一次PDF文件的处理(一)
pdf·c#
大鹏说大话20 小时前
Java 锁膨胀机制深度解析:从偏向锁到重量级锁的进化之路
开发语言·c#
武藤一雄21 小时前
WPF处理耗时操作的7种方法
microsoft·c#·.net·wpf
武藤一雄1 天前
C#常见面试题100问 (第一弹)
windows·microsoft·面试·c#·.net·.netcore
庞轩px1 天前
HotSpot详解——符号引用、句柄池、直接指针的终极解密
java·jvm·设计模式·内存·虚拟机·引用·klass