类是你java程序中的建筑模块。如果这些建筑模块不健壮,那么你的建筑(这里说的是你的应用程序)将会面在未来掉入痛苦的深渊。这基本上意味着当程序扩展的时候那些写的不好模块会导致你陷入非常困难的境地,或者程序在无论是生产还是维护方面将面临必然的设计问题。
另一方面相比而言一系列拥有良好设计的类可以加快编码的速度,而且还会减少bug的数量。
在这篇文章中我将会列出5个最值得推荐的设计原则。当写类的时候你应该将他们时刻记在脑子里。这些设计的原则的简称叫做SOLID。下面的表格当中同样列出了最佳实践让你能够模仿的去设计你的类。
下面让我们一个一个的、深度的讨论他们。
单一职责原则
这个原则的名字是在说“一个类应该有且只有一个职责”
换句话说你写一个类或者改变一个类,异或维护一个类都只是为了一个目的。如果这个类是一个model类那么它应该严格的只代表一个角色或者实体。这将给你未来的编码工作带来灵活性,从而不必担心改变另一个实体的时候影响这个类。
相似的如果你写service层或者manager层的类,那么它应该包含唯一的他的哪一部分方法,其他的功能都不应该包括。不要将实用的全局的方法关联到模块上去,最好将他们分开放到全局的另外一个可以访问的类文件中(Util类?)。这将帮助你保持明确的目的去维护这个类,而且你可以决定这些类是否只是被特殊的模块看到。
开闭原则
这是第二个重要的规则,而且这个原则是你在设计系统的时候要时刻保持在脑子里面的。它是这么说的
“软件的组件应该对扩展开放,但是对修改关闭”
这是什么意思呢?这里的意思是你的类应该被设计的这样:无论什么时候后面的开发者因为特殊的情况想改变控制流程,所有他们要做的工作是而且只能是扩展你的类以及重载你的一些方法。
如果其他的开发者由于你之前类的设计不能将自己的设计按照他所想的那样放到你的类中,那么你应该考虑改变你的类。这里我不是说任何人可以改变你的类整个的逻辑,但是他应该有能力去通过一种无害的被软件允许的方式重载一些软件所提供的选项。
例如你看到的任何一个好的框架,比如struts或者spring。你可以不改变他们的核心逻辑以及请求处理的细节,但是你仍然可以通过扩展一些类,然后把你自己的类通过配置文件注入的方式插入到系统当中去完成你想要做的事情。
里氏替换原则
这个原则是前面讨论过的开闭原则的一个变种。他这样描述
“衍生出来的类型必须可以完全替代他们的基础类型”
这意味着后来的开发者们通过扩展你的类而获得的新类应该能够符合应用的需要并且没有错误。举个例子来说,如果一个后面的开发者通过蹩脚的方式扩展了你的类的一些地方,然后把这个新的类注入到框架或者应用当中,尽管是这样这个类也不应该使得应用被中断或者抛出明显的异常。
通过遵守第一条原则可以严格的保证这条这一条规则成立。如果你的基础类只是做一件事情,退一万步讲后面的开发者只会将这个拥有唯一特性的类重载错误。这将引起一些错误但这仅仅是在一个小范围内,这个错误并不会导致整个应用的崩塌。
接口隔离原则
这个原则是我最喜欢的原则。他是适用于接口的单一职责原则。他这样描述
“客户端不应该被强制的实现那些不会被用的方法”
举个例子。开发者A创建了一个报表接口,然后加入两个方法分别生成Excel和PDF。现在有一个类要实现这个接口,但是他只是打算要使用生成PDF的那个功能。他会简单的实现这个功能么?
不,他不得不实现两个方法,其中的一个是软件设计者强加给他的多余的负担。实现者要么实现Excel这个方法要么将这个方法留置为空白方法,这些做法都不是理想的解决方案。
那么真正的解决办法是什么呢?那就是把当前的这个接口一分为二,变成两个接口。上面的例子中应该是这样的:PDF报表接口和Excel报表接口。这样当用户仅仅需要一个功能的时候将给他们提供灵活的选择。
依赖倒转原则
开发者中的大部分人已经熟悉这个原则中的名词,他是这样说的
“依赖抽象,不要依赖实现”
换句话说,你应该这样设计你的软件:各种模块被抽象的层所分开,同时也被这样的层所绑定到一起。这条原则的经典用法是BeanFactory和spring框架。在spring框架中所有的模块以彼此分开的模式被提供,但是他们可以通过简单的注入来一起工作。而且各个组件之间的界限很接近,以至于你可以在其他的软件模块当中很简单的使用它们。
这样的目标已经靠依赖倒转以及开闭原则实现了。所有的模块被暴露的仅仅是抽象的有用的部分,这些组件在扩展功能以及为其他模块当做插件方面是非常有用的。
以上这些就是五项经典的类设计的原则,这些原则是你在设计系统时候的最佳实践,如果你有意见或者更好的想法欢迎随时沟通。