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

2017-11-23  本文已影响6人  Coralline_xss

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

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

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


提纲.png

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


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

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

重构函数
  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 ]

上一篇下一篇

猜你喜欢

热点阅读