重构改善既有代码的设计—— 读书笔记3

当我们对代码理解不够深刻时,往往会感觉 重构改善既有代码的设计 这本书的内容过于浮夸,颇有“初闻不知曲中意,再闻已是曲中人”之感.
但根据个人经验,还是希望能尽早地运用其中的一些技巧。

该篇文章的内容主要来自于书中的第6章——重新组织函数

Linux 的创始人 Linus Torvalds 曾说:Talk is cheap.Show me the code

下面我将书中的一些技巧总结一下,以供参考学习交流。

1. 提炼函数(Extract Method)

将某段代码放进一个独立的函数中,并让函数名称解释该函数的用途。

无论你是否已经意识到,下面这几点你都是无可反驳的事实:

  1. 如果每个函数的粒度都很小,则函数被复用的机率就更大;
  2. 代码的阅读性更高;
  3. 覆写函数会变得更容易;

人们都会有疑问,函数的长度多少才算合适?

书中强调,函数的关键不在于长度,而在于函数名称能否正确表达出函数的功能;如果提炼可以强化代码的清晰度,那就尽管去做,就算函数名称比提炼出来的代码还长也无所谓。

这里举个例子,基础好的朋友也许一眼就能看出来这是个冒泡排序并打印排序后的数据。很显然,并不是每一个人都能直接读懂的。这里我们一定要明白,代码很多时候是给其他人看的

我们就按照提炼函数的思路来优化一下

public static void main(String[] args) {
        int[] array = {1,5,3,2};
            for (int i = 0; i < array.length-1; i++) {
                for (int j = 0; j < array.length-1-i; j++) {
                    if(array[j] > array[j+1]){
                        int tmp = array[j];
                        array[j] = array[j+1];
                        array[j+1] = tmp;
                    }
                }
            }
        Arrays.stream(array).forEach(System.out::println);
    }

优化版本1:

  // 冒泡排序
 public static void bubbleSort(int[] arr){
        for (int i = 0; i < arr.length-1; i++) {
            for (int j = 0; j < arr.length-1-i; j++) {
                if(arr[j] > arr[j+1]){
                    int tmp = arr[j];
                    arr[j] = arr[j+1];
                    arr[j+1] = tmp;
                }
            }
        }
    }
// 再看main函数,是不是感觉很轻松
 public static void main(String[] args) {
        int[] array = {1,5,3,2};
  		 bubbleSort(array);
  		 // 这里,采用Java 1.8 的写法其实是为了故弄玄虚的,这样我们提炼函数才有意义
		 Arrays.stream(array).forEach(System.out::println);
    }

经常刷算法的朋友对上面的冒泡排序或许会认为还有优化空间,这就产生了我们的

优化版本2:

 public static void BubbleSort(int[] arr){
        for (int i = 0; i < arr.length-1; i++) {
            for (int j = 0; j < arr.length-1-i; j++) {
                if(arr[j] > arr[j+1]){
					swap(arr,j,j+1);
                }
            }
        }
    }
 // 互换操作,使用的场景还是挺多的,这里更多的是考虑到复用场景
 public static void swap(int[] nums,int i,int j){
        int tmp = nums[i];
        nums[i] = nums[j];
        nums[j] = tmp;
    }

优化版本3:

// 再看main函数,是不是感觉很轻松
 public static void main(String[] args) {
        int[] array = {1,5,3,2};
  		 bubbleSort(array);
  		 printArray(array);
    }
    
// 打印数组,更多地从可读性上来考虑
 public static void printArray(int[] array){
        Arrays.stream(array).forEach(System.out::println);
    }

经多上面的一系列优化重构操作,main函数是不是让你一目了然。

当然在我们实际的开发过程中,可能需要考虑到很多场景——入参 和 出参 ,尤其是当其数量过多时,我们有可能考虑使用多个函数or对象包裹等方法,这里就不一一展开,更多地内容,可以去看书籍,不过还是想强调一点:

纸上得来终觉浅,绝知此事要躬行。


2. 内联函数(Inline Method)

// 这个是JDK自带的函数,但是在实际开发中使用的很少。
 public boolean isEmpty() {
        return size == 0;
    }
// 233333... 一般在开发中没这么写的吧,这里就需要 **内联** 一下
 public static boolean isAvailable(List list){
        return  (list == null || list.isEmpty()) ? false : true;
    }

内联后的效果,也就是大家开发中最常用的:

 public static boolean isAvailable(List list){
        return  (list == null || list.size() ==0 ) ? false : true;
    }

这里的例子可能不是太恰当,But不要懵逼…,其实就是函数不必要就删掉

3. 内联临时变量(Inline Temp)

  public static boolean isAvailable(List list){
  		// 在此处,size临时变量就该被内联化
  		int size = list.size();
        return  (list == null || size != 0 ) ? false : true;
    }

书中说了那么多,理解起来就是一句话:不要多此一举

综合2,3来看,

内联 即 Don’t 多此一举

大家更关系,如何识别什么是内联变量

只被一个简单表达式赋值一次的变量。

书中的这个技巧可以学一下:

若该变量没有被声明为final,可将声明为final,然后编译,这样可以确定该临时变量是否真的只被赋值一次

这个章节的内容过多,其它的放在后续文章中讲解,欢迎掌眼…

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章