Mit*_*h A 15 oop abstraction design-patterns dependency-injection inversion-of-control
我当前的应用程序允许用户通过一组管理屏幕定义自定义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
}
}
Run Code Online (Sandbox Code Playgroud)
一切都很好(一段时间).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
}
}
Run Code Online (Sandbox Code Playgroud)
一切都很好,平衡已恢复到力量.用户界面仍然不知道表格中的内容,我们的关注点分离得以实现.然而,仅仅几个星期之后,该业务就提出了一项新要求:在某些情况下,我们应该只应用上面提到的一些表单转换.
在这一点上,感觉就像"显式方法"方法已达到死胡同,除非我想最终爆发一些方法(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);
}
}
Run Code Online (Sandbox Code Playgroud)
从表面上看,这似乎是可接受的方法,但有一定的气味.也就是说,UI一直生活在关于OpenFormForViewing的实现细节的无知幸福中,必须拥有IFormViewCreator的知识并创建它的实例.
据我所知,您需要在将表单发送到UI层之前修改表单.这对我来说听起来就像装饰师一样.保留旧的IFormService接口,而不使用IFormViewCreator.
您现在可以创建一个或多个实现所需过滤或修改的Decorating FormService.
public class MyDecoratingFormService : IFormService
{
private readonly IFormService formService;
public MyDecoratingFormService(IFormService formService)
{
if(formService == null)
{
throw new ArgumentNullException("formService");
}
this.formService = formService;
}
public Form OpenFormForEditing(int formId)
{
var form = this.formService.OpenFormForEditing(formId);
return this.TransformForm(form);
}
public Form OpenFormForViewing(int formId)
{
var form = this.formService.OpenFormForViewing(formId);
return this.TransformForm(form);
}
public Form TransformForm(Form form)
{
// Implement transformation/filtering/modification here
}
}
Run Code Online (Sandbox Code Playgroud)
您现在可以使用一个或多个此类装饰器来装饰原始IFormService实现.
IFormService formService = new MyDecoratingFormService(new MyFormService());
Run Code Online (Sandbox Code Playgroud)
您可以根据需要将尽可能多的装饰器(每个都有自己的责任)包裹在一起.
没有明确需要DI容器来做到这一点,但它很适合其他DI模式.我一直都在使用Decorator :)
| 归档时间: |
|
| 查看次数: |
555 次 |
| 最近记录: |