美文网首页
《重构-改善既有代码的设计》阅读笔记

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

作者: Coralline_xss | 来源:发表于2017-11-23 23:06 被阅读6次

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

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

    • 发现自己其实已经具备了判断代码是否具有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 ]

    相关文章

      网友评论

          本文标题:《重构-改善既有代码的设计》阅读笔记

          本文链接:https://www.haomeiwen.com/subject/wecavxtx.html