2012-02-09 54 views
3

我们的客户拥有一个庞大的遗留系统,正在从.NET 1.1升级到.NET 4.0。除此之外,还将把底层框架移植到WCSF 2010用于Web应用程序,以及Enterprise Library 5.0或Iou1作为基础企业框架。除了这些框架外,还有DI设施。在传统应用系统中应用DI实践

WCSF有效地强制MVP和模块设计依赖于ObjectBuilder及其属性,因此Web应用程序升级遵循该模式。

Web应用程序在应用程序层(通过WCF)使用额外的应用程序服务。由于底层框架已经成为企业库,Unity应用程序块已经“免费滑入”了。但是现有的编码风格仍然是传统的,因此与web层不同,它没有从根本上切换到DI。

在应用层的典型层

  • 商业门面(BF) - 公众公开粗粒度的业务功能,控制交易。
  • 业务组件(BC) - 由门面方法协调的粒度逻辑组件,用于执行事务中的实际工作。
  • 数据访问(DA) - 阅读业务组件/写数据

为什么我的风格上面提到的仍然是旧的,因为各层之间的服务通信发生在通过传递数据集(他们是巨大的)通过网络。这个DataSet被传递给每个对象的构造函数。例如。伪代码

BF.SomeExposedMethod(StrongTypeDS ds) 
{ 
    this.BeginTransaction(); 
    BizComp bc = new BizComp(ds); 
    bc.ShareTransaction(); 
    bc.DoWork(); 
    this.CommitTransaction(); 
} 

BC.DoWork() 
{ 
    DataAccess da = new DataAccess(this.transaction, this.ds); 
    // perform work 
    da.SaveWork(this.ds); 
} 

更重要的是这些类的构造是基于它们的父抽象类的风格;他们期望在实例化时接收数据集。

我一直在阅读马克塞曼的DI在NET书和各种其他公共互联网来源有关DI问题。从所有这些讨论中,我似乎都明白,DI看起来不错,它准备好了准备开展工作的清洁对象的图表。清理我的意思是清空上下文数据。这些遗留代码模式的构造函数从一开始就期望正确的工作数据和上下文。

如果我正确理解Composition Root的原则,则必须重新设计构造函数和方法,以便通过属性传递上下文DataSet。我不清楚DI容器(在这种情况下,Unity是如何)可以自己弄清楚DataSet注入的内容。当然,它不能是一个全新的DataSet。在这个开发阶段(我没有直接参与这个项目,但是从旁边支持),我将无法建议对实例化Facade对象之前的WCF实现进行基本更改,使其成为Composition Root。

此外,我还没有收集关于DI如何适用于基于运行条件实例化对象的重要建议?根据数据的执行状态,可能会实例化其他对象,并且类型可能因数据类别而异。这似乎是在这个应用程序中引入某种级别的DIP和DI实践的最简单方法,就是将Unity容器作为服务定位器使用;只根据需要在执行时抓取实例。

UPDATE来回答

基于马克·塞曼的建议,我已经制作了以下POC

BF有统一的容器。虽然我成功地尝试了Unity.Wcf包,但我也对每个BF都做了第二个最接近的事情,一个Composition根,其中每个Facade方法将调用容器来解析执行该方法工作所需的对象图。 (这是更现实这种环境下可能会选择给情景模式。)

static ExampleBF() 
{ 
    container = new UnityContainer().LoadConfiguration(); 
} 

BF得到了解决IBCFactory,这将实例化一个具体的BC与通过现场上下文数据。

DataSet IExampleService.GetProducts(DataSet ds) 
{ 
    IExampleBC bc = container.Resolve<IBCFactory>().CreateBC(ds); 
    // GetProducts() takes no parameter because DataSet already passed in on construction. 
    return bc.GetProducts(); 
} 

BCFactory通过构造器注入接收IDACFactory。它交给每个实例化的BC。

public BCFactory(IDACFactory DACFactory) 
{ 
    this.DACFactory = DACFactory; 
} 

IExampleBC IBCFactory.CreateBC(DataSet ds) 
{ 
    return new ExampleBC(this.DACFactory, ds); 
} 

BC将依靠IDACFactory为其提供DAC。

DataSet IExampleBC.GetProducts() 
{ 
    IExampleDAC dac = this.dacFactory.CreateDAC(this.ds); 
    return dac.GetProducts(); 
} 

DACFactory类似地基于上下文数据实例化DAC。

IExampleDAC IDACFactory.CreateDAC(DataSet ds) 
{ 
    return new OrderDAC(ds); 
} 

当然的代码库的复杂的现实情况是幅度较大的方式,但这个简单的例子应该展示DI概念,他们希望就足够了。

回答

3

据我了解有问题的类的描述,他们听起来更像是数据载体(实体,如果你愿意)比服务。如果这是真的,那是not the responsibility of the Composition Root to compose data objects

但是,如果您必须根据运行时条件解决服务问题,则可以使用Abstract Factory is the universal solution

由于您正在使用遗留代码库,因此我想推荐本书Working Effectively with Legacy Code,该书提供了有关如何解耦紧密耦合的遗留代码库的重要指导。

+0

我确实有这本书,但并没有像书中那么深入。我不“拥有”代码库,因此对它没有真正的权威;我只能研究现有的模式并提出建议。在审查中,我越来越意识到单靠DI是不足以改进这些代码结构的;看起来这将是一个漫长的旅程。 :-) – icelava 2012-02-10 03:14:09

+0

真正的实体和数据对象是数据集;所有这些业务类都处理DataSet中的数据。 – icelava 2012-02-10 03:24:26

+0

从您的建议更新状态,谢谢。 – icelava 2012-02-14 03:00:08