策略模式+ 简单工厂模式

一、实时修改配置 → 不适合固定单例,分析和改造方案

核心:单例适合「程序生命周期内,策略固定不变」;如果你支持运行时改配置、切换存储模式,全局固定单例就不合适了。

两种场景区分

  1. 配置只读,启动加载一次(之前的场景)
    程序启动读一次配置,全程不变 → 单例完全没问题,只创建一次实例。

  2. 配置可以实时修改(你现在的场景)
    运行时,用户改json配置,点击刷新,程序要切换到另一种存储实现(XData ↔ XRecord ↔ BlockAttr)。

  • 如果用固定单例:实例是第一次创建好锁死的,就算配置改了,还是旧实例,无法切换。
  • ❌ 不能简单加个 _instance=null 然后重新赋值:
    多线程/多业务同时读写CAD实体时,正在使用旧store,突然替换实例,会出现一半业务用旧实现、一半用新实现,引发诡异bug。

推荐方案(运行时可切换策略)

方案A:工厂 + 持有「可替换的实例引用」(推荐,最简单)

不要把实例做成静态只读单例,而是用一个静态引用变量保存当前有效的store实例。

public static class CadPropertyStoreFactory
{
    // 这里不是单例,只是保存当前在用的实例引用
    private static ICadPropertyStore _currentStore;

    // 程序启动 / 用户刷新配置时调用一次
    public static void ReloadStore(string configMode)
    {
        _currentStore = configMode switch
        {
            "BlockAttr" => new BlockAttributeStore(),
            "XData" => new XDataStore(),
            "XRecord" => new XRecordStore(),
            _ => throw new NotSupportedException($"不支持存储模式:{configMode}")
        };
    }

    // 业务代码获取当前实例
    public static ICadPropertyStore GetCurrentStore()
    {
        if (_currentStore == null)
            throw new InvalidOperationException("请先加载配置初始化Store");
        return _currentStore;
    }
}

业务调用:

// 用户修改配置后,执行一次刷新
CadPropertyStoreFactory.ReloadStore(ReadConfig().PropertyStoreMode);

// 业务代码获取当前生效的store
var store = CadPropertyStoreFactory.GetCurrentStore();
store.Write(ent, "key", val);

注意并发问题:
如果CAD插件存在多线程后台处理管网数据,_currentStore 需要加锁,或者用 volatile,防止半替换。
ZWCAD插件大多是单线程CAD命令上下文,一般不用锁,但要知道这个风险。

工作逻辑:

  • 刷新配置 → 新建对应实现类实例,替换引用;
  • 已经拿到旧store引用的业务代码,会继续使用旧实例执行完当前操作
  • 下一次调用 GetCurrentStore() 拿到的就是新实例。
    这是一种安全平滑切换,不会中途打断正在执行的读写。

方案B:每次Get都根据配置新建实例(不推荐)

public static ICadPropertyStore GetStore()
{
    var mode = ReadConfig().PropertyStoreMode; // 每次都读配置文件
    return mode switch { ... };
}

缺点:每次读写属性都读磁盘配置文件,频繁IO,性能差。

所以:配置文件不要每次都读,内存里缓存配置对象;配置修改时,才重新读一次配置并ReloadStore。

小结

✅ 运行时支持切换存储策略:放弃固定不变的单例,改用工厂维护当前策略引用

本质区别:

  • 经典单例:全局唯一实例,生命周期等于AppDomain,不可替换。
  • 当前方案:策略实例可替换,但同一时刻全局只有一个策略生效

二、接口 + 多个实现类 + 工厂类:是不是经典组合?

是的!这是面向对象里非常经典的组合:策略模式(Strategy Pattern) + 简单工厂模式(Simple Factory)

拆开讲两者职责

  1. 接口 ICadPropertyStore:策略契约,定义统一行为。
  2. 多个实现类(XDataStore / BlockAttrStore):不同策略实现。
  3. 工厂类 CadPropertyStoreFactory:负责根据条件(配置),创建对应的策略实例,把实例选择逻辑集中一处。

策略模式核心:把可变的算法/存储逻辑封装成独立类,实现同一个接口;上层代码依赖接口,不依赖具体实现。
工厂在这里是配套工具,用来隔离实例创建逻辑,不要让业务代码到处写 if/switch + new

常见变体

  1. 简单工厂(我们现在写的):一个静态工厂方法,switch判断创建实例,适合你这种3种、少数几种实现。足够用,项目维护成本低。
  2. 工厂方法模式:每个策略对应一个工厂类,适合实现类非常多、持续大量新增场景,你的CAD属性读写工具没必要上这个,会过度设计。
  3. 抽象工厂:用于创建一组相关对象,这个场景用不到。

一句话区分:

  • 策略模式:解决“用哪个算法/逻辑”的问题(业务逻辑可变)
  • 工厂模式:解决“怎么创建对象”的问题(对象创建解耦)

两者经常成对出现,是.NET插件、CAD二次开发里最常用的一套组合。


三、额外补充一个小坑(贴合你的场景)

因为你支持运行时切换策略:
不要在各个Store实现类的构造函数里写全局持久化注册逻辑(比如多次调用 RegAppName)。
可以放到静态初始化,避免反复ReloadStore的时候重复执行注册。

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值