我发现自己在多个解决方案之间犹豫不决,但当涉及到封装某些功能时,从来没有找到我完全满意的东西。
这在我最近的桌面GUI项目中尤其成问题,我想概括一个功能,它封装了一组定义良好的视图以及一些逻辑,但是一个视图必须被"注入",并且可以采用多种形式,这在很大程度上取决于用户。为此,我为视图定义了一个接口,该接口可以通过构造函数传递。
进程由用户启动,完成后通过回调将结果返回给调用者。
接口:
interface ICustomMecPathViewModel : IScreen, IMecPathViewModel
{
public Dictionary<string, object> getStepResult(); //subview must return its result
public void Reload(Dictionary<string, object> preset); //subview will be reloaded for each new iteration
}
构造函数:
public PreparePathViewModel(ILogger logger, IConfiguration config, ICustomMecPathViewModel customParameterViewModel, ITool tool, Action<MecPathModel> callback)
{ ... }
这里的问题是这个过程包括多个步骤,并且实现ICustomMecPathViewModel的视图可能需要对这些步骤进行不同的配置。我在这里看到了两个解决方案,并努力寻找最佳答案(也许两者都没有?)
或者我可以传递一些非常通用的东西,例如字典列表(允许根据步骤进行各种配置的列表),没有类型限制,因为它是我的预设值:
List<Dictionary<string, object>> settings
或者我可以传递一个定义精确设置的接口列表,每次添加新配置时添加新元素:
List<IStepSettings>
第一个解决方案是不令人满意的,因为缺少类型检查,而后者可能成为一个带有许多随机内容的界面,这些内容之间没有一致性,这感觉是错误的。(它不会像一般的API那样广泛)
由于这个原因,我认为第一个解决方案更好。我的想法是:泛化是有代价的,就是这样。
你觉得怎么样?这种设计有什么问题吗?还有更好的解决方案吗?
我为我的具体情况找到了一个令人满意的解决方案。它超出了最初问题的范围,但它带来了答案的元素。
一些关于模块状态的信息可以提供给被注入的视图,视图可以自己决定做什么。
只需要简单的接口修改:
interface ICustomMecPathViewModel : IScreen, IMecPathViewModel
{
public Dictionary<string, object> getStepResult(); //subview can return its result for each iteration
public void Reload(Dictionary<string, object> preset, MecPathModel moduleState); //subview will be reloaded for each next iteraction
}
这个设计对我来说似乎更合适!
然而,最初的问题仍然悬而未决:是否应该不惜一切代价避免我最初的计划?在任何情况下都可以吗?