2009-10-31 154 views
6

从不知道在哪里放置功能,如:创建一个Catch-All AppToolbox类 - 这是一个坏习惯吗?

String PrettyPhone(String phoneNumber) // return formatted (999) 999-9999 
String EscapeInput(String inputString) // gets rid of SQL-escapes like ' 

我创建一个Toolbox类,可作为不完全满足需要的其他类功能的仓库每个应用程序。我读过这样的类是糟糕的编程实践,尤其是糟糕的面向对象设计。然而,参考文献似乎更多的是个人设计师和开发人员的看法,而不是一个强有力的共识。所以我的问题是,一个全能的工具箱是一个糟糕的设计模式吗?如果是这样,为什么,还有什么替代方法?

回答

6

伟大的问题。我总是发现任何足够复杂的项目都需要“实用”类。我认为这只是因为面向对象编程的本质迫使我们将事物放置在一个整齐的结构化分层分类中,但这并不总是可行或合适的(例如,尝试为哺乳动物创建一个对象模型,然后将鸭嘴兽)。这是激励工作到aspect oriented programming(c.f. cross cutting concern)的问题。通常进入公用事业阶级的是交叉担忧的事情。

使用工具箱或实用程序类的一种替代方法是使用扩展方法为基元类型提供其他所需的功能。然而,陪审团仍然没有确定是否构成了良好的软件设计。

我对这个主题的最后一句话是:如果你需要的话,随它去吧,只要确保你不是更好的设计。当然,如果需要,你可以在以后重构。

1

这没有什么错。有一件事是试图把它分解成逻辑部分。通过这样做你可以保持你的智能清洁。

MyCore.Extensions.Formatting.People 
MyCore.Extensions.Formatting.Xml 
MyCore.Extensions.Formatting.Html 
0

我认为它在真实皱起了眉头的原因是因为“工具箱”可以成长,你将要调用一个函数每次装载一吨资源。

使用适用于实际类中的对象的方法也更优雅 - 只是更有意义。

这就是说,我个人不认为这是一个问题,但会避免它只是出于上述原因。

2

在这些例子中我会更倾向于延长字符串:

class PhoneNumber extends String 
{ 
    public override string ToString() 
    { 
     // return (999) 999-9999 
    } 
} 

如果你写下你需要这些功能的所有地方,你可以找出真正使用它,然后将其添加到相应的类。这有时可能很困难,但仍然是您应该瞄准的目标。

编辑:

如下指出的那样,你不能在C#重写字符串。我想指出的一点是,在功能属于这一操作是在一个电话号码的,这样是:

interface PhoneNumber 
{ 
    string Formatted(); 
} 

如果你有不同的格式,你可以交换******中国的实现,而不if语句乱抛垃圾代码,例如,

相反的:

if(country == Countries.UK) output = Toolbox.PhoneNumberUK(phoneNumber); 
else ph = Toolbox.PhoneNumberUS(phoneNumber); 

你可以使用:

output = phoneNumber.Formatted(); 
+0

问题是关于C#,而不是Java。无论如何,在.NET和Java中,String类是封闭的(最终使用Java) – 2009-10-31 03:19:42

2

我认为一个静态辅助类,想到的第一件事。这是很常见的,有些人甚至将其称为面向对象设计的一部分。然而,助手类最大的问题是它们倾向于成为一个大转储。我想我看到了这种情况发生在我参与的几个较大的项目上。你正在研究一个类,不知道该把这个和那个函数粘在哪里,所以你把它放在你的帮助类中。此时,你的助手不能很好地交流他们的工作。类名称中的'helper'或'util'本身并不意味着什么。我认为几乎所有的OO大师都提倡反对助手,因为如果你给予足够的思考,你可以很容易地用更多的描述性类来替换它们。我倾向于赞同这种方法,因为我认为帮手违反了单一责任原则。老实说,带上一粒盐吧。我对OOP有一点评论:)

+0

我倾向于在公共库中创建特定的帮助器。所以你没有看到一个包含IO辅助函数和字符串助手的通用助手类。但我确实有:IoHelper,StringHelper等等。这就是我如何得到我的'关注点分离'。 ;-) – 2009-10-31 08:58:31

1

我的经验是,效用函数很少发生孤立。如果您需要格式化电话号码的方法,那么您还需要验证电话号码和解析电话号码。遵循YAGNI原则,你肯定不想在实际需要之前编写这些东西,但我认为继续前进并将这些功能分离为单独的类是有帮助的。随着时间的推移,这些从单一方法到次要子系统的类别的增长将自然发生。我发现这是保持代码长期有组织,易于理解和可维护的最简单方法。

1

当我创建一个应用程序时,我通常会创建一个静态类,其中包含静态方法和属性,我无法确定将其他位置放在哪里。

这不是一个特别好的设计,但这就是一个重点:它给了我一个地方化一整套设计决策的地方,我还没有想到。一般而言,随着应用程序的增长并通过重构进行改进,这些方法和属性实际应该存在的地方就会变得更加清晰。毫不夸张地说,重构工具的状态是这样的,以至于这些改变通常不会特别痛苦。

我试过用另一种方式做,但另一种方式基本上是在我足够了解我的应用程序以正确设计对象模型之前实现对象模型。如果我做,我花了相当多的时间和精力提出了一个平庸的解决方案,我必须在未来某个时候从头开始重新审视和重建。好吧,如果我知道我将重构此代码,那么我怎么样跳过设计和构建不必要的复杂类的步骤,这些类并不真正起作用?

例如,我构建了一个正被多个客户使用的应用程序。我很早就想到,我需要有一种方法来分离需要针对不同客户以不同方式工作的方法。我构建了一个静态实用程序方法,我可以在程序中的任何位置调用一个自定义方法,并将其粘贴到静态类中。

这工作好几个月。但是有一点刚开始看起来很丑陋。所以我决定将它重构成它自己的类。在我查看所有调用此方法的地方的代码时,非常清楚,所有自定义方法确实需要成为抽象类的成员,客户的程序集需要包含单个派生类它实现了所有的抽象方法,然后程序只需要从配置中获取程序集名称和命名空间,并在启动时创建自定义要素类的实例。对于我来说,找到所有必须定制的方法非常简单,因为我需要做的就是找到每个地方,我的负载自定义功能方法被调用。我花了整整一个下午的时间来完成整个代码库并使这个设计合理化,最终的结果是非常灵活和强大,并且解决了正确的问题。

事情是,当我第一次实现该方法(实际上是三个或四个相关的方法)时,我意识到这不是正确的答案。但我不知道足够的答案是什么。所以我用最简单的错误答案去解决问题,直到正确的答案变得清晰。

0

我发表了评论,但认为我会详细阐述一点。

我所做的是创建一个带有命名空间的公共库:[Organization]。[Product] .Common作为根和子命名空间Helpers。

这里有几个人提到了创建一个班级和推动一些他们不知道放哪里的东西。错误。我会说,即使你需要一个辅助方法,它也与某些东西有关,所以创建一个正确命名的(IoHelper,StringHelper等)静态辅助类并将其放入Helpers命名空间中。那样,你会得到一些结构,你会得到某种分离的担忧。

在根名称空间中,可以使用需要状态的实例实用程序类(它们存在!)。不用说也可以使用适当的类名,但不要使用助手后缀。

相关问题