You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何实现工厂创建对象的批量替换且自动更新所有代码引用?

更优实现方案汇总

方案1:代理模式实现无侵入透明替换

该方案解决了原实现需要调用.Value的侵入性问题,对外始终暴露ITheme接口,调用方完全感知不到间接层的存在。
首先实现代理类:

public class ThemeProxy : ITheme
{
    // 内部持有实际主题实例,工厂可直接修改该值
    internal ITheme InnerTheme { get; set; }
    
    public ThemeProxy(ITheme initialTheme)
    {
        InnerTheme = initialTheme;
    }

    // 接口成员全部转发到内部实例
    public string TextColor => InnerTheme.TextColor;
    public string BgrColor => InnerTheme.BgrColor;
}

改造后的工厂类:

public class ProxyThemeFactory
{
    private readonly List<WeakReference<ThemeProxy>> _proxies = new();

    public ITheme CreateTheme(bool dark)
    {
        var theme = dark ? new DarkTheme() : new LightTheme();
        var proxy = new ThemeProxy(theme);
        _proxies.Add(new WeakReference<ThemeProxy>(proxy));
        // 对外直接返回ITheme接口,调用方无需感知代理存在
        return proxy;
    }

    public void ReplaceTheme(bool dark)
    {
        var newTheme = dark ? new DarkTheme() : new LightTheme();
        foreach (var wr in _proxies)
        {
            if (wr.TryGetTarget(out var proxy))
            {
                proxy.InnerTheme = newTheme;
            }
        }
    }

    // 保留原有的存活实例统计能力
    public string Info
    {
        get
        {
            var sb = new StringBuilder();
            foreach (var wr in _proxies)
            {
                if (wr.TryGetTarget(out var proxy))
                {
                    bool isDark = proxy.InnerTheme is DarkTheme;
                    sb.Append(isDark ? "Dark" : "Light");
                    sb.AppendLine(" theme");
                }
            }
            return sb.ToString();
        }
    }
}

使用示例:

var factory = new ProxyThemeFactory();
var theme = factory.CreateTheme(true);
Console.WriteLine(theme.BgrColor); // 输出 dark gray
factory.ReplaceTheme(false);
Console.WriteLine(theme.BgrColor); // 输出 white

优势:完全兼容ITheme接口,调用方代码不需要做任何修改,没有.Value的额外编码要求,也不会出现漏写.Value的低级错误。
注意点:如果ITheme接口后续新增成员,代理类需要同步新增转发逻辑,可通过源生成器自动生成代理类避免手动维护成本。


方案2:适配DI生态的可观测主题方案

如果项目本身使用依赖注入框架,可直接复用.NET内置的IOptionsMonitor能力实现全局替换,无需自己维护弱引用列表:

  1. 定义主题配置类
public class ThemeOptions
{
    public bool IsDark { get; set; }
}
  1. 注册服务
// 注册配置监听服务
services.Configure<ThemeOptions>(opt => opt.IsDark = false);
// 注册ITheme为每次获取时从最新配置生成实例
services.AddTransient<ITheme>(sp => 
{
    var opt = sp.GetRequiredService<IOptionsMonitor<ThemeOptions>>().CurrentValue;
    return opt.IsDark ? new DarkTheme() : new LightTheme();
});
  1. 全局替换主题时只需要修改配置
var optMonitor = serviceProvider.GetRequiredService<IOptionsMonitor<ThemeOptions>>();
optMonitor.CurrentValue.IsDark = true;
// 后续所有获取ITheme的地方都会自动拿到新的主题实例

优势:完全复用DI框架能力,不需要自己实现工厂、弱引用追踪逻辑,适合中大型项目使用。
注意点:已经提前获取到的ITheme实例不会自动更新,适合使用方每次使用前从DI容器获取实例的场景。


方案3:通用泛型代理方案

如果需要支持多个类型的全局替换,可做通用的泛型动态代理,不需要为每个接口手写代理类,可通过Castle.Core等动态代理库实现,简化实现思路如下:

public class DynamicProxy<T> : DispatchProxy where T : class
{
    public T Inner { get; set; }

    public static T Create(T initial)
    {
        var proxy = Create<T, DynamicProxy<T>>();
        ((DynamicProxy<T>)proxy).Inner = initial;
        return proxy;
    }

    protected override object Invoke(MethodInfo targetMethod, object[] args)
    {
        return targetMethod.Invoke(Inner, args);
    }
}

使用时工厂直接返回DynamicProxy<T>.Create(实例)即可,所有接口调用都会自动转发到内部实例,替换时修改Inner属性即可。


内容的提问来源于stack exchange,提问作者Dmitri Nesteruk

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.04 19:00:00