设计视角:静态方法与类

时间:2010-01-08 18:10:52

标签: c# asp.net static-methods

虽然这是一个相当普遍的问题,但我正在努力解决它的最佳方法(如果在这种情况下需要接近它)。

我继承了一个网站(ASP.NET,C#),其中一部分包含一个充满静态方法的类(老实说,这是一个非常大的类)。一种方法特别是用于发送电子邮件。它具有我能想到的所有可能参数,并且运行良好。然而,由于所有内容都被推入内部 - 特别是在不使用大多数参数的情况下,该特定方法的内部构造相当麻烦以进行管理和理解。此外,由于这一方法的所有参数,再次处理错误有点困难。

实际拥有一个在您想要发送电子邮件时实例化的EMail类会更有意义吗?这对我来说“感觉”更合适,但我无法完全解释原因。对于这种特殊情况,您有什么想法?一般来说怎么样?

感谢。

5 个答案:

答案 0 :(得分:5)

你所描述的内容听起来像是格言的一个例子,“你可以用任何语言写FORTRAN。”

一个充满静态方法的大型课程通常(并不总是)表明有人没有“获得”OOP,陷入程序编程思维模式并试图扭曲语言来做他想做的事情。

根据经验:如果任何方法,静态或实例,需要超过大约5个参数,这通常表明该方法试图同时做太多事情,并且是重构为一个的好方法或更多课程。

另外,如果静态方法没有真正相关,那么它们应该至少分成实现相关功能的类。

我实际上想知道为什么你会有一个“发送电子邮件”方法,因为System.Net.Mail命名空间几乎可以处理所有情况,并且可以通过app.config / web进行配置。配置文件,因此您不需要传递服务器名称或端口。这是一种“通知”方法 - 单个页面应该调用的方法,以便根据填写了各种值的模板发送几条“标准”消息之一,并自动添加某些页眉/页脚?如果是这样,这种类型的交互有许多设计比你似乎继承的更容易使用。 (即MailDefinition

更新:现在看到您的评论,这是用于异常处理,我认为最合适的解决方案是实际的异常处理程序。这方面有大量资源。对于ASP.NET WebForms,我实际上拿了几年前Jeff Atwood写的那个,把它移植到C#并进行了一些更改(比如忽略404错误)。 this previous question中有许多好的链接。

这些天我的偏好只是将异常处理(以及随后的异常报告的电子邮件)视为日志记录的子集。 log4net有一个非常强大的SmtpAppender,您可以将其配置为仅用于“致命”错误(即未处理的异常 - 在您的处理程序中,您只需进行LogFatal调用)

重要的是,你无疑会从上面的SO链接和任何引用的链接中获取,这里实际上有两个反模式 - “杂项”静态类,以及捕获异常你不知道如何处理。这在.NET中很糟糕 - 在大多数情况下,您应该只捕获可以从中恢复的特定于应用程序的异常,并让所有其他异常冒出来,在必要时安装全局异常处理程序。

答案 1 :(得分:4)

一般来说,这是Microsoft guidelines for when to use static types

我想补充一些事情:

  • 必须使用静态类型来编写扩展方法。
  • 静态类型可以使单元测试变得困难,因为它们很难/不可能模拟。
  • 静态类型强制执行不变性和引用透明函数,这可能是一个很好的设计。因此,将它们用于设计为不可变且没有外部依赖性的事物。例如,System.Math
  • 有些人认为(e.g.)单身人士模式是一个坏主意。无论如何,将静态类型视为单身人士是错误的;他们比那更广泛。

这种特殊情况有副作用(发送电子邮件),似乎不需要扩展方法。所以它不适合我所看到的静态类型的有用情况。另一方面,使用对象将允许模拟电子邮件,这将有助于单元测试。所以我认为你说静态类型在这里是不恰当的。

答案 2 :(得分:3)

哦,天哪,是的。

这听起来像是一个旧的经典ASP应用程序已被移植。

违反了single responsibility principle。如果你能重构那个类。使用重载来执行该功能。

答案 3 :(得分:2)

这是Utils anti-pattern的一个例子。

根据他们的责任分开这些方法总是一个好主意。创建电子邮件类绝对是一个好主意™。它将为您提供更好的界面,并允许您在测试中模拟电子邮件。

答案 4 :(得分:0)

参见 The Little Manual of API Design ,它描述了具有最小构造函数和大量getter / setter的类相对于使用具有许多参数的构造函数/方法的替代方案的好处

由于您提到的方法的大多数参数都没有使用,更好的方法是使用简单的构造函数,为内部变量设置合理的默认设置。使用setter方法后,您可以设置需要非默认值的少数参数(并且只有那些参数)。