在整个应用程序中传递运行时参数

本文关键字:运行时 参数 应用程序 | 更新日期: 2023-09-27 18:33:36

我有一个遗留的C#库(一组相互关联的算法(,其中有一个传递给所有类的全局god对象。这个 god 对象(简称为 Manager :D(有一个参数成员和一个 ObjectCollection 成员(以及其他许多成员(。

public class Manager
{
    public Parameters {get; private set;}
    public ObjectCollection {get; private set;}
    ...
    ...
}

无法测试算法,因为一切都将管理器作为依赖项,初始化这意味着我必须初始化所有内容。所以我想重构这个设计。

参数中有 100 多个字段,这些值控制不同的算法。对象集合具有引擎整体执行所需的实体,按 Id、按名称等存储。

以下是我尝试但不满意的方法:

  1. 传递参数和对象集合(或IParameter和IObjectCollection(而不是管理器,但我认为这不能解决任何问题。我不知道算法将依赖于哪些参数。

  2. 将参数类拆分为较小的参数类也很困难,因为一个参数可能会影响许多算法,因此逻辑分离很困难。此外,每种算法的依赖关系最终可能会很多。

  3. 像这样的单例模式通常是为记录器完成的,但这也是不可测试的。

  4. 有些参数
  5. 控制算法逻辑,有些参数只是算法所需要的。我正在考虑使每个算法成为实现接口的单独类,并在应用程序启动时根据参数决定要实例化的算法。我最终可能会将当前的算法类集拆分为更多,我担心我最终会使其更加复杂并失去算法的结构。

是否有任何标准方法来解决这个问题,或者只是将大类拆分为较小的类并通过构造函数传递依赖项是唯一的一般建议?

在整个应用程序中传递运行时参数

为了让自己迈出一小步,我会从单一算法开始,并确定它所需的参数。然后可以在界面中公开这些,以便...

public interface IAmTheParametersForAlgorithm1 
{
  int OneThing {get;}
  int AnotherThing {get;}
}

然后,您可以更改Manager以便它实现该接口,并如 @marcel 的答案所示,直接在管理器上公开这些参数。

现在,您可以使用非常小的模拟或自分流来测试算法1,因为您无需初始化巨大的管理器即可运行测试。算法 1 不再知道它需要一个管理器对象。

public Manager : IAmTheParametersForAlgorithm1 {}
public class Algorithm1 
{
  public Algorithm1(IAmTheParametersForAlgorithm1 parameters){}
}

您可以一点一点地将其扩展到每组参数,并且处理小型的特定接口将允许您识别不同算法具有公共参数的位置。

public Manager : 
  IAmTheParametersForAlgorithm1, 
  IAmTheParametersForAlgorithm2, 
  IAmTheParametersForAlgorithm3, 
  IAmTheParametersForAlgorithm4 {}

这也意味着,当您识别其参数不再在其接口之外访问的算法时,您可以停止将 Manager 注入到这些算法中,从 Manager 中删除参数,并创建一个仅提供这些参数的新类。

这意味着,如果您无法花时间进行一项巨大的重大更改,则可以在进行此更改的整个过程中保持应用程序运行

对于参数,我会选择这样的东西:

public class Parameters
{
    public int MyProperty1 { get; set; }
    public int MyProperty2 { get; set; }
    public int MyProperty3 { get; set; }
}
public class AlgorithmParameters1
{
    private Parameters parameters;
    public int MyProperty1 { get { return parameters.MyProperty1; } }
    public int MyProperty3 { get { return parameters.MyProperty3; } }
    public AlgorithmParameters1(Parameters parameters)
    {
        this.parameters = parameters;
    }
}
public class Algorithm1
{
    public void Run(AlgorithmParameters1 parameters)
    {
        //Access only MyProperty1 and MyProperty3...
    }
}

用法如下所示:

var parameters = new Parameters()
{
    MyProperty1 = 4,
    MyProperty2 = 5,
    MyProperty3 = 6,
};
new Algorithm1().Run(new AlgorithmParameters1(parameters));

顺便说一句,我不明白控制算法和算法所需的参数之间有什么区别。通过控制,你的意思是它们被用来决定采用哪种算法?