SOLID原则或非SOLID原则

5
我正在继续开发一个ASP.NET应用程序(基于Web表单),之前的开发人员没有遵循良好的面向对象设计原则,即SOLID(http://www.remondo.net/solid-principles-csharp-interface-segregation/)。我已经阅读了像这样的帖子:Long-held, incorrect programming assumptions
问题在于许多类的内聚性低且高度耦合,并且许多类没有单一职责(它们有许多职责)。我的具体问题是:我应该开始遵循SOLID原则还是只是继续通过调整和添加更多内容来开发类?我过去一直尝试遵循像SOLID这样的原则,但我所谈论的应用程序非常大且复杂。我是这个项目中唯一的开发人员。
目前完全重写是不可能的,但将来可能会有机会。

更新于15/07/2012 到目前为止,我发现SOLID是一种设计原则,而GRASP是一种设计模式,可能更适合于MVC而不是页面控制器类型的应用程序。根据此链接,模拟对象也可能更适合于MVC:http://www.asp.net/mvc/tutorials/older-versions/overview/asp-net-mvc-overview。根据迄今为止的回答,遵循SOLID原则始终是一个好习惯。然而,到目前为止的答案并不推荐针对基于表单的应用程序使用设计模式。

4个回答

5

尝试逐步重构代码。

如果你正在处理一个模块,可以在编写新代码时逐渐添加一些接口。任何新的代码都应该遵循SOLID原则。尽可能地封装旧代码,将旧代码放在一个外观后面。你不需要立即重写它,也许永远不需要。只要你能够将旧代码封装在一个外观后面,并为外观编写单元测试,你就会感觉好多了。

例如:假设你有一个类集合,用于实现某个功能,如发票处理。现在我想象这些类被用在很多地方,存在很多重复代码。计算总发票金额的代码在每个显示页面上都被复制了。在这种情况下,我会创建一个发票服务,它将公开获取发票、添加新行、计算总金额等方法。然后,你可以将现有的代码放在这个服务中,而无需进行太多重构,你将保持相同的数据库架构等。但从现在开始,你的页面将只与IInvoiceService接口交互,你可以很好地模拟它。这有点像“把灰尘扫到地毯底下”,但至少你可以停止垃圾进一步传播。下次你需要在发票模块中做一些事情(修复错误、实现新功能),你可以稍微整理一下现有的代码。随着时间的推移,地毯下的灰尘越来越少。你只需要坚持自己的立场,并确保服务接口保持良好。

你可能需要进行一些更广泛的系统级更改,如引入DI框架,但尽量保持更改的最小化。通常当你开始走得太远时,你很容易发现自己在重写所有东西,你不想这样。

进行小的更改,经常提交。


+1 对于依赖注入框架的提及。我之前没有听说过这个。你能详细解释一下你所说的“将旧的垃圾隐藏在外观后面”是什么意思吗? - w0051977
更新了一个答案并附上了一个例子。 - Jakub Konecki
大部分的 .NET 代码都在一个地方。那里有 VB6 和 C++ 代码。这通常是重复的,即 VB6 代码出现在 .NET 应用程序中,而 C++ 代码则出现在 VB6 应用程序中。 - w0051977
我所做的研究表明,DI框架更适用于基于MVC的应用程序,而非基于表单的应用程序。 - w0051977
在我看来,无论你正在构建什么类型的应用程序,依赖注入(DI)都是提高代码可维护性的好方法。我已经成功地在MVC、WebForms、WinForms和Windows服务中使用了DI。 - Jakub Konecki

0

我曾在一家覆盖率良好的店铺工作过(超过3000个测试),编写测试代码鼓励我们的代码通常遵循SOLID原则。

我也曾在一家覆盖率为0%的店铺工作过(约50万行代码),几乎没有采用SOLID原则。

由于没有测试覆盖率,我们无法重构任何一半的代码(无论是为了SOLID还是其他任何原因)。因此,随着时间的推移,代码变得越来越难以维护。

在我的第一份工作中,我们不需要重构,因为代码已经是SOLID的,但我们可以轻松地重构并使用良好的单元测试代码覆盖率来确保没有回归。

这就像魔术:对于那些相信的人,无需证明;对于那些不相信的人,永远不会有足够的证据。

让我们这样说:你想要在一个代码极难理解、难以维护、开发人员因代码太差而离职、错误猖獗的地方工作吗?选择后者,始终如一,无论是SOLID还是其他,但在我看来,将SOLID和单元测试结合起来将使长期实现这一点更加容易。


0

这就像是在问:“我刚从别人那里买了一套公寓,但到处都很脏。我应该清理它还是保持原样?”

答案很明显。你说这个应用程序很复杂。如果它之所以复杂只是因为糟糕的架构 - 那么你就有机会让它更易懂。如果它之所以复杂是因为业务问题的本质,那么糟糕的架构只会让情况变得更糟。

SOLID原则非常重要。同时要注意GRASP指南,我想你也这样做了,因为你提到了低耦合和高内聚,这些属于GRASP而不是SOLID。

最明显的方法是逐步进行正确的重构。解耦类,定义它们的职责,使它们更加内聚,引入接口并针对它们编写代码。这比SOLID的开闭原则或Liskov替换原则更重要。


谢谢。你的第一句话确实有道理,但我认为这是一个优先事项。还有很多工作要做,优先任务是完成它。如果我有更多时间,我会重构所有的代码。 - w0051977
真的,优先级很重要。事实是,您的客户可能不太关心架构,他们只想要完成的东西。然而,您越长时间不整理这个混乱,您就越慢地引入新功能。如果您独自工作,则可能并不重要。但是,如果您身后有一个团队,则您所有人都有一个不想要的负担,会减慢您的速度。 - Wiktor Zychla

0

我的建议是选择一个功能并开始单元测试,引入Moq或FakeItEasy等模拟库。

我完全理解这是交接给你的代码。但是通过单元测试,您将了解哪些代码是单一职责的好候选者,哪些必须是服务或必须移动到存储库中。

您已经要实现DI,但使用像AutoMapper这样的东西可以节省大量时间,并使代码更小,更清晰

当我像您这样被交接时,我做的第一件事就是阅读Uncle Bob的书http://www.amazon.co.uk/Working-Effectively-Legacy-Robert-Martin/dp/0131177052,它会给您一些好的想法。

关于您的评论的更新: 在头3个月后,该应用程序的错误更少,并且实现新变更也稍微容易和快速。最好的部分是我们现在具备了领域知识。一个好处是阻止旧代码和新更改引起错误的是反腐层,请查看此链接 http://domaindrivendesign.org/library/peng_hu_2007_2


你的应用现在看起来怎么样?你已经在开发它多久了?谢谢。 - w0051977
我所阅读的资料表明,Mock库和DI更适用于基于MVC的应用程序,而不是Windows窗体。你同意吗?请参见此处:http://www.asp.net/mvc/tutorials/older-versions/overview/asp-net-mvc-overview - w0051977
@w0051977 这篇文章说MVC框架拥有所有的功能。 - HatSoft
这些功能不能在Web表单/Windows表单中使用吗?也就是说,表单中是否“包含所有功能”? - w0051977
是的,你可以使用这些独立的框架。Unity 用于依赖注入,NUnit 用于单元测试,Moq 用于模拟,AutoMapper 用于对象映射。 - HatSoft

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接