design-patterns - 这是 IOC 的典型用例吗?

标签 design-patterns oop dependency-injection inversion-of-control abstraction

我当前的应用程序允许用户通过一组管理屏幕定义自定义 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 层。这听起来像是 Decorator将到位。保留没有 IFormViewCreator 的旧 IFormService 接口(interface)。

    您现在可以创建一个或多个 Decorating FormService(s) 来实现所需的过滤或修改。

    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
        }
    }
    

    您现在可以使用一个或多个这样的装饰器来装饰您的原始 IFormService 实现。
    IFormService formService = new MyDecoratingFormService(new MyFormService());
    

    您可以根据需要将任意数量的装饰器(每个都有自己的责任)包裹在彼此周围。

    没有明确需要 DI 容器来执行此操作,但它非常适合其他 DI 模式。我一直使用装饰器:)

    关于design-patterns - 这是 IOC 的典型用例吗?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/2151188/

    相关文章:

    sockets - 实现客户端服务器 GUI 应用程序的正确方法

    javascript - 高级原型(prototype)函数

    java - 创建方法与工厂方法

    unit-testing - 如何在函数式编程中编写好的单元测试

    java - 使用 DAO 模式访问 Web session

    javascript - 子类互相覆盖对方的方法

    c++类成员返回奇数

    c# - 构建灵活且可重用的类层次结构

    angular - 如何将带有参数化构造函数的服务注入(inject)组件 - Angular

    具有依赖关系的子 ViewModel 的 WPF/MVVM 导航