0
点赞
收藏
分享

微信扫一扫

《设计模式在C#中的实践:单例与工厂模式(七)》

线程安全单例的进化之路与工厂模式的解耦艺术

1. 单例模式:唯一实例的全局访问点

核心目标:确保一个类仅有一个实例,并提供全局访问入口,常用于配置管理、线程池、日志服务等场景。

1.1 线程安全单例的五种实现范式

  • 饿汉式(静态初始化)

csharp
 public sealed class Singleton
 
 {
 
     private static readonly Singleton _instance = new Singleton();
 
     public static Singleton Instance => _instance;
 
     private Singleton() { } // 私有构造函数
 
 }

  • 优点:线程安全(类加载时初始化)、简单高效。
  • 缺点:提前占用资源,无法延迟加载。
  • 懒汉式(简单锁)

csharp
 public sealed class Singleton
 
 {
 
     private static Singleton _instance;
 
     private static readonly object _lock = new object();
 
     public static Singleton Instance
 
     {
 
         get
 
         {
 
             lock (_lock)
 
             {
 
                 return _instance ??= new Singleton();
 
             }
 
         }
 
     }
 
     private Singleton() { }
 
 }

  • 优点:延迟加载,节省启动资源。
  • 缺点:每次访问需加锁,性能损耗较大。
  • 双重检查锁定(DCL)

csharp
 public sealed class Singleton
 
 {
 
     private static volatile Singleton _instance;
 
     private static readonly object _lock = new object();
 
     public static Singleton Instance
 
     {
 
         get
 
         {
 
             if (_instance is null)
 
             {
 
                 lock (_lock)
 
                 {
 
                     if (_instance is null)
 
                         _instance = new Singleton();
 
                 }
 
             }
 
             return _instance;
 
         }
 
     }
 
     private Singleton() { }
 
 }

  • 关键点volatile确保内存可见性,避免指令重排序导致半初始化对象被读取。
  • 适用场景:.NET Framework 4.5及以下版本,需谨慎处理内存模型。
  • .NET 4+ 推荐方案:Lazy

csharp
 public sealed class Singleton
 
 {
 
     private static readonly Lazy<Singleton> _lazy = new Lazy<Singleton>(() => new Singleton());
 
     public static Singleton Instance => _lazy.Value;
 
     private Singleton() { }
 
 }

  • 优点:内置线程安全、延迟加载、异常封装(如构造器抛出异常时,后续调用重试)。
  • 无锁单例(静态类)

csharp
 public static class Singleton
 
 {
 
     public static void Configure(Action<Singleton> config) { ... }
 
 }

  • 适用场景:无需状态存储的工具类,通过静态方法提供功能。

1.2 单例模式的变体与扩展

  • 可关闭单例:通过Dispose方法释放资源,允许重新初始化。
  • 多例模式:控制实例数量上限(如连接池),通过对象池复用实例。
  • 依赖注入集成:在ASP.NET Core中通过AddSingleton注册服务,实现容器管理。

2. 工厂模式:解耦对象创建与使用逻辑

核心价值:将对象的创建逻辑封装在工厂中,使客户端代码仅依赖抽象接口,提升代码灵活性与可测试性。

2.1 简单工厂:集中化的创建逻辑

  • 结构
  • 工厂类:包含静态方法,根据参数返回具体产品实例。
  • 产品接口:定义抽象产品行为。
  • 具体产品:实现接口的具体类。

代码示例

csharp
 public interface IProduct { void Operation(); }
 
 public class ConcreteProductA : IProduct { public void Operation() { } }
 
 public class ConcreteProductB : IProduct { public void Operation() { } }
 
  
 
 public static class SimpleFactory
 
 {
 
     public static IProduct CreateProduct(string type) => type switch
 
     {
 
         "A" => new ConcreteProductA(),
 
         "B" => new ConcreteProductB(),
 
         _ => throw new ArgumentException("未知类型")
 
     };
 
 }
 
  
 
 // 客户端调用
 
 IProduct product = SimpleFactory.CreateProduct("A");

  • 缺点:违反开闭原则(新增产品需修改工厂类),工厂类职责过重。

2.2 工厂方法模式:多态工厂的扩展性

  • 结构
  • 抽象工厂:定义创建产品的接口方法。
  • 具体工厂:实现抽象工厂,负责创建具体产品。
  • 产品接口与具体产品:同简单工厂。

代码示例

csharp
 public interface IFactory
 
 {
 
     IProduct CreateProduct();
 
 }
 
  
 
 public class ConcreteFactoryA : IFactory
 
 {
 
     public IProduct CreateProduct() => new ConcreteProductA();
 
 }
 
  
 
 public class ConcreteFactoryB : IFactory
 
 {
 
     public IProduct CreateProduct() => new ConcreteProductB();
 
 }
 
  
 
 // 客户端调用(通过具体工厂创建)
 
 IFactory factory = new ConcreteFactoryA();
 
 IProduct product = factory.CreateProduct();

  • 优点:符合开闭原则(新增产品只需添加具体工厂),支持动态切换创建逻辑。
  • 应用场景:数据库访问层(如不同数据库的连接工厂)、插件系统。

2.3 抽象工厂模式:产品族的协同创建

  • 核心:提供一系列相关或依赖对象的接口,无需指定具体类。
  • 适用场景:跨平台UI组件(如Windows/MacOS的按钮、文本框)、主题皮肤切换。

代码示例

csharp
 public interface IButton { void Render(); }
 
 public interface ITextBox { void Render(); }
 
  
 
 public interface IGUIFactory
 
 {
 
     IButton CreateButton();
 
     ITextBox CreateTextBox();
 
 }
 
  
 
 public class WindowsFactory : IGUIFactory
 
 {
 
     public IButton CreateButton() => new WindowsButton();
 
     public ITextBox CreateTextBox() => new WindowsTextBox();
 
 }
 
  
 
 // 客户端通过工厂创建产品族
 
 IGUIFactory factory = new WindowsFactory();
 
 IButton button = factory.CreateButton();
 
 button.Render();

3. 单例与工厂的协同应用案例

案例:全局配置管理器

  • 单例角色ConfigurationManager作为单例,存储全局配置。
  • 工厂角色IConfigLoaderFactory创建不同配置加载器(如JSON、XML)。
  • 协同逻辑

csharp
 public sealed class ConfigurationManager
 
 {
 
     private static readonly Lazy<ConfigurationManager> _lazy = new Lazy<ConfigurationManager>(() => new ConfigurationManager());
 
     public static ConfigurationManager Instance => _lazy.Value;
 
     
 
     private IConfigLoader _loader;
 
     
 
     private ConfigurationManager()
 
     {
 
         // 通过工厂注入具体加载器
 
         var factory = new ConfigLoaderFactory();
 
         _loader = factory.CreateLoader("JSON");
 
     }
 
 }

4. 最佳实践与避坑指南

  • 单例模式
  • 优先使用Lazy<T>实现线程安全单例,避免手动锁管理。
  • 避免在单例中持有可变状态,防止并发问题。
  • 工厂模式
  • 简单工厂适用于产品类型固定的场景,工厂方法更适用于需要扩展的场景。
  • 抽象工厂需谨慎设计产品族接口,避免过度复杂化。
  • 依赖注入集成
  • 在ASP.NET Core中,通过IServiceCollection注册单例或工厂,利用DI容器管理生命周期。

5. 总结与进阶方向

  • 单例模式:从基础实现到线程安全优化,再到与依赖注入框架的集成,是全局状态管理的核心工具。
  • 工厂模式:通过解耦创建逻辑,提升代码的灵活性与可测试性,是设计可扩展系统的基础。
  • 进阶探索
  • 单例模式的序列化问题(如[Serializable]属性与跨进程单例)。
  • 工厂模式与构建器模式(Builder)的对比,适用于复杂对象的逐步构造。
  • 结合反射与依赖注入实现动态工厂,支持插件化架构。

通过本篇深度解析,你将系统掌握单例与工厂模式在C#中的实践技巧,为设计高可维护性、可扩展性的系统奠定坚实基础。

举报

相关推荐

0 条评论