3

大家好。我遇到了使用存储库和服务模型的奇怪设计模式。该应用程序由 ASP.NET MVC、WCF 和一些 Windows 服务组成。我的存储库正在使用 LINQ DataContext。随着我的应用程序的发展,我发现自己到处都在传递对 IWhateverService 服务的引用。例如,我有 IAccountService,它定义了诸如 ChangePlan(Account account, Plan plan) 之类的方法。

现在,似乎 IAccountService 是放置此方法的最佳位置,因为我们在这里为帐户提供服务。但是,ChangePlan 方法需要知道几件事才能真正更改计划。它必须知道用户的当前使用情况、可用计划列表、用于计费的电子商务服务接口的实例等。

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

因此,现在我发现自己为 AccountService 创建了一个巨大的构造函数,其中包含 IAccountRepository、IPPlanService、IUsageService、IEcommerceService 和 IValidationDictionary 的实例。这感觉根本不对。

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

此外,为了避免在需要的任何地方实例化服务,我创建了一个名为 ServiceFactory 的静态类,它具有静态方法、CreateAccountService、CreatePlanService 等……我在应用程序周围调用这些方法。看起来不错,但我无法摆脱这种不合适的感觉。

我的断线在哪里?有人有什么建议吗?

谢谢。

安德鲁

4

5 回答 5

5

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

SOLID 原则通常会接受您在实现中描述的非规范化,并且宁愿专注于让此类组件的每个外部用例都有自己的接口。

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

于 2009-04-19T05:31:12.503 回答
1

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

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

于 2009-04-19T04:33:38.617 回答
1

所以现在我发现自己为 AccountService 创建了一个巨大的构造函数,其中包含 IAccountRepository、IPPlanService、IUsageService、IEcommerceService 和 IValidationDictionary 的实例。这感觉根本不对。

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

此外,为了避免在需要的任何地方实例化服务,我创建了一个名为 ServiceFactory 的静态类,它具有静态方法、CreateAccountService、CreatePlanService 等……我在应用程序周围调用这些方法。看起来不错,但我无法摆脱这种不合适的感觉。

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

除非您的对象非常大或在构造过程中加载数据(它们通常不应该这样做),否则构造一个类的新实例需要的时间非常少,不应该担心。

于 2009-04-19T15:35:26.483 回答
0

I've been a little way down the same path as yourself on previous projects and I've yet to see a clean approach to solve the issue. I think the real answer is that SOA causes as many problems as it solves. The logic goes that by decoupling everything you can switch services and their implementations in/out easily. However, if the price that we pay for such a feature is code that turns into a spaghetti mess of interfaces, services, and injected dependencies then is the benefit worth the hassle - I say it's not.

My current approach to SOA is to approach with caution. We harvest services from conventionally written code once the the intent and implementation have settled down.

于 2009-04-19T10:30:49.023 回答
0

您可以创建接受执行底层操作所需接口的重载构造函数吗?例如:

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

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

于 2009-04-22T06:51:50.570 回答