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

如何基于参数类型实现工厂模式,消除Photo类判断的冗余if条件

C# 消除Photo类型判断的实现方案

可以通过工厂模式实现,除此之外还有多类适配不同场景的优雅实现方案,具体如下:


方案1:动态分发(最小改动方案)

利用C#的dynamic关键字将重载决议从编译期推迟到运行期,自动匹配对应派生类的Load重载,仅需修改一行代码即可完全消除所有if类型判断:

public void ImportPhoto(PhotoBase photo)
{
    _photoLoader.Load((dynamic)photo);
}

优缺点

  • 优点:改动量极小,无需修改原有基类、派生类、PhotoLoader的结构,新增派生类时仅需在PhotoLoader中添加对应重载即可自动适配
  • 缺点:存在极微小的动态类型性能开销,无编译期类型校验,若新增派生类后未添加对应Load重载,仅会在运行期抛出异常

方案2:访问者模式(类型安全的OOP标准方案)

如果追求编译期类型安全、无额外性能开销,可以采用访问者模式实现多态分发:

第一步:修改抽象基类,定义访问者接口

public abstract class PhotoBase
{
    public string Path { get; set; }
    // 新增接收访问者的抽象方法
    public abstract void Accept(IPhotoVisitor visitor);
}

// 定义访问者接口
public interface IPhotoVisitor
{
    void Visit(FilePhoto photo);
    void Visit(ExternalPhoto photo);
    // 后续新增派生类时,仅需在此处添加对应Visit方法定义
}

第二步:派生类实现Accept方法

public class FilePhoto : PhotoBase 
{
    public override void Accept(IPhotoVisitor visitor) => visitor.Visit(this);
}

public class ExternalPhoto : PhotoBase 
{
    public override void Accept(IPhotoVisitor visitor) => visitor.Visit(this);
}

第三步:PhotoLoader实现访问者接口

public class PhotoLoader : IPhotoVisitor
{
    public void Visit(FilePhoto Photo)
    {
        // 原有从文件系统加载的逻辑
    }

    public void Visit(ExternalPhoto Photo)
    {
        // 原有从URL下载的逻辑
    }
}

第四步:修改ImportPhoto逻辑

public void ImportPhoto(PhotoBase photo)
{
    photo.Accept(_photoLoader);
}

优缺点

  • 优点:完全类型安全,编译期即可校验所有派生类是否有对应处理逻辑,无额外性能开销,符合开闭原则
  • 缺点:需要修改原有基类和派生类的结构,新增派生类时需要同步修改访问者接口的定义

方案3:工厂+策略模式(无需修改原有类结构的工厂实现)

就是你提到的工厂模式的落地实现,将类型判断逻辑收敛到PhotoLoader内部的策略字典中,完全不需要修改基类和派生类:

public class PhotoLoader
{
    // 存储类型对应加载策略的字典
    private readonly Dictionary<Type, Action<PhotoBase>> _loadStrategies = new();

    public PhotoLoader()
    {
        // 注册各类型的加载逻辑
        RegisterStrategy<FilePhoto>(LoadFilePhoto);
        RegisterStrategy<ExternalPhoto>(LoadExternalPhoto);
    }

    // 泛型注册方法,避免重复转型代码
    private void RegisterStrategy<T>(Action<T> loadAction) where T : PhotoBase
    {
        _loadStrategies.Add(typeof(T), photo => loadAction((T)photo));
    }

    // 对外统一的Load入口
    public void Load(PhotoBase photo)
    {
        if (_loadStrategies.TryGetValue(photo.GetType(), out var loadAction))
        {
            loadAction(photo);
            return;
        }
        throw new NotSupportedException($"不支持的照片类型:{photo.GetType().Name}");
    }

    // 原有各类型的加载逻辑,改为私有方法
    private void LoadFilePhoto(FilePhoto Photo)
    {
        // 从文件系统加载
    }

    private void LoadExternalPhoto(ExternalPhoto Photo)
    {
        // 从URL下载
    }
}

修改后ImportPhoto可以直接调用统一入口:

public void ImportPhoto(PhotoBase photo)
{
    _photoLoader.Load(photo);
}

优缺点

  • 优点:无需修改原有基类、派生类的结构,类型安全,无动态类型开销,新增派生类时仅需添加对应加载方法并在构造函数中注册即可
  • 缺点:需要手动注册策略,漏注册会在运行期抛出异常

方案选型建议

  • 小型项目、快速迭代优先选动态分发方案,改动成本最低
  • 中大型项目、派生类数量稳定优先选访问者模式,类型安全更有保障
  • 不能修改基类/派生类结构的场景优先选工厂+策略模式,适配性最强

内容的提问来源于stack exchange,提问作者Hooman Bahreini

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.26 14:54:07