我的代码充满了服务接口!
大家好。 我使用存储库和服务模型遇到了一种奇怪的设计模式。 该应用程序由 ASP.NET MVC、WCF 和一些 Windows 服务组成。 我的存储库正在使用 LINQ DataContext。 随着我的应用程序的发展,我发现自己到处传递对 IWhateverService 服务的引用。 例如,我有 IAccountService ,它定义了 ChangePlan(Account account, Plan plan) 等方法。
现在,看来 IAccountService 是放置此方法的最佳位置,因为我们在这里为帐户提供服务。 但是,ChangePlan 方法需要了解几件事才能真正更改计划。 它必须知道用户当前的使用情况、可用计划列表、用于计费的电子商务服务接口的实例等。
我认为让 ChangePlan 方法接受 IAccountService 接口中的所有必需服务。 但这些其他服务的要求是实现问题,不应该成为接口定义的一部分。
所以现在我发现自己为 AccountService 创建了一个巨大的构造函数,采用 IAccountRepository、IPlanService、IUsageService、IEcommerceService 和 IValidationDictionary 的实例。 这感觉根本不对劲。
现在来看这个场景。 显然 IAccountService 包含一个通过 ID 检索用户帐户的简单方法: Account Get(int id) 有好几次我只需要调用此方法。 因此,我去创建我的 AccountService,它需要所有其他服务的实例(特别是 IValidationDictionary,我不需要对此进行验证)。 再次,这感觉不对。 我可以传递 null,但这只是因为我知道实现不会仅将它们用于此方法。
另外,为了避免在需要的地方实例化服务,我创建了一个名为 ServiceFactory 的静态类,它具有静态方法、CreateAccountService、CreatePlanService 等...我在应用程序周围调用这些方法。 看起来不错,但我无法摆脱这种不恰当的感觉。
我的断线在哪里? 有人有什么建议吗?
谢谢。
安德鲁
Hey all. I'm coming across a weird design pattern using the repository and service model. The application constists of ASP.NET MVC, WCF, and some Windows services. My repositories are using LINQ DataContext. As my application evolves I'm finding myself passing references to IWhateverService service everywhere. For example, I have IAccountService which defines methods such as ChangePlan(Account account, Plan plan).
Now, it seems like IAccountService is the best place to put this method since we're servicing accounts here. However, the ChangePlan method needs to know several things before it can actually change the plan. It has to know the user's current usage, the list of available plans, an instance to an ecommerce service interface for billing, etc.
I thought having ChangePlan method accept all of the required services in the IAccountService interface. But the requirement of these other services is a matter of implementation and shouldn't be part of the interface definition.
So now I find myself creating a huge constructor for AccountService taking an instance of IAccountRepository, IPlanService, IUsageService, IEcommerceService, and IValidationDictionary. This doesn't feel right at all.
Now take this scenario. Obviously IAccountService contains a simple method to retrieve a user's account by ID: Account Get(int id) There are several times when I just need to call this method only. So, I go to create my AccountService, and it wants instances of all these other services (especially IValidationDictionary, I'm not needing validation for this). Again, this feels wrong. I could pass null, but that's only becuase I know the implementation doesn't use them for just this method.
Also, to avoid instantiating the services everywhere I need them, I created a static class called ServiceFactory, which has static methods, CreateAccountService, CreatePlanService, etc... I call these methods around the application. The seems OK but I can't shake the feeling that this is improper.
Where's my disconnect here? Anyone got any suggestions?
Thanks.
Andrew
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(5)
您描述的设计似乎非常符合 SOLID 原则。 许多较小的组件通常也被认为是良好的设计。
SOLID 原则通常会接受您在实现中描述的非规范化,并且更愿意专注于让此类组件的每个外部用例都有自己的接口。
我认为您面临的主要问题是您花费了太多时间来思考如何构造这些对象。 您可能应该寻找一个依赖注入框架来处理这个问题,例如 Castle Windsor。 然后,您只需构建完整状态的对象,而不必担心所有依赖项不会被用于每个调用。
The design you are describing seems to be pretty much in line with the SOLID principles. A lot of smaller components is also generally considered to be good design.
The SOLID principles would generally accept the denormalization you're describing in the implementation, and would rather focus on letting each external use-case of such a component have its own interface.
I think the main problem you have is that you're spending too much time wondering how to construct these objects. You should probably be looking at a dependency injection framework to handle this, like Castle Windsor. Then you'd just construct the object in its full state and not worry about all the dependencies not being used for every call.
事件至少可以帮助您解耦其中的一部分。 您可以将需要验证计划更改的其他服务注册到 ChangePlanRequestEvent,让每个服务执行必要的验证,并在不允许更改时引发异常。 现在你遇到了问题。 计划的细节应编码在 Plan 对象中,除非您想显示可用计划,否则没有人需要可用计划的列表。
但为什么会有 AccountService 呢? 对我来说,为什么 ChangePlan 不是一种记账方法?
Events could help you decouple at least some of that. You could have the other services that need to validate a plan change register to a ChangePlanRequestEvent, have each service perform the necessary validation, and throw an exception if the change shouldn't be allowed. Now you have the problem. The specifics of the plan should be encoded in the Plan object and no one should need a list of available plans unless you want to display them.
But why is there an AccountService at all ? To me, Why isn't ChangePlan a method of account ?
像这样的依赖关系不应该是一个大问题。 您需要注意的是 AccountService 中的大量方法。 如果您的方法长达 100 行,那么可能是时候考虑重构并将 AccountService 分解为几个较小的服务了。
您可以使用控制反转容器消除对这些工厂的需求。
除非您的对象非常大或者在构造期间加载数据(它们通常不应该这样做),否则构造类的新实例需要花费极少的时间,并且不应该担心。
Dependencies like this should not be a huge concern. What you want to look out for are huge methods within your AccountService. If you have methods that are 100s of lines long then it might be time to look at refactoring and breaking AccountService up into a few smaller services.
You can use an Inversion of Control container to remove the need for these factories.
Unless your objects are very large or are loading data during construction (which they typically should not be doing) then constructing new instances of a class takes an infinitesimal amount of time and should not be something to worry about.
在之前的项目中,我已经沿着与您相同的道路前进了一点,但我还没有看到解决该问题的干净方法。 我认为真正的答案是 SOA 引起的问题和它解决的问题一样多。 其逻辑是,通过解耦一切,您可以轻松地切换服务及其实现。 然而,如果我们为这样的功能付出的代价是变成一堆意大利面条般的接口、服务和注入依赖项的代码,那么这种麻烦是值得的——我说事实并非如此。
我目前对 SOA 的态度是谨慎对待。 一旦意图和实现确定下来,我们就会从传统编写的代码中获取服务。
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.
您可以创建接受执行底层操作所需的接口的重载构造函数吗? 例如:
帐户服务中的方法可以在对其进行操作之前断言特定接口引用不为空。
Can you create overloaded constructors that accept interfaces you need to perform the underlying operation? For example:
The methods in the account service can then assert that a particular interface reference is not null before operting against it.