《重构-改善既有代码的设计》阅读笔记

一直以来,总觉得自己只会纯粹地码代码,对代码没有自己的一种设计思想,久而久之,总觉得思维被固化。针对这种情况,给自己定了个目标,阅读两本关于代码设计书籍,第一本当然是设计模式相关,第二本就是本篇以之为主题将要陈述读后感的《重构-改善既有代码的设计》。

先来总体说下看完本书后对我个人的感触,主要有这两点:

  • 发现自己其实已经具备了判断代码是否具有Bad Smell的能力;
  • 重构不只是一次对项目的大型重构,也表现在对一段你看不惯的代码进行重新设计和组织;
  • 重构随时可发生。

整本书是按照以下这张图进行组织,主要介绍了何为重构,为何重构,何时重构,如何重构。


提纲.png

书中介绍了很多重构手法,主要分为以下几大块:


重构方式.png

针对每大块,作者进行了细分,列举了很多重构手法说明、动机和目的,这本书可以当做一本字典,没事翻一翻。当真遇到某种某种重构场景,可再详细查阅重构步骤。这里只介绍几种我认为比较常见和有用的重构手法。在陈述重构手法前,先看下书中所陈述的,什么样的代码具有坏代码的味道。
坏代码的味道
坏代码味道.png

总的来说,坏代码主要表现为以下几点:

  • 函数过长;
  • 类责任太多;
  • 类之间的耦合度太高;
  • switch / if-else 条件语句过长且逻辑重复。
重构函数
  1. 提炼函数 - Extract Method
    场景:你有一段代码可以被组织在一起并独立起来。将这段代码放进一个独立函数中,并让函数名称解释该函数的用途。

重构前:

public void printInfo() {
        printBaseInfo();
        
        System.out.println("job = " + _job);
        System.out.println("_salary = " + _salary);
    }
    
    private void printBaseInfo() {
        System.out.println("name = " + _name);
        System.out.println("age = " + _age);
    }

重构后:

public void printInfo() {
        printBaseInfo();
        printExtraInfo();
    }
    
    private void printBaseInfo() {
        System.out.println("name = " + _name);
        System.out.println("age = " + _age);
    }
    
    private void printExtraInfo() {
        System.out.println("job = " + _job);
        System.out.println("_salary = " + _salary);
    }
  1. 以查询取代临时变量 - ReplaceTemp with Query
    场景:你的程序以一个临时变量保存一个表达式的结果。将这个表达式提炼到一个独立函数中。将这个临时变量的所有引用点替换为对新函数的调用。

重构前:

double basePrice = _price * _quantity;
        if (basePrice > 1000) { 
            return basePrice * 0.7f;
        } else {
            return basePrice;
        }

重构后:

    if (basePrice() > 1000) { 
        return basePrice() * 0.7f;
    } else {
        return basePrice();
    }
    ...
    double basePrice() {
        return _price * _quantity;
    }
重构类
  1. 搬移函数/字段 - Move Method / Field
    场景:你的程序中,某个函数/字段被其所驻类之外的另一个类更多地用到。在目标类新建一个函数/字段,修改源函数/字段的所有用户,令其使用新的函数/字段。

这里拿实际项目中我认为需要用到此类重构方式的例子来说明。根据返回的 status = (10, 20)订单被拒绝时展示拒绝按钮btnRejected,否则就隐藏。
重构前:

Activity 中调用:btnRejected.setVisibility(order.getStatus() == 10 || order.getStatus() == 20);
public class Order {
        private int status;
        
        public int getStatus() {
            return status;
        }
    }

重构后:

Activity 中调用:btnRejected.setVisibility(order. isRejected());
public class Order {
        private int status;

        public int getStatus() {
            return status;
        }

        public boolean isRejected() {
            return status == 10 || status == 20;
        }
    }
  1. 隐藏委托关系 - Hide Delegate
    场景:客户通过一个委托类来调用另一个对象。在服务类上建立客户所需的所有函数,用以隐藏委托关系。

    image.png

    上述图示直接陈述了委托关系,对客户隐藏委托关系,就不需要在服务器中公开被委托对象。这里可以将Client类对delegate类的引用 转为直接对 Server类的引用,然后由 Server 类委托 delegate 类的所有方法。

    这里暂时不写案例。我在看这本书时,一直以为委托和组合是同一种。书中对委托提到的次数比较多。我自己看设计模式,其中有一条设计模式原则:多用组合少用继承。这个着实很令人疑惑,后来查阅,得知委托和组合其实并不是同一种。这里简单介绍下组合和委托,如以下两图所示。


    组合类图.png

    委托类图.png

    对比可发现,委托相对于组合,是在受托方法中加入了委托对象,最后实际调用的还是受托者的方法。

简化条件表达式
  1. 以多态取代条件表达式 - Replace Conditional with Polymorphism
    场景:项目中条件表达式,根据对象类型的不通而选择不同的行为。将这个条件表达式的每个分支放进一个子类内的覆写函数中,然后将原始函数声明为抽象函数。

重构前:

    public class Employee {
        public int payAmount(int type) {
            switch (type) {
                case ENGINEER:
                    return salary + comission;
                case SALESMAN:
                    return salary + bonus;
            }
            return 0;
        }
    

重构后,以一张类图展示多态替换条件表达式的好处:


多态替换表达式后的类图.png
简化函数调用
  1. 分离查询函数和修改函数 - Separate Query from Modifier
    场景:某个函数既返回对象状态值,又修改对象状态。建立两个不同的函数,其中一个负责查询,另一个负责修改。
    此重构方式,遵循一条规则:任何有返回值的函数,都不应该有看得到的副作用。可以把这种方式看做把 get方法 和 set方法分开。

  2. 引入参数对象 - Introduce Parameter Object
    场景:某些参数总是很自然地同时出现。以一个对象取代这些参数。
    本项重构的价值在于缩短参数列表,项目中常见作用于将很长的网络请求参数封装在一个对象中,然后直接将对象转成 JSON格式请求。

关于本书每章节的思维导图和书籍电子版,已上传至github。如有误,请指正!
详情参考:
https://github.com/CoralXss/AndroidFrameworkProcessChart [ 重构-坏代码味道.xmind ]

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 215,539评论 6 497
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 91,911评论 3 391
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 161,337评论 0 351
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,723评论 1 290
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,795评论 6 388
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,762评论 1 294
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,742评论 3 416
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,508评论 0 271
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,954评论 1 308
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,247评论 2 331
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,404评论 1 345
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,104评论 5 340
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,736评论 3 324
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,352评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,557评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,371评论 2 368
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,292评论 2 352

推荐阅读更多精彩内容