架构问题:我应该在哪个组件中放置哪个类,以获得干净的解决方案?

前言:

这是迄今为止我留在这里的最长的post……但我认为在这种情况下需要它。

很长一段时间我对这些事情都有疑问:如何命名程序集,以及如何在其中划分类。

我想在这里给出一个应用程序的例子,只有最少的类来演示我想要理解的内容。

想象一下这个应用程序

  • 接受客户端消息,将它们存储在数据库中,然后将它们出列到MTA服务器。
  • 它是一个Web应用程序,具有用于编写消息的ASP.NET接口+附加附件。
  • 还有一个Silverlight客户端,因此webapp使用一个OperationContract(SaveMessage)公开ClientServices WCF ServiceContract。
  • 还有一个Windows客户端……与Silerlight合同做同样的事情。

好。 这应该是一个虚假的场景来certificate我的无知。

以上将需要以下类:

  • 信息
  • MessageAddress
  • MessageAddressType(包含From,To的枚举)
  • MessageAddressCollection

  • MessageAttachment

  • MessageAttachmentType
  • MessageAttachmentCollection

  • MessageException

  • MessageAddressFormatException

  • MessageExtensions(Message的静态扩展)

  • MessageAddressExtensions(MessageAddress的静态扩展)
  • MessageAttachmentExtensions(MessageAttachment的静态扩展)

Project.Contract.dll

我将上述内容组织到正确的程序集中的第一步就是观察Message,MessageAddress,MessageAttachment,其属性所需的枚举(MessageAddressType,MessageAttachmentType)以及它们所需的集合(MessageAddressCollection,MessageAttachmentCollection)都将被标记为[DataContract]以便它们可以在WCF客户端和服务器之间进行序列化。 两者都很常见,我想我会将它们转移到一个名为Contract的中立共享程序集中。

Project.Client.dll

我需要服务器[ServiceContract]的客户端代理,它会引用Contract.dll中的类。

所以现在服务器,它也引用Project.Contract.dll现在可以保存从WCF客户端收到的序列化消息,并将它们保存到数据库中。

插件

接下来我会意识到我希望通过第三方插件(例如,病毒检查程序)将这些对象处理为服务器端…

但是插件应该只读取(仅)访问变量以检查变量,如果他们看到他们不喜欢的东西就抛出错误。

所以我会考虑回到从IMessageReadOnlyinheritanceMessage …但是在哪里放置那个接口?

Project.Interfaces.dll

如果我把它放在一个名为Project.Interfaces.dll的程序集中,这对于可以引用它但没有引用Contracts.dll的插件有效…但是现在客户端必须引用Contracts程序集和接口……听起来不是一个好方向……

重复对象

或者,我可以有两个Messages结构(并复制其他MessageAttachment等类)…一个用于从客户端到服务器(在Contracts.dll中)进行通信,然后使用第二个ServerMessage / ServerMessageAddress / ServerMessageAddressCollection服务器端,inheritance自IMessageReadOnly,然后看起来我更接近我想要的。 对于重复的对象,插件的访问受限,而Server BL等具有与其工作相关的类型的完全访问权限,而客户端具有不同但相同的对象……实际上……我们应该开始考虑它们由于不相同,我的头脑中更清楚的是对象就在那里与客户交谈,即合同/通信对象)……

网站用户界面

如果有两个不同的消息,它们现在有不同的属性……哪一个最适合用于支持ASP.NET表单? ServerMessage对象看起来最快(类型之间没有映射)…但是所有逻辑都已经针对客户端消息对象(具有不同的属性和内部逻辑)进行了解决。 那么我是否会使用ClientMessage,并将其映射到Servermessage,以便在不同的介质中保持各种UI逻辑相同? 或者我应该更喜欢映射,只是重写UIvalidation?

那么第三种情况,Silverlight …… Contracts程序集是一个完整框架程序集…… Silverlight无法引用(不同的框架/构建机制)….所以我在Silverlight端的程序集可能是完全相同的代码,但必须是一个不同的程序集。 这怎么办?

究竟要考虑什么作为DataContract?

最后……我发誓,接近我的大问题的结尾……那些不太明显DataContract的讨厌的额外课程怎么样?

例如,MessageAddress是DataContract。 好。 它暴露的枚举是它的一部分……有道理……但是如果messageAddress构造函数引发MessageAddressFormatException …它是否被认为是DataContract的一部分?

服务器,客户端和插件都可以使用通用的类吗?

或者它是BOTH ServerMessageAddress和ClientMessageAddress常见的exception,因此不应该重复,而是在Common程序集中……所以最终客户端必须绑定到Contracts AND Common? (我们不是只用接口组件走下这条小巷吗?)

常见的基类/接口怎么样?

这些例外是否应该有共同的基类? 例如… ClientMessageAddressException,ServerMessageAddressException,ServerMessageVirusException(来自插件)……我应该努力让它们 – 尽可能最好 – 所有都来自一个抽象的MessageException …或者是否有一个enheritence / reusse的时间只是不再适合争取的目标?

非常感谢您阅读本报告。

我是一名开发人员,在科技方面,我可以随心所欲……但是这些问题,我必须布置组件,架构,我自己,让我非常困惑……而且失去了我太多时间了,因为我自己开车,把东西从一个组件移动到另一个组件,看看哪一个是最合适的,虽然不是很确定我在做什么,并试图不获得循环引用……

所以 – 真的 – 感谢您的倾听,我希望能够通过描述如何干净地展示上述内容的人来阅读,希望能够表达如何通过它来思考未来的项目。

在花了10分钟编辑格式化问题之后,我仍然打算投票。 我无法阅读所有内容。

去拿一份


框架设计指南:可重用.NET库的约定,惯用语和模式(第2版)

作为一名建筑师,我已经了解到,第一次让事情变得非常完美并不会让人满意,完美是主观的。 重构,尤其是在程序集之间移动类,没有太大的成本。 听起来像你已经在逻辑和正确地思考问题了。 以下是我对您的一些问题的看法

问:我的数据合同类是否应该有只读合同?

最可能的插件根本不应该知道您的数据合同。 病毒检查程序可以使用字节数组,拼写检查程序,字符串和语言环境等。如果您要为插件创建通用接口层,则应该将共享的内容与插件特定的数据隔离开来。 这将允许您最大化其重用。 因此,我认为你在创建数据契约结构的接口方面会得到很少的回报,这些接口应该主要是几乎没有逻辑的笨拙的数据包实际上是接口本身。

问:我应该在我的ASP.NET应用程序中使用与Silverlight应用程序相同的数据协定类,还是直接使用服务器端类?

我会使用客户端消息对象,以便您可以从代码重用中受益。 对象创建相当便宜,我确信大多数映射都是一对一的。 它不是那么快,真实,但这不会成为您应用程序的瓶颈。

问:我在哪里放置我的exception类?

我会将您的示例exception类放在具有数据协定的程序集中,因为它们都是由于违反合同而提出的,或者是在履行合同时传达错误的方法。

问:例外是否有共同的基类?

我还没有必要这样做,但我不知道你的代码库。 我的猜测是,如果有的话它会带给你很少。

编辑:

你可能会为将来过度计划。 根据我的经验,采用YAGNI方法使我们能够更快地完成重要的事情。 进行增量设计更改是首选花费宝贵的时间来构建一个您可能永远不会从中受益的精细架构。