当前位置: 首页 > news >正文

C# 设计模式——工厂模式

工厂模式

在C#中,工厂设计模式(Factory Pattern) 是一种创建型设计模式,核心目的是封装对象的创建过程,将对象的“使用”与“创建”解耦,让客户端无需直接依赖具体类,而是通过“工厂”间接获取对象。这种模式能提高代码的灵活性、可维护性和扩展性,尤其适合需要频繁创建相似类型对象的场景。

工厂模式通常分为三种形式,从简单到复杂依次为:简单工厂模式工厂方法模式抽象工厂模式。下面分别详解:

一、简单工厂模式(Simple Factory)

核心思想:由一个统一的工厂类根据输入参数,决定创建哪种具体产品的实例。
(注:简单工厂不算“标准”设计模式,但应用广泛,是理解其他工厂模式的基础。)

结构
  • 抽象产品(Product):定义所有具体产品的公共接口(或抽象类)。
  • 具体产品(Concrete Product):实现抽象产品接口,是工厂的创建目标。
  • 工厂(Factory):提供静态方法(或实例方法),根据参数创建并返回具体产品实例。
示例:创建不同类型的计算器

假设需要实现加法、减法计算器,用简单工厂统一创建:

// 1. 抽象产品:计算器接口(定义计算方法)
public interface ICalculator
{int Calculate(int a, int b);
}// 2. 具体产品1:加法计算器
public class AddCalculator : ICalculator
{public int Calculate(int a, int b) => a + b;
}// 3. 具体产品2:减法计算器
public class SubtractCalculator : ICalculator
{public int Calculate(int a, int b) => a - b;
}// 4. 工厂类:根据参数创建具体计算器
public static class CalculatorFactory
{// 静态方法:输入操作类型,返回对应计算器public static ICalculator CreateCalculator(string operation){return operation.ToLower() switch{"+" => new AddCalculator(),"-" => new SubtractCalculator(),_ => throw new ArgumentException("无效的操作符")};}
}// 客户端使用
class Program
{static void Main(string[] args){// 客户端不直接new具体类,而是通过工厂获取ICalculator addCalc = CalculatorFactory.CreateCalculator("+");Console.WriteLine(addCalc.Calculate(5, 3)); // 8ICalculator subCalc = CalculatorFactory.CreateCalculator("-");Console.WriteLine(subCalc.Calculate(5, 3)); // 2}
}
优缺点
  • 优点:客户端无需知道具体产品类名,只需通过参数获取对象,简化了对象创建。
  • 缺点:若新增产品(如乘法计算器),需修改工厂类的CreateCalculator方法,违反“开闭原则”(对扩展开放,对修改关闭),且工厂类职责过重,不易维护。

二、工厂方法模式(Factory Method)

核心思想:将工厂抽象化,每个具体产品对应一个具体工厂,由具体工厂负责创建对应的产品。客户端通过调用具体工厂的方法获取产品,新增产品时只需新增对应的工厂,无需修改原有代码。

结构
  • 抽象产品(Product):所有具体产品的公共接口。
  • 具体产品(Concrete Product):实现抽象产品。
  • 抽象工厂(Factory):定义创建产品的接口(抽象方法)。
  • 具体工厂(Concrete Factory):实现抽象工厂接口,创建对应的具体产品。
示例:日志记录器(文件日志、数据库日志)

假设需要支持“文件日志”和“数据库日志”,且未来可能扩展更多日志类型:

// 1. 抽象产品:日志记录器接口
public interface ILogger
{void Log(string message);
}// 2. 具体产品1:文件日志
public class FileLogger : ILogger
{public void Log(string message){Console.WriteLine($"文件日志:{message}");}
}// 3. 具体产品2:数据库日志
public class DatabaseLogger : ILogger
{public void Log(string message){Console.WriteLine($"数据库日志:{message}");}
}// 4. 抽象工厂:日志工厂接口(定义创建日志的方法)
public interface ILoggerFactory
{ILogger CreateLogger(); // 工厂方法:返回日志实例
}// 5. 具体工厂1:文件日志工厂(创建FileLogger)
public class FileLoggerFactory : ILoggerFactory
{public ILogger CreateLogger() => new FileLogger();
}// 6. 具体工厂2:数据库日志工厂(创建DatabaseLogger)
public class DatabaseLoggerFactory : ILoggerFactory
{public ILogger CreateLogger() => new DatabaseLogger();
}// 客户端使用
class Program
{static void Main(string[] args){// 客户端依赖抽象工厂和抽象产品,不直接依赖具体类ILoggerFactory factory1 = new FileLoggerFactory();ILogger fileLogger = factory1.CreateLogger();fileLogger.Log("系统启动成功"); // 输出:文件日志:系统启动成功ILoggerFactory factory2 = new DatabaseLoggerFactory();ILogger dbLogger = factory2.CreateLogger();dbLogger.Log("用户登录"); // 输出:数据库日志:用户登录}
}
优缺点
  • 优点:符合“开闭原则”,新增产品(如ConsoleLogger)只需新增对应的ConsoleLoggerFactoryConsoleLogger,无需修改原有代码;客户端完全依赖抽象,降低耦合。
  • 缺点:每增加一个产品,需同时增加一个具体工厂,导致类数量增多,系统复杂度上升。

三、抽象工厂模式(Abstract Factory)

核心思想:用于创建一系列相互关联或相互依赖的产品族(而非单一产品)。抽象工厂定义创建多个产品的接口,具体工厂实现该接口,负责创建对应系列的所有产品。

结构
  • 抽象产品族(多个Product接口):如“按钮”“文本框”属于UI控件产品族。
  • 具体产品(Concrete Product):每个产品族下的具体实现(如“Windows按钮”“Mac按钮”)。
  • 抽象工厂(Abstract Factory):定义创建产品族中所有产品的接口(多个工厂方法)。
  • 具体工厂(Concrete Factory):实现抽象工厂,创建某一系列的所有产品(如“Windows控件工厂”创建Windows按钮和文本框)。
示例:跨平台UI控件(Windows和Mac系统的按钮、文本框)

假设需要为Windows和Mac系统创建配套的按钮和文本框(同一系统的控件风格一致):

// 1. 抽象产品1:按钮接口
public interface IButton
{void Render();
}// 2. 抽象产品2:文本框接口
public interface ITextBox
{void Render();
}// 3. 具体产品1:Windows按钮
public class WindowsButton : IButton
{public void Render() => Console.WriteLine("渲染Windows风格按钮");
}// 4. 具体产品2:Windows文本框
public class WindowsTextBox : ITextBox
{public void Render() => Console.WriteLine("渲染Windows风格文本框");
}// 5. 具体产品3:Mac按钮
public class MacButton : IButton
{public void Render() => Console.WriteLine("渲染Mac风格按钮");
}// 6. 具体产品4:Mac文本框
public class MacTextBox : ITextBox
{public void Render() => Console.WriteLine("渲染Mac风格文本框");
}// 7. 抽象工厂:UI控件工厂(定义创建按钮和文本框的方法)
public interface IUiFactory
{IButton CreateButton();ITextBox CreateTextBox();
}// 8. 具体工厂1:Windows控件工厂(创建Windows系列控件)
public class WindowsUiFactory : IUiFactory
{public IButton CreateButton() => new WindowsButton();public ITextBox CreateTextBox() => new WindowsTextBox();
}// 9. 具体工厂2:Mac控件工厂(创建Mac系列控件)
public class MacUiFactory : IUiFactory
{public IButton CreateButton() => new MacButton();public ITextBox CreateTextBox() => new MacTextBox();
}// 客户端使用
class Program
{static void Main(string[] args){// 根据系统选择对应的工厂(实际场景可能从配置文件读取)IUiFactory factory = new WindowsUiFactory(); // 切换为MacUiFactory即可切换全系列控件// 创建配套控件IButton button = factory.CreateButton();ITextBox textBox = factory.CreateTextBox();// 渲染button.Render(); // 渲染Windows风格按钮textBox.Render(); // 渲染Windows风格文本框}
}
优缺点
  • 优点:保证同一工厂创建的产品都是“配套”的(如Windows控件风格统一);客户端无需知道具体产品,只需依赖抽象工厂和产品接口。
  • 缺点:扩展产品族困难(如新增“下拉框”控件),需修改抽象工厂和所有具体工厂的接口,违反“开闭原则”。

三种工厂模式的对比与选择

模式核心场景优点缺点
简单工厂产品类型少且稳定,无需频繁扩展实现简单,客户端调用方便新增产品需修改工厂,违反开闭原则
工厂方法产品类型可能扩展,每个产品独立创建符合开闭原则,扩展灵活类数量增多,系统复杂度上升
抽象工厂需要创建一系列相互关联的产品族(如跨平台组件)保证产品一致性,适合产品族场景扩展产品族困难,修改成本高

总结

工厂模式的核心是**“封装对象创建”**,通过引入工厂层隔离客户端与具体产品的依赖,使系统更易扩展和维护。在C#开发中:

  • 简单场景(如工具类创建)用简单工厂
  • 单一产品扩展(如日志、计算器)用工厂方法
  • 多产品族场景(如跨平台组件、数据库驱动套件)用抽象工厂

泛型+工厂

在C#中,将工厂模式泛型结合,可以进一步简化代码、提高灵活性,并增强类型安全。泛型的“类型参数化”特性能够避免工厂模式中大量重复的具体工厂类,同时让工厂更通用——无需硬编码具体产品类型,而是通过泛型参数动态指定要创建的产品。

核心思路

泛型工厂的核心是:通过泛型类型参数替代硬编码的具体产品类型,利用泛型约束(where)限制产品必须符合抽象产品的规范,最终通过反射(如Activator.CreateInstance)或委托动态创建产品实例。

这种结合既能保留工厂模式“解耦创建与使用”的优势,又能减少代码冗余(无需为每个产品编写单独的工厂类)。

一、简单工厂 + 泛型:通用产品创建器

简单工厂的痛点是“新增产品需修改工厂逻辑”,而泛型可以通过类型参数动态指定产品,彻底避免硬编码判断(如switch/if)。

示例:通用日志工厂(创建不同类型的日志记录器)

假设需要创建FileLoggerDatabaseLoggerConsoleLogger等日志记录器,且所有日志都实现ILogger接口:

// 1. 抽象产品:日志接口
public interface ILogger
{void Log(string message);
}// 2. 具体产品:文件日志
public class FileLogger : ILogger
{public void Log(string message) => Console.WriteLine($"[文件日志] {message}");
}// 3. 具体产品:数据库日志
public class DatabaseLogger : ILogger
{public void Log(string message) => Console.WriteLine($"[数据库日志] {message}");
}// 4. 具体产品:控制台日志
public class ConsoleLogger : ILogger
{public void Log(string message) => Console.WriteLine($"[控制台日志] {message}");
}// 5. 泛型简单工厂:通过泛型参数创建具体产品
public static class GenericLoggerFactory
{// 泛型方法:创建T类型的日志实例(T必须实现ILogger,且有公共无参构造函数)public static T CreateLogger<T>() where T : ILogger, new(){// 利用new()约束直接创建实例(无需反射)return new T();}
}// 客户端使用
class Program
{static void Main(string[] args){// 通过泛型参数指定要创建的日志类型ILogger fileLogger = GenericLoggerFactory.CreateLogger<FileLogger>();fileLogger.Log("系统启动"); // [文件日志] 系统启动ILogger consoleLogger = GenericLoggerFactory.CreateLogger<ConsoleLogger>();consoleLogger.Log("用户操作"); // [控制台日志] 用户操作}
}
关键点解析
  • 泛型约束where T : ILogger, new() 确保:
    • T必须是ILogger的实现类(保证产品符合抽象规范);
    • T有公共无参构造函数(允许通过new T()创建实例)。
  • 扩展性:新增日志类型(如NetworkLogger)时,只需让其实现ILogger并提供无参构造函数,无需修改GenericLoggerFactory,完全符合“开闭原则”。

二、工厂方法 + 泛型:简化具体工厂

工厂方法模式的痛点是“每新增一个产品需对应新增一个具体工厂类”,导致类数量爆炸。泛型可以通过一个泛型具体工厂替代多个具体工厂,大幅减少类数量。

示例:泛型日志工厂(替代多个具体工厂)
// 1. 抽象产品:ILogger(同上)
// 2. 具体产品:FileLogger、DatabaseLogger等(同上)// 3. 抽象工厂:定义创建日志的接口
public interface ILoggerFactory
{ILogger CreateLogger();
}// 4. 泛型具体工厂:通过泛型参数指定产品类型,实现抽象工厂
public class GenericLoggerFactory<T> : ILoggerFactory where T : ILogger, new()
{public ILogger CreateLogger(){return new T(); // 创建T类型的日志实例}
}// 客户端使用
class Program
{static void Main(string[] args){// 泛型工厂替代了FileLoggerFactory、DatabaseLoggerFactory等ILoggerFactory fileFactory = new GenericLoggerFactory<FileLogger>();ILogger fileLogger = fileFactory.CreateLogger();fileLogger.Log("文件日志测试"); // [文件日志] 文件日志测试ILoggerFactory dbFactory = new GenericLoggerFactory<DatabaseLogger>();ILogger dbLogger = dbFactory.CreateLogger();dbLogger.Log("数据库日志测试"); // [数据库日志] 数据库日志测试}
}
优势
  • 原来需要FileLoggerFactoryDatabaseLoggerFactory等多个类,现在通过一个GenericLoggerFactory<T>即可覆盖所有产品,减少类数量。
  • 新增产品时,只需创建产品类(如NetworkLogger),直接通过GenericLoggerFactory<NetworkLogger>使用,无需新增工厂类。

三、抽象工厂 + 泛型:处理产品族

抽象工厂用于创建“产品族”(如Windows控件族、Mac控件族),泛型可简化产品族的创建逻辑,避免为每个产品族编写大量重复的具体工厂代码。

示例:跨平台UI控件工厂(泛型处理控件族)

假设需要创建“按钮(IButton)”和“文本框(ITextBox)”组成的UI控件族,支持Windows和Mac平台:

// 1. 抽象产品1:按钮
public interface IButton { void Render(); }// 2. 抽象产品2:文本框
public interface ITextBox { void Render(); }// 3. Windows产品族
public class WindowsButton : IButton { public void Render() => Console.WriteLine("Windows按钮"); }
public class WindowsTextBox : ITextBox { public void Render() => Console.WriteLine("Windows文本框"); }// 4. Mac产品族
public class MacButton : IButton { public void Render() => Console.WriteLine("Mac按钮"); }
public class MacTextBox : ITextBox { public void Render() => Console.WriteLine("Mac文本框"); }// 5. 抽象工厂:定义创建产品族的接口
public interface IUiFactory
{IButton CreateButton();ITextBox CreateTextBox();
}// 6. 泛型具体工厂:通过两个泛型参数指定按钮和文本框类型(同属一个产品族)
public class GenericUiFactory<TButton, TTextBox> : IUiFactory where TButton : IButton, new()where TTextBox : ITextBox, new()
{public IButton CreateButton() => new TButton();public ITextBox CreateTextBox() => new TTextBox();
}// 客户端使用
class Program
{static void Main(string[] args){// Windows控件族工厂(按钮=WindowsButton,文本框=WindowsTextBox)IUiFactory windowsFactory = new GenericUiFactory<WindowsButton, WindowsTextBox>();windowsFactory.CreateButton().Render(); // Windows按钮windowsFactory.CreateTextBox().Render(); // Windows文本框// Mac控件族工厂(按钮=MacButton,文本框=MacTextBox)IUiFactory macFactory = new GenericUiFactory<MacButton, MacTextBox>();macFactory.CreateButton().Render(); // Mac按钮macFactory.CreateTextBox().Render(); // Mac文本框}
}
优势
  • GenericUiFactory<TButton, TTextBox>替代了WindowsUiFactoryMacUiFactory,无需为每个产品族编写单独的工厂类。
  • 产品族的扩展更灵活:若新增Linux控件族,只需创建LinuxButtonLinuxTextBox,直接通过GenericUiFactory<LinuxButton, LinuxTextBox>使用。

四、泛型工厂的进阶:解决“无参构造函数”限制

上面的示例依赖new()约束(要求产品有公共无参构造函数),但实际开发中产品可能需要带参构造(如DatabaseLogger需要连接字符串)。此时可通过泛型方法参数委托传递构造参数:

示例:支持带参构造的泛型工厂
public class DatabaseLogger : ILogger
{private string _connectionString;// 带参构造函数(需要连接字符串)public DatabaseLogger(string connectionString){_connectionString = connectionString;}public void Log(string message) => Console.WriteLine($"[数据库日志({_connectionString})] {message}");
}// 支持带参构造的泛型工厂
public static class GenericLoggerFactory
{// 泛型方法:通过参数传递构造函数参数public static T CreateLogger<T>(params object[] parameters) where T : ILogger{// 用反射创建带参实例(绕过new()约束)return (T)Activator.CreateInstance(typeof(T), parameters);}
}// 客户端使用
class Program
{static void Main(string[] args){// 传递构造参数(连接字符串)ILogger dbLogger = GenericLoggerFactory.CreateLogger<DatabaseLogger>("Server=localhost;DB=LogDB");dbLogger.Log("连接成功"); // [数据库日志(Server=localhost;DB=LogDB)] 连接成功}
}

总结:泛型 + 工厂模式的核心价值

  1. 减少代码冗余:用泛型参数替代硬编码的具体类型,避免大量重复的工厂类或判断逻辑。
  2. 增强扩展性:新增产品时,只需实现抽象产品接口,无需修改工厂代码(符合开闭原则)。
  3. 类型安全:通过泛型约束(where)确保创建的产品符合规范,编译时即可发现类型错误。
  4. 灵活性:支持无参/带参构造函数,适配更多场景。

实际开发中,泛型工厂尤其适合“产品类型多、创建逻辑相似”的场景(如工具类、数据访问层、插件系统等),结合依赖注入框架(如Autofac)可进一步提升易用性。

http://www.dtcms.com/a/507646.html

相关文章:

  • 配置电话交换机 3CX 对接微软 Teams 直接路由
  • 亚马逊云渠道商:如何配置 AWS 自动化快照?
  • [优选算法专题四.前缀和——NO.29 和为 K 的子数组]
  • Python Web框架深度对比:Django vs Flask vs FastAPI(含优缺点与选型策略)
  • 盲盒抽谷机小程序:打造个性化消费的梦幻舞台
  • 性能优化揭秘:将淘宝商品 API 响应时间从 500ms 优化到 50ms 的技术实践
  • 龙岩互联网抖音seo招商
  • C++ 智能指针 std::unique_ptr、std::shared_ptr、std::weak_ptr
  • 猿辅导Java面试真实经历与深度总结(三)
  • Doris 数据导入
  • 网站建设+泰安saas建站平台有哪些
  • 动态规划之两个字符组/两个数组的dp问题
  • 【AI论文】UniVideo:面向视频的统一理解、生成与编辑
  • 获取resources目录下静态资源的两种方式
  • 一个域名可以做几个网站吗最好加盟网站建设
  • Android 自定义 View 如何设置默认尺寸
  • C#技术栈
  • 广东建设监理网站如何查企业的工商信息
  • INT301 Bio-computation 生物计算(神经网络)Pt.2 监督学习模型:感知器(Perceptron)
  • 机器学习(4)多特征与向量化
  • stripe/paypal
  • 机器学习(5)特征缩放与梯度下降收敛
  • 英飞凌推出首款100V aec合格GaN晶体管
  • 李宏毅机器学习笔记27
  • 机器学习作业七
  • openEuler安装jdk,nginx,redis
  • ffmpeg 交叉编译
  • Python编程之面向对象
  • 建设一个网站大概费用门户网站开发工具
  • OpenCV cv::Mat.type() 以及类型数据转换