工厂模式替代方案:根据文件扩展名选择构造不同的进程类
嘿,这个问题我之前也踩过类似的坑——当子类构造函数签名不一样时,常规的简单工厂确实会显得束手束脚。不过有几个很实用的方案可以解决这个问题,我给你梳理下:
方案1:参数对象+工厂方法(最推荐,兼顾清晰与灵活)
核心思路是把不同子类需要的构造参数,统一封装成一个参数对象,让工厂只需要传递这个对象,子类自己从里面提取需要的信息。这样不管子类构造函数差异多大,工厂的接口都是统一的。
举个代码示例:
// 基类 public abstract class BaseProcess { public abstract void Start(); } // 参数对象,包含所有可能需要的参数 public class ProcessCreationParams { public string ExecutablePath { get; set; } public IntPtr ParentProcessHandle { get; set; } // 其他可能的参数:命令行参数、工作目录等 } // 独立进程子类 public class IndependentProcess : BaseProcess { private readonly string _execPath; public IndependentProcess(ProcessCreationParams @params) { _execPath = @params.ExecutablePath; // 这里只用到自己需要的参数 } public override void Start() { // 启动独立进程逻辑 } } // 依赖进程子类 public class DependentProcess : BaseProcess { private readonly IntPtr _parentHandle; private readonly string _execPath; public DependentProcess(ProcessCreationParams @params) { _parentHandle = @params.ParentProcessHandle; _execPath = @params.ExecutablePath; // 用到父进程句柄和路径 } public override void Start() { // 依赖父进程启动的逻辑 } } // 工厂类 public static class ProcessFactory { public static BaseProcess CreateProcess(string fileExtension, ProcessCreationParams @params) { return fileExtension.ToLower() switch { ".exe" => new IndependentProcess(@params), ".dll" => new DependentProcess(@params), _ => throw new NotSupportedException($"不支持的扩展名:{fileExtension}") }; } }
这种方式的好处是:工厂接口始终稳定,后续新增子类只需要扩展参数对象(如果需要新参数)和工厂的switch分支,代码可读性也很强。
方案2:抽象工厂模式(适合复杂扩展场景)
如果你的系统后续可能会新增更多类型的进程,或者每个进程类型还需要配套的其他对象(比如进程配置器、日志器),抽象工厂会是更好的选择。
简单来说,先定义一个抽象工厂接口,每个具体工厂对应一种进程类型,负责创建该类型的实例并处理自己的构造参数:
// 抽象工厂 public interface IProcessFactory { BaseProcess CreateProcess(object[] args); } // 独立进程工厂 public class IndependentProcessFactory : IProcessFactory { public BaseProcess CreateProcess(object[] args) { // 这里明确要求参数是可执行路径 if (args.Length != 1 || args[0] is not string execPath) throw new ArgumentException("独立进程需要传入可执行路径"); return new IndependentProcess(execPath); } } // 依赖进程工厂 public class DependentProcessFactory : IProcessFactory { public BaseProcess CreateProcess(object[] args) { // 这里要求参数是父进程句柄和可执行路径 if (args.Length != 2 || args[0] is not IntPtr parentHandle || args[1] is not string execPath) throw new ArgumentException("依赖进程需要传入父进程句柄和可执行路径"); return new DependentProcess(parentHandle, execPath); } } // 工厂的注册表/调度器 public static class ProcessFactoryDispatcher { private static readonly Dictionary<string, IProcessFactory> _factories = new() { { ".exe", new IndependentProcessFactory() }, { ".dll", new DependentProcessFactory() } }; public static BaseProcess CreateProcess(string fileExtension, params object[] args) { if (!_factories.TryGetValue(fileExtension.ToLower(), out var factory)) throw new NotSupportedException($"不支持的扩展名:{fileExtension}"); return factory.CreateProcess(args); } }
这种方式把不同进程的创建逻辑完全解耦,每个具体工厂只关心自己的参数要求,后续扩展新进程只需要新增对应的工厂类和注册项即可。
方案3:委托注册表(灵活度拉满,适合小项目或快速迭代)
如果你的场景比较简单,不想写太多工厂类,可以用委托来实现动态注册。本质上是把创建实例的逻辑封装成委托,存在字典里:
public static class ProcessDelegateFactory { private static readonly Dictionary<string, Func<object[], BaseProcess>> _creationDelegates = new() { { ".exe", args => new IndependentProcess((string)args[0]) }, { ".dll", args => new DependentProcess((IntPtr)args[0], (string)args[1]) } }; public static BaseProcess CreateProcess(string fileExtension, params object[] args) { if (!_creationDelegates.TryGetValue(fileExtension.ToLower(), out var createFunc)) throw new NotSupportedException($"不支持的扩展名:{fileExtension}"); return createFunc(args); } }
这种方式代码量最少,但要注意类型安全——调用时必须传入正确类型和数量的参数,否则会抛出运行时异常。适合小项目或者快速验证想法的场景。
内容的提问来源于stack exchange,提问作者Rampartisan
相关产品推荐
相关产品推荐

