我有一个复杂的RIA客户端,它与WCF SOAP Web服务通信,第二个 a 是操作词。这导致了一个可怕的神类,到目前为止包含131 [OperationContract]方法,甚至还有更多的私有方法。
就个人而言,我对此没有任何问题;我使用Visual Studio的搜索和导航功能很容易找到我在课堂上的方式。然而,其他开发商正因此受苦。他们是慢慢滚动寻找事物的种类(看起来很烦人)。我把这个班级区分成几个部分,但我是唯一一个似乎享受这个好处的人(他们是看似更常见的#地区仇恨阵营)。
所以,为了对其他程序员好一点,也许享受一些我不知道的好处,我想重构怪物。这是我看到的选项:
我不喜欢这样做会破坏我的客户端代码。我必须重写它以使用新的代理类。另外,我还需要维护更多的WCF配置(哎呀!)。此外,可能存在共享私有方法所属的监护权争夺战。
这个想法似乎对我很有吸引力。我对这种方法的处理方法是让每个源文件(不是太多其中许多)代表Web服务的功能划分。例如:
MyService.svc.cs
MyService.AccountManagement.svc.cs
MyService.Preferences.svc.cs
MyService.MediaManagement.svc.cs
我对这种方法有点担心,因为在一家前公司,当我提出这种可能性时,一位开发人员说这是一个坏主意,因为一些模糊的“部分类有问题”的原因。我从来没有比这更好的解释,但我接受了他的话。
我认为复杂的Web服务创建诸如此类的神类并不罕见,因此必须有一些我不知道的良好实践方法。您可以使用哪些技术使您的Web服务类更容易上手?
感谢大家的意见。我希望我能接受不止一个答案。
我已经阅读了你的答案,与开发团队讨论过,现在,我们只是将服务重组为部分类。我将对其他建议发表评论,以解释为什么我不采取这些方法,至少目前是这样。你们都给了我一些有价值的东西来考虑未来的发展。
答案 0 :(得分:8)
嘿雅各布,不确定这是否能直接帮到你,但你提到了很多私人方法。
这告诉我你的WebService正在服务于两个角色,逻辑和接口......但事实上,它应该只提供一个,即接口的逻辑。
是否可以将尽可能多的逻辑移动到一个漂亮的命名空间类库中,只留下服务本身的最小方法?
<强>更新强>
关于你为什么要重构,和/或你应该如何设计你的类库,S.O.L.I.D principles中的一些原则可能对你有用。特别是:
检查上面的链接,它将包含所有原则的摘要。
这里有一些SO discussions。如果有人有更好的链接,请告诉我,欢呼
答案 1 :(得分:5)
如果您可以将服务重构为单独的部分类文件,每个文件都封装了一定数量的相关功能,您也可以将服务重构为封装此功能的单独类。您的服务将成为这些课程及其功能的简单外观。
有时候这是不可行的,并且会使事情进一步复杂化,但是你知道你的代码库是你在这里打电话的人。在这种情况下(在与分析师开发人员进行良好的头脑风暴会议之后),部分类文件仍然是更好的选择。
有一件事是肯定的。您的服务必须才能重构。 (编辑:代码不仅仅用于执行,也用于维护。如果很难找到解决办法,那肯定是无法维护的。)
关于部分类问题。我不认为这是一个有价值的评论,直到它被一些真实的事实支持为什么它们是一个问题。
关于重构
将您的服务视为Web应用程序用户界面。就像Web应用程序使用BLL类一样,它们的封装功能与整个解决方案的单个问题/方面有关,因此应该是您的Web服务。它应该是一个也使用BLL类及其原子功能的接口。它不是视觉界面,而是API。
答案 2 :(得分:4)
部分类选项听起来不错,因为它基本上为您提供了选项1的好处,同时保持了暴露接口的兼容性。我所知道的部分类没有真正的问题,VS在所有设计器文件中使用它们,如果出现问题也没有意义。
答案 3 :(得分:4)
重新分解建议:
您不必在一份服务合同中签订131份操作合同。将它们分解为每个功能区域的一个服务合同。您最终会在服务中使用多个端点,但这真的很重要吗?
将所有服务合同和数据合同放入“仅合同”程序集中。将实现类放入不同的程序集(或按功能细分的几个程序集)。将Web服务外观放入另一个程序集中,该程序集仅包含web.config
文件和许多指向实现类的空.svc
文件。
重新分解.svc
文件的示例,没有代码隐藏(因为“代码隐藏”在不同的程序集中):
<%@ ServiceHost Service="Fully.Qualified.Name.Of.Implementation.Class" %>
以这种方式拆分代码的额外好处是,您的客户端应用程序不必与svcutil.exe
和服务引用混淆。您可以直接引用合同程序集,并使用ChannelFactory<IContract>
来调用该服务。
这种结构的另一个好处是,一个服务实现类现在可以以与外部调用相同的一致方式在同一个程序集中调用另一个服务实现类,但没有通过WCF的开销。
答案 4 :(得分:2)
您的第一个选项当然值得考虑,但您对增加的部署开销是正确的。有131个操作的服务听起来像是它有太多的责任,但你是否认为这是一个问题取决于你的使用场景。如果服务仅存在 来为您的RIA客户端提供服务,这可能不是问题,因为它只是一个实现细节 - 基本上,使用SOAP的唯一原因是因为它是一个可互操作的传输机制。 p>
另一方面,如果您需要为其他客户端公开此服务,则它不是非常可组合的。如果是这种情况,我建议将服务分解为更易于管理的子部分。
无论您对服务界面做出何种决定,都应认真考虑将服务重构为更易于管理的内容。理想情况下,应该有一个域模型来实现服务的所有行为。这样的领域模型将由许多类组成,每个类都有各自独立的职责。然后,该服务将成为域模型的Facade。如果所有操作都是将其实现委托给域模型,那么131次操作并不是太难以管理。
关于你使用部分课程的建议,我不知道这会有什么帮助。如果您将当前的服务类任意分割为多个部分类,那么找到您正在寻找的内容将变得更加困难。
另一方面,如果您找到一些逻辑分组来订购您的部分课程,那么您已经在走向更深层次的模型。在这种情况下,为什么不将这些组封装到可以在真实的单独类中建模的概念而不是部分类?
无论如何,我同意罗伯特:服务必须重构。
答案 5 :(得分:0)
关于您的选择/评论:
选项1:我理解您的担忧,但您需要在某处画线。您不应该继续使用1000个操作服务继续使用,这次不是针对您的代码而是针对调用者。此外,可能有理由在您的方案中进行大量操作,只需确保避免使用繁琐的API,因为您实际上不希望在同一操作中进行多次往返。
选项2 +区域:正如你所说,你有应用程序的单独部分。那些不应该属于同一个类,命名一些模式并不会真正卖得好。查看这个系列,作为许多这些事情的旅程http://blog.wekeroad.com/category/mvc-storefront(从第1章开始) - 它对我帮助很大。你也可以在实体上查看这本电子书 - http://www.lostechies.com/content/pablo_ebook.aspx。目前正在进行的许多事情有很多理由,但它们中的任何一个都不能用一个吸引人的短语传播。
正如其他人所说,您的服务代码应该只是一个很小的层,可以转换为适当的服务格式和应用程序逻辑。考虑学习单元测试,当你使用这样的代码时,这些看起来很荒谬,因为它几乎阻止你使用它。这将不断提醒你/指出你的代码全部被束缚在哪里。