【发布时间】:2010-01-27 23:36:41
【问题描述】:
我当前的应用程序允许用户通过一组管理屏幕定义自定义 Web 表单。它本质上是一个 EAV 类型的应用程序。因此,我无法对 HTML 或 ASP.NET 标记进行硬编码来呈现给定页面。相反,UI 从服务层请求一个 Form 对象的实例,而后者又使用多个 RDMBS 表构造一个。表单包含您希望在这种情况下看到的类:Form=> IEnumerable<FormSections>=>IEnumerable<FormFields>
服务层如下所示:
public class MyFormService: IFormService{
public Form OpenForm(int formId){
//construct and return a concrete implementation of Form
}
}
一切都很好(有一段时间)。 UI 并不知道给定表单中存在哪些部分/字段:它很高兴地将接收到的 Form 对象呈现到功能性 ASP.NET 页面中。
几周后,我收到了业务的新要求:查看不可编辑(即只读)版本的表单时,应将某些字段值合并在一起,并应添加其他人为/计算的字段.我说没问题。只需修改我的服务类,使其方法更明确:
public class MyFormService: IFormService{
public Form OpenFormForEditing(int formId){
//construct and return a concrete implementation of Form
}
public Form OpenFormForViewing(int formId){
//construct and a concrete implementation of Form
//apply additional transformations to the form
}
}
再次一切正常,力量恢复平衡。 UI 继续不知道表单中的内容,并且实现了我们的关注点分离。然而,仅仅短短几周后,业务就提出了一个新要求:在某些情况下,我们应该只应用我上面提到的一些表单转换。
在这一点上,感觉“显式方法”方法已经走到了尽头,除非我想以爆炸式的方法结束(OpenFormViewingScenario1、OpenFormViewingScenario2 等)。相反,我介绍了另一个级别的间接:
public interface IFormViewCreator{
void CreateView(Form form);
}
public class MyFormService: IFormService{
public Form OpenFormForEditing(int formId){
//construct and return a concrete implementation of Form
}
public Form OpenFormForViewing(int formId, IFormViewCreator formViewCreator){
//construct a concrete implementation of Form
//apply transformations to the dynamic field list
return formViewCreator.CreateView(form);
}
}
从表面上看,这似乎是可以接受的方法,但有一定的气味。也就是说,一直生活在对OpenFormForViewing的实现细节一无所知的UI中,必须拥有IFormViewCreator的知识并创建一个实例。
- 我的问题有两个: 更好的方法来实现 我追求的可组合性? (也许通过 使用 IoC 容器或家庭 轧制工厂创建 具体的 IFormViewCreator)?
- 我是不是彻底搞砸了 抽象在这里?
【问题讨论】:
-
我同意你对气味的看法。似乎 UI 不必了解 IFormViewCreator。给你一个问题:用户界面是否知道你应该返回哪个“风味”的参数? UI 传递一个对象可能更有意义,该对象用作确定要应用哪些转换的各种值的容器。然后,您的 OpenFormForViewing() 方法将负责转发到工厂类,或明确找出要返回的“风味”。
标签: design-patterns oop dependency-injection inversion-of-control abstraction