【《代码整洁之道》精读与演绎】之五 整洁类的书写准则
2017-01-11 16:58
465 查看
这篇文章将与大家一起聊一聊,书写整洁类的一些法则。 一、引言 以下引言的内容,有必要伴随这个系列的每一次更新,这次也不例外。《代码整洁之道》这本书提出了一个观点: 代码质量与其整洁度成正比,干净的代码,既在质量上可靠,也为后期维护、升级奠定了良好基础。书中介绍的规则 均来自作者多年的实践经验,涵盖从命名到重构的多个编程方面,虽为一“家”之言,然诚有可资借鉴的价值。但我 们知道,很多时候,理想很丰满,现实很骨感,也知道人在江湖,身不由己。因为项目的紧迫性,需求的多样性,我 们无法时时刻刻都写出整洁的代码,保持自己输出的都是高质量、优雅的代码。但若我们理解了代码整洁之道的精髓, 我们会知道怎样让自己的代码更加优雅、整洁、易读、易扩展,知道真正整洁的代码应该是怎么样的,也许就会渐渐 养成持续输出整洁代码的习惯。而且或许你会发现,若你一直保持输出整洁代码的习惯,长期来看,会让你的整体效 率和代码质量大大提升。 二、本文涉及知识点思维导图 国际惯例,先放出这篇文章所涉及内容知识点的一张思维导图,就开始正文。大家若是疲于阅读文章正文,直接看 这张图,也是可以Get到本文的主要知识点的大概。 三、整洁类的书写准则 1.合理地分布类中的代码 一般情况下,我们遵循变量列表在前,函数在后的原则。 类应该从一组变量列表开始。若有公有静态常量,应该最先出现,然后是私有静态变量,以及公有变量,私有变量。 尽可能少的出现公有变量。公共函数应该出现在变量列表之后。我们喜欢把由某个公共函数调用的私有工具函数紧跟 在公共函数后面。这样是符合自定向下的原则,让程序读起来像一篇报纸文章。 2.尽可能保持类的封装 我们喜欢保持变量和工具函数的私有性,但不执著于此。有时,我们需要用到protected变量或者工具,比如让测 试可以访问到。然而,我们会尽可能使函数或变量保持私有,不对外暴露太多细节。放松封装,总是下策。 3.类应该短小 正如之前关于函数书写的论调。类的一条规则是短小,第二条规则还是要短小。 和函数一样,马上有个问题要出现,那就是,多小合适呢? 对于函数,我们通过计算代码行数来衡量大小,对于类,我们采用不同的衡量方法,那就是权责(responsibility)。 3.1 单一权责原则 单一权责(Single Responsibility Principle,SRP)认为,类或模块应有且只有一条加以修改的理由。举个栗子, 下面这个类足够短小了吗? public class SuperDashboard extends JFrameimplements MetaDataUser { public Component getLastFocusedComponent() public void setLastFocused(Component lastFocused) public int getMajorVersionNumber() public int getMinorVersionNumber() public int getBuildNumber() } 答案是否定的,这个类不够“短小”。5个方法不算多,但是这个类虽方法少,但还是拥有太多权责。这个貌似很 小的SuperDashboard类,却有两条关联度并不大的加以修改的理由: 第一, 它跟踪会随着软件每次发布而更新的版本信息(含有getMajorVersionNumber等方法)。 第二,它还在管理组件(含有getLastFocusedComponent方法)。 其实,鉴别权责(修改的理由)常常帮助我们在代码中认识到并创建出更好的抽象。 我们可以轻易地将SuperDashboard拆解成名为Version的类中,而这个名为Version的类,极可能在其他应用程序 中得到复用: public class Version { public int getMajorVersionNumber() public int getMinorVersionNumber() public int getBuildNumber() }这样,这个类就大致做到了单一权责。 4.合理提高类的内聚性 我们希望类的内聚性保持在较高的水平。何为类的内聚性?类的内聚性就是类中变量与方法之间的依赖关系。类中 方法操作的变量越多,就越黏聚到类上,就代表类的内聚性高。类应该只有少量的实体变量,类中的每个方法都应该 操作一个或者多个这种变量。通常而言,如果一个类中的每个变量都被每个方法所使用,则该类具有最大的内聚性。 一般来说,创建这种极大化的内聚类不可取,也不可能。我们只希望内聚性保持在较高的水平。内聚性高,表示类中 方法和变量相互依赖,相互结合成一个逻辑整体。举个高内聚的例子: public class Stack { private int topOfStack = 0; List<Integer> elements = new LinkedList<Integer>(); public int size() { return topOfStack; } public void push(int element) { topOfStack++; elements.add(element); } public int pop() throws PoppedWhenEmpty { if (topOfStack == 0) throw new PoppedWhenEmpty(); int element = elements.get(--topOfStack); elements.remove(topOfStack); return element; } }这个类非常内聚,在三个方法中,仅有size()方法没有使用所有的两个变量。 注意,保持函数和参数短小的策略,有时候会导致为一组子集方法所用的实体变量增加。我们应该尝试将这些方法拆 分到两个或者多个类中,让新的类更为内聚。 5.有效地隔离修改 需求会改变,所以代码也会改变。在面向对象入门知识中我们学习到,具体类包含实现细节(代码),而抽象类则 呈现概念。依赖于具体细节的客户类,当细节改变时,就会有风险。我们可以借助接口和抽象类来隔离这些细节带来 的影响。 举个栗子,在一个设计场景下,我们以其设计直接依赖于TokyoStockExchange的Protfolio类,不如创建StockExchange 接口,里面只声明一个方法: public interface StockExchange { MoneycurrentPrice(String symbol); }接着设计TokyoStockExchange类来实现这个接口: public class TokyoStockExchange extends StockExchange { //… }我们还要确保Portfolio的构造器接受作为参数StickExchange引用: public Portfolio { private StockExchange exchange; public Portfolio(StockExchange exchange) { this.exchange = exchange; } // ... }
|
相关文章推荐
- 【《代码整洁之道》精读与演绎】之三 整洁代码的函数书写准则
- 【《代码整洁之道》精读与演绎】之三 整洁代码的函数书写准则
- 【《代码整洁之道》精读与演绎】之五 整洁类的书写准则
- 【《代码整洁之道》精读与演绎】之三 整洁代码的函数书写准则
- 【《代码整洁之道》精读与演绎】之三 整洁代码的函数书写准则
- 【《代码整洁之道》精读与演绎】之五 整洁类的书写准则
- 《代码整洁之道》精读与演绎】之四 优秀代码的格式准则
- 【《代码整洁之道》精读与演绎】之四 优秀代码的格式准则
- 【《代码整洁之道》精读与演绎】之四 优秀代码的格式准则
- 【《代码整洁之道》精读与演绎】之四 优秀代码的格式准则
- 【《代码整洁之道》精读与演绎】之四 优秀代码的格式准则
- 【《代码整洁之道》精读与演绎】之四 优秀代码的格式准则
- 【《代码整洁之道》精读与演绎】之四 优秀代码的格式准则
- 【《代码整洁之道》精读与演绎】之二 高质量代码的命名法则
- 【《代码整洁之道》精读与演绎】之二 高质量代码的命名法则
- 【《代码整洁之道》精读与演绎】之一 让代码比你来时更干净
- 【《代码整洁之道》精读与演绎】之二 高质量代码的命名法则
- 【《代码整洁之道》精读与演绎】之二 高质量代码的命名法则
- 【《代码整洁之道》精读与演绎】之一 让代码比你来时更干净
- 【《代码整洁之道》精读与演绎】之二 高质量代码的命名法则