代码整洁之道核心记要(一)

代码整洁之道是鲍勃大叔的经典作品。这本书主要介绍鲍勃大叔的整洁代码的方法,如何写出好代码,如何将糟糕代码改成好代码。在阅读这本书后,我将该本书的内容整理如下。

0. 简介

代码整洁之道共有三部分组成:

  1. 介绍编写整洁代码的原则、模式和实践
  2. 几个复杂性不断增加的案例研究
  3. 案例研究中的启示和灵感

本篇笔记为第一部分,其核心内容如下图所示,在后续的笔记中,我将详细补充部分说明。
代码简洁之道核心纪要一

1. 前言

整洁代码就像是一种艺术品一样,拥有设计优雅、逻辑清晰等等优点。它可以使得阅读代码的程序员感到赏心悦目。
知易行难,会读简洁代码并不代表着会写简洁代码。本书主要介绍鲍勃大叔在编写简洁代码时的一些经验。每个人编写简洁代码的设计思路并非完全相同,但却有迹可循,参考这本书的方法,可以更快领悟简洁代码的精髓。

2. 详解

详解部分为上图的补充说明,帮助理解、记忆上图

1. 命名

  1. 读的出来的名称,不能使用俗语,俚语等命名。
  2. 如果在接口和实现中选择一个编码,建议选择实现,如接口为ShapeFactory,那么实现可以为ShapeFactoryImp。
  3. 使用解决方案领域名称,比如计算机领域的术语,算法名。比如命名为AccountVisitor就是访问者的意思。如果没有计算机领域名称,可以使用业务领域的专业名称。

2. 函数

  1. 每个函数都处在一个抽象层级上,比如getHtml()属于较高层级,PathParser.render(pagePath)处于中间抽象层级,而.append("\n")则位于较低抽象层级。
  2. 若函数参数为参数列表,即数量可变的参数
  3. 指令是控制程序的代码,询问是判断属性是否存在的情况,这两种代码最好分隔开,使用if语句先询问,再控制。
  4. 并不从一开始就按照规则写函数,往往在刚开始写函数时,都冗长而复杂。有太多缩进和嵌套循环,有过长的参数列表,名称是随意取的,也会有重复的代码。在配上一套单元测试后,再慢慢打磨这些代码,根据规则慢慢修改,同时保证测试通过。最后一句规则组装这些代码。

3. 对象与数据结构

  1. 数据抽象是指将数据结构抽象为一个接口,没有过多取值器和赋值器暴露具体数据,而是使用一些抽象形态表述数据。
  2. 隐藏实现并非只是在变量之间放上一个函数层那么简单。隐藏实现关乎抽象!类并不简单地用取值器和赋值器将其变量推向外间,而是曝露抽象接口,以便用户无需了解数据的实现就能操作数据本体。
  3. 以下两个例子展示了对象与数据结构之间的差异。对象把数据隐藏于抽象之后,曝露操作数据的函数。数据结构曝露其数据,没有提供有意义的函数。
  • 过程式形状代码
public class Square {
	public boint topLeft; 
	public double side; 
}

public class Rectangle {
	public Point topLeft; 
	public double height; 
	public double width; 
}

public class Circle {
	public Point center; 
	public double radius; 
}

public class Geometry {
	public final double PI = 3.141592653589793; 

	public double area (Object shape) throws NoSuchShapeException {
		if (shape instanceof Square) {
			Square s = (Square) shape;
			return s. side * s. side
		}
		else if (shape instanceof Rectangle) {
			Rectangle r = (Rectangle) shape;
			return r. height * r. width;
		}
		else if (shape instanceof Circle){
			Circle c = (Circle) shape;
			return PI * c. radius * c. radius;
		}
		throw new NoSuchShapeException(); 
}
  • 多态式形状(面向对象式)
public class Square implements Shape {
	private Point topLeft;
	private double side;
	
	public double area() {
	return side*side;
	}
}
public class Rectangle implements Shape {
	private Point topLeft;
	private double height;
	private double width;

	public double area() { 
		return height*width;
	}
}

public class Circle implements Shape {
	private Point center;
	private double radius;
	public final double PI = 3.141592653589793public double area() {
		return PI*radius*radius;
	}
}

从上述代码段中可以看出,过程式代码(使用数据结构的代码)便于在不改动既有数据结构的前提下添加新函数。面向对象代码便于在不改动既有函数的前提下添加新类过程式代码难以添加新数据结构,因为必须修改所有函数。面向对象代码难以添加新函数,因为必须修改所有类。
可以总结为,在任何一个复杂系统中,都会有需要添加新数据类型而不是新函数的时候。这时,对象和面向对象就比较适合。另一方面,也会有想要添加新函数而不是数据类型的时候。在这种情况下,过程式代码和数据结构更合适。

  1. 得墨忒耳定律
    得墨忒耳律(The Law of Demeter)认为,模块不应了解它所操作对象的内部情形。更准确地说是,类C的方法f只应该调用以下对象的方法:
    ·C
    ·由f创建的对象;
    ·作为参数传递给f的对象;
    ·由C的实体变量持有的对象。
    方法不应调用由任何函数返回的对象的方法。换言之,只跟朋友谈话,不与陌生人谈话。
    如果有代码存在连串调用,通常都是肮脏的代码,比如:final String outputDir = ctxt.getOptions().getScratchDir().getAbsolutePath();。这个代码可以切分为:
Options opts = ctxt.getOptions();
File scratchDir = opts.getScratchDir(); 
final String outputDir = scratchDir.getAbsolutePath();

这些代码是否违反得墨忒耳律,取决于ctxtOptionsScratchDir是对象还是数据结构。如果是对象,则它们的内部结构应当隐藏而不曝露,而有关其内部细节的知识就明显违反了得墨忒耳律。如果ctxtOptionsScratchDir只是数据结构,没有任何行为,则它们自然会曝露其内部结构,得墨忒耳律也就不适用了。
如果这些代码一半是数据结构,一半是对象,会增大添加新函数和新数据结构的难度,应尽量避免这种结构。
假如ctxtOptionsScratchDir是对象,那么如何实现上述方法?通过分析发现,上述方法是为了取得临时目录的绝对路径,然后是创建制定名称的临时文件,所以可以直接让ctxt来做:

BufferedOutputStream bos = ctxt.createScratchFileStream(classFileName);

这样就隐藏了内部结构,防止当前函数违反得墨忒耳定律。

感悟

  1. 命名
    命名是一件非常重要的事情,好的命名能准确描述每一个变量的作用及意义。一个好的名字,即为变量、函数、参数、类和封包最好的注释,可以让人一目了然。所以在取名字时需要仔细斟酌、考虑。

  2. 函数
    每个coder都会写函数,但不是每一个coder都能写好函数。若要编写好一个函数,不仅仅需要一个好的名称,更需要定义好函数的功能,入参以及异常处理。一个好的函数仅仅实现一个功能,一个好的函数代表一个抽象层级,一个好的函数最多一个入参。我们也许无法一次将函数写好,却可以通过无数次重构改善函数,使得函数尽可能完美。

  3. 对象与数据结构
    面向对象编程与面向过程编程的思想完全不同,前者利于扩充新类,后者利于扩充函数。在具体应用时,应该分情况使用。
    对象曝露行为,隐藏数据。便于添加新对象类型而无需修改既有行为,同时也难以在既有对象中添加新行为。数据结构曝露数据,没有明显的行为。便于向既有数据结构添加新行为,同时也难以向既有函数添加新数据结构。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值