如何写优质的JAVA代码

 
  整洁的代码不一定是好代码,但好代码一定是整洁的,整洁是好代码的必要条件。好的代码一定是高内聚低耦合的,是为了让程序新加功能尽可能对以前的代码进行修改,对修改关闭,对扩展开放,也一定是可读性强、易维护的。

以Java代码为例:

1.变量命名:

  大到项目名、包名、类名,小到方法名、变量名、参数名,甚至是一个临时变量的名称,其命名都是很严肃的事,好的名字需要斟酌。
 
名副其实:好的名称一定是名副其实的,不需要注释解释即可明白其含义的。一般内部变量m开头,例如mPersonNumber。
 
常量全大写。所有常量都要先定义,任何常量都要先定义,提高可读性。
例如: if( mPersonNumber > 40) 要先定义常量
private int MIN_PERSON_NUMBER = 40;
if(mPersonNumber > MIN_PERSON_NUMBER) {
/*内容*/
}

容易区分:我们很容易就会写下非常相近的方法名,仅从名称无法区分两者到底有啥区别(getAccount()与getAccountInfo()),这样在调用时也很难抉择要用哪个,需要去看实现的代码才能确定。

2.类和函数:

  类和函数应短小:更短小类和函数都不应该过长,过长的函数可读性一定差,往往也包含了大量重复的代码。
  函数只做一件事(同一层次的事):同一个函数的每条执行语句应该是统一层次的抽象。
  例如,我们经常会写一个函数需要给某个 DTO 赋值,然后再调用接口,接着返回结果。那么这个函数应该包含三步:DTO 赋值,调用接口,处理结果。如果函数中还包含了 DTO 赋值的具体操作,那么说明此函数的执行语句并不是在同一层次的抽象。

3.注释

规范的代码能减少写注释的必要性。
  别给糟糕的代码加注释,重构:注释不能美化糟糕代码。当企图使用注释前,先考虑是否可以通过调整结构,命名等操作,消除写注释的必要,往往这样做之后注释就多余了。
  好的注释提供信息、表达意图、阐释、警告:我们经常遇到这样的情况:注释写的代码执行逻辑与实际代码的逻辑并不符合。大多数时候都是因为代码变化了,而注释并没有跟进变化。所以,注释最好提供一些代码没有的额外信息,展示自己的设计意图,而不是写具体如何实现。
  删除掉注释的代码:git等版本控制已经帮我们记录了代码的变更历史,没必要继续留着过时的代码,注释的代码也会对阅读等造成干扰。

4.高内聚低耦合

  互联网公司相对于传统的软件行业,通常是先满足需求再迭代,一个想法需要尽可能快的上线。通过不断从用户的反馈进行迭代,不断完善,目前所有的产品都在不断迭代,没有完美的产品。所以当有新的需求,尽可能对以前功能带来最少的影响,代码的架构,高内聚低耦合,数据库满足三范式,表尽可能的小至关重要。
 
  JAVA(面向对象)六大设计原则:我们编写代码时的指导方针,按照这些原则开发的代码具有高内聚低耦合的特性,核心是通过接口和抽象类将功能抽象出来,通过不同的实例化达到对扩展开放,对修改关闭:
 

(1)单一职责原则 SRP (Single Responsibility Principle):

 一个对象应该只包含单一的职责,并且该职责被完整地封装在一个类中。

1)一个类(或者大到模块,小到方法)承担的职责越多,它被复用的可能性越小,而且如果一个类承担的职责过多,就相当于将这些职责耦合在一起,当其中一个职责变化 时,可能会影响其他职责的运作。
2)类的职责主要包括两个方面:数据职责和行为职责,数据职责通过其属性来体现,而行为职责通过其方法来体现。
3)单一职责原则是实现高内聚、低耦合的指导方针,在很多代码重构手法中都能找到它的存在,它是最简单但又最难运用的原则,需要设计人员发现类的不同职责并将其分离,而发现类的多重职责需要设计人员具有较强的分析设计能力和相关重构经验。
 
例如:一个数据结构职责类和算法行为都放在一个类User。我们应该把数据结构和行为分开。现使用单一职责原则对User类进行重构。
 
(2)开闭原则 OCP (The Open-Close Principle):
对扩展开放,对修改关闭
1)当软件实体因需求要变化时, 尽量通过扩展已有软件实体,可以提供新的行为,以满足对软件的新的需求,而不是修改已有的代码,使变化中的软件有一定的适应性和灵活性 。
2)实现开闭原则的关键就是抽象化 :在“开-闭”原则中,不允许修改的是抽象的类或者接口,允许扩展的是具体的实现类,抽象类和接口在“开-闭”原则中扮演着极其重要的角色。
3)可变性的封闭原则:找到系统的可变因素,将它封装起来。
 
例如:模板方法模式和观察者模式都是开闭原则的极好体现,很多设计原则都是为开闭原则服务的。
 
(3)里氏替换原则 LSP (Liskov Substitution Principle):
任何父类可以出现的地方,子类也可以出现。
 
1)基类和子类的关系,只有这种关系存在时,里氏替换原则才存在。正方形是长方形是理解里氏代换原则的经典例子。
2)里氏代换原则可以通俗表述为:在软件中如果能够使用基类对象,那么一定能够使用其子类对象。把基类都替换成它的子类,程序将不会产生任何错误和异常,反过来则不成立,如果一个软件实体使用的是一个子类的话,那么它不一定能够使用基类。
3)里氏代换原则是实现开闭原则的重要方式之一,由于使用基类对象的地方都可以使用子类对象,因此在程序中尽量使用基类类型来对对象进行定义,而在运行时再确定其子类类型,用子类对象来替换父类对象。
 
例如:可以对一个类中开放的方法参数为父类,通过实例化不同子类实现不同效果,来达到新添加功能的效果,不必重写父类。
 
(4)接口隔离原则 ISP (Interface Segregation Principle):
不应该依赖那些不需要的接口。
1)接口隔离原则是指使用多个专门的接口,而不使用单一的总接口。每一个接口应该承担一种相对独立的角色,不多不少,不干不该干的事,该干的事都要干。
2)使用接口隔离原则拆分接口时,首先必须满足单一职责原则,将一组相关的操作定义在一个接口中,且在满足高内聚的前提下,接口中的方法越少越好。
3)可以在进行系统设计时采用定制服务的方式,即为不同的客户端提供宽窄不同的接口,只提供用户需要的行为,而隐藏用户不需要的行为。
 
例如:一个拥有多个客户类的系统,在系统中定义了一个巨大的接口(胖接口)AbstractService来服务所有的客户类。可以使用接口隔离原则对其进行重构。
 
(5)依赖倒置原则 DIP (Dependence Inversion Principle):
模块间的依赖通过抽象发生,实现类之间不发生直接的依赖关系,其依赖关系是通过接口或抽象类产生的。(通过抽象再实例化接口,依赖通过接口)
 
1)如果说开闭原则是面向对象设计的目标,依赖倒转原则是到达面向设计“开闭”原则的手段。如果要达到最好的“开闭”原则,就要尽量的遵守依赖倒转原则。可以说依赖倒转原则是对“抽象化”的最好规范,依赖倒转原则也是里氏代换原则的补充。
2)依赖倒转原则的常用实现方式之一是在代码中使用抽象类,而将具体类放在配置文件中。
3)类之间的耦合:零耦合关系,具体耦合关系,抽象耦合关系。依赖倒转原则要求依赖于抽象耦合,以抽象方式耦合是依赖倒转原则的关键。
 
单一职责,开闭原则,里氏替换,接口隔离,依赖倒置可以总结为:抽象、单一职责、最小化
 
(6)最少知识原则 LKP (Least Knowledge Principle)) / 迪米特法则 (Law Of Demeter):
系统中的类,尽量不要与其他类互相作用,减少类之间的耦合度。
 
狭义的迪米特法则:如果两个类之间不必彼此直接通信,那么这两个类就不应当发生直接的相互作用,如果其中的一个类需要调用另一个类的某一个方法的话,可以通过第三者转发这个调用。
广义的迪米特法则:指对对象之间的信息流量、流向以及信息的影响的控制,主要是对信息隐藏的控制。
 

常用软件架构

如何写优质的JAVA代码