我的代码充斥着服务接口!

时间:2009-04-19 04:11:26

标签: c# asp.net-mvc service repository-pattern

嘿所有人。我使用存储库和服务模型遇到了一种奇怪的设计模式。 ASP.NET MVC,WCF和一些Windows服务的应用程序组成部分。我的存储库正在使用LINQ DataContext。随着我的应用程序的发展,我发现自己在任何地方都传递了对IWhateverService服务的引用。例如,我有IAccountService,它定义了ChangePlan(帐户帐户,计划计划)等方法。

现在,似乎IAccountService是放置此方法的最佳位置,因为我们在此处为帐户提供服务。但是,ChangePlan方法在实际更改计划之前需要了解一些事情。它必须知道用户的当前使用情况,可用计划列表,用于计费的电子商务服务界面的实例等。

我认为让ChangePlan方法接受IAccountService接口中的所有必需服务。但是这些其他服务的要求是实现的问题,不应该成为接口定义的一部分。

所以现在我发现自己为AccountService创建了一个巨大的构造函数,它采用了IAccountRepository,IPlanService,IUsageService,IEcommerceService和IValidationDictionary的实例。这根本感觉不对。

现在采取这种方案。显然,IAccountService包含一个通过ID检索用户帐户的简单方法:Account Get(int id)有几次我只需要调用此方法。所以,我去创建我的AccountService,它想要所有这些其他服务的实例(特别是IValidationDictionary,我不需要验证)。再次,这感觉不对。我可以传递null,但这只是因为我知道实现不会将它们用于此方法。

另外,为了避免在我需要的地方实例化服务,我创建了一个名为ServiceFactory的静态类,它有静态方法,CreateAccountService,CreatePlanService等......我在应用程序周围调用这些方法。似乎还可以,但我不能动摇这种不合适的感觉。

我的断线在哪里?有人有任何建议吗?

感谢。

安德鲁

5 个答案:

答案 0 :(得分:5)

您所描述的设计似乎与SOLID原则非常吻合。许多较小的组件通常也被认为是良好的设计。

SOLID原则通常会接受您在实现中描述的非规范化,而是专注于让这样一个组件的每个外部用例都有自己的接口。

我认为你遇到的主要问题是你花了太多时间想知道如何构建这些对象。您可能应该查看依赖注入框架来处理此问题,例如Castle Windsor。然后你只需构造完整状态的对象,而不用担心每次调用都没有使用所有依赖项。

答案 1 :(得分:1)

事件可以帮助你解耦至少其中的一部分。您可以将需要验证计划更改寄存器的其他服务更改为ChangePlanRequestEvent,让每个服务执行必要的验证,如果不允许更改则抛出异常。现在你遇到了问题。计划的细节应该在Plan对象中编码,除非您想要显示它们,否则任何人都不需要可用计划列表。

但为什么会有AccountService呢?对我来说,为什么ChangePlan不是一种帐户方法?

答案 2 :(得分:1)

  

所以现在我发现自己创造了一个巨大的   AccountService的构造函数   IAccountRepository的一个实例,   IPlanService,IUsageService,   IEcommerceService,和   IValidationDictionary。事实并非如此   感觉很对。

这样的依赖关系不应该是一个巨大的问题。您想要注意的是AccountService中的大量方法。如果您的方法长达100行,那么可能是时候考虑重构并将AccountService分解为几个较小的服务。

  

另外,要避免实例化   我需要的地方服务,我   创建了一个名为的静态类   ServiceFactory,它有静态   方法,CreateAccountService,   CreatePlanService等...我称之为   应用程序周围的方法。该   似乎没事,但我无法摆脱这种感觉   这是不合适的。

您可以使用Inversion of Control container来消除对这些工厂的需求。

除非您的对象非常大或在构造期间加载数据(他们通常不应该这样做),否则构建类的新实例需要花费极少的时间,不应该担心。

答案 3 :(得分:0)

在以前的项目中我和你一样走了一条路,我还没有看到一个干净的方法来解决这个问题。我认为真正的答案是SOA会导致尽可能多的问题。逻辑认为,通过解耦所有内容,您可以轻松地切换服务及其实现。但是,如果我们为这样一个功能付出的代价就是变成接口,服务和注入依赖关系的意大利面条的代码,那么这个好处值得麻烦 - 我说它不是。

我目前对SOA的态度是谨慎对待。一旦意图和实施结束,我们就从传统编写的代码中获取服务。

答案 4 :(得分:0)

您是否可以创建接受执行基础操作所需接口的重载构造函数?例如:

AccountService(IAccountRepository)
AccountService(IAccountRepository, IPlanService)
AccountService(IAccountRepository, IPlanService, IUsageService, IEcommerceService,IValidationDictionary)

然后,帐户服务中的方法可以在对其进行操作之前声明特定接口引用不为null。