大家好,我是码农老吴,欢迎收看,我们极客架构师,最新推出的,架构师书房栏目,今天,我继续给大家解读《代码不朽》这本书,上期我们聊了第一原则,要编写短小的代码单元(Write Short Units of Code ),最好15行以内。今天,我们聊聊如何才能编写出短小的代码。
写代码犹如写文章好的代码是设计出来的吗?
好的代码是一蹴而就的吗?
非也,非也,我的观点是(非本书作者的观点),写代码犹如写文章,好的代码往往是修改出来的,是重构出来的。
写代码之前,先大致构思一下,然后开始写第一版代码(也就是初稿),先确保业务功能基本实现(deadline给你带来的焦虑感会随之消失大半),然后是一点点的修改,优化,或者叫重构(每优化完成一点点,成就感,兴奋感就会增加一点点,大脑的多巴胺就会多分泌一点点,这大概就是码农的快乐吧),直至改无可改,或者deadline已到,形成终版,代码提交。当然,随着编码水平的提高,第一版(初稿)的质量也会越来越高,优化,重构的速度也会越来越快,直至封神,成为技术大牛。
本章介绍了两个,使用率很高的,很实用的代码重构技巧。在介绍这些技巧之前,我们先简要介绍一下,本书采用的案例代码。
案例介绍-代尔夫特理工大学教授的授课案例Jpacman 吃豆人本书使用的案例有些特别,不是临时编写的实验性质的代码,而是采用了一款类似吃豆人的游戏源代码,项目的名称是JPacman(吃豆人),它是由荷兰代尔夫特理工大学(Delft University of Technology, The Netherlands)的 Arie van Decursen 教授及其团队开发创建,用于讲授测试代码的编写技巧。这个项目我已经fork到我的github上了,大家有兴趣可以看看。
案例1:start方法重构重构前-start方法
16行代码,超过15行,需要重构
重构方案1:将19行-30行代码,提取到一个新的方法中,最终2个方法(满足要求,每个方法不超过15行)
重构方案2:将19行-30行代码,两个if语句,分别提取为一个独立方法,最终3个方法(满足需求,但是后面每个方法,5行代码,有点过了)
操作提示
重构后
// tag::start[]
public void start() {
if (inProgress) {
return;
}
inProgress = true;
updateObservers();
}
// end::start[]
@SuppressWarnings("unused")
// tag::updateObservers[]
private void updateObservers() {
// Update observers if player died:
if (!isAnyPlayerAlive()) {
for (LevelObserver o : observers) {
o.levelLost();
}
}
// Update observers if all pellets eaten:
if (remainingPellets() == 0) {
for (LevelObserver o : observers) {
o.levelWon();
}
}
}
点评
上面提取出来的方法updateObservers(),比较简单,没有任何参数,也没有返回值。下面看一个复杂一点的,提取的方法,会包含很多参数。
案例2:createBoard方法重构重构前-createBoard()
该方法明显超过15行
重构方案1:将红色标注部分,15-20行,最里面的for语句,提取为一个方法。
重构后
package eu.sig.training.ch02.v1;
public class BoardFactory {
// tag::createBoard[]
public Board createBoard(Square[][] grid) {
assert grid != null;
Board board = new Board(grid);
int width = board.getWidth();
int height = board.getHeight();
for (int x = 0; x < width; x ) {
for (int y = 0; y < height; y ) {
Square square = grid[x][y];
for (Direction dir : Direction.values()) {
setLink(square, dir, x, y, width, height, grid);
}
}
}
return board;
}
// end::createBoard[]
// tag::setLink[]
private void setLink(Square square, Direction dir, int x, int y, int width,
int height, Square[][] grid) {
int dirX = (width x dir.getDeltaX()) % width;
int dirY = (height y dir.getDeltaY()) % height;
Square neighbour = grid[dirX][dirY];
square.link(neighbour, dir);
}
// end::setLink[]
}
class Board {
@SuppressWarnings("unused")
public Board(Square[][] grid) {}
public int getWidth() {
return 0;
}
public int getHeight() {
return 0;
}
}
class Square {
@SuppressWarnings("unused")
public void link(Square neighbour, Direction dir) {}
}
class Direction {
public static Direction[] values() {
return null;
}
public int getDeltaY() {
return 0;
}
public int getDeltaX() {
return 0;
}
}
点评
上面重构出来的代码中,setLink方法包含了7个参数,当一个方法,参数过多时,一般不超过3到4个,说明存在优化的可能。
private void setLink(Square square, Direction dir, int x, int y, int width,
int height, Square[][] grid) {
int dirX = (width x dir.getDeltaX()) % width;
int dirY = (height y dir.getDeltaY()) % height;
Square neighbour = grid[dirX][dirY];
square.link(neighbour, dir);
}
那么如何优化呢?欲知后事如何,且听下回分解,下期我们聊聊,另外一个重构技巧,方法对象的提取。我们下期见。
Copyright © 2024 妖气游戏网 www.17u1u.com All Rights Reserved