重构

2021-12-06  本文已影响0人  my_passion

禁止转载

同步于 Github 仓库

https://github.com/liyu030076/Refactoring

要让重构发挥威力, 必须做到 "不需了解 软件行为"

    嗅到 "坏味道" -> 重构 -> 理解 软件行为

Chapter2 重构原则

    1   何谓重构

            在 `不改变 软件 可观察行为` 的前提下, 
                
                用 重构 `手法` 改善其 `内部结构`

        Note
            两顶帽子: 添加新功能 / 重构
                
                只应该 同时戴一个帽子
            
    2   为何重构
    
        (1) 改进 软件设计
        
        (2) 使软件 更易理解
        
            `code 简洁`, 才能显现 `设计层面` 的东西
        
    3   何时重构
    
        (1) 三次法则
        
            第 3 次 做类似事情时
            
        (2) 复审代码时

chapter 3 代码的 坏味道

    1   重复 code 出现在
    
        ———————————————————————————————————————————————————————————————————————————————————————
        (1) class 的 2 个 func
                
                [1] Extract Method
        ———————————————————————————————————————————————————————————————————————————————————————
        (2) 兄弟子类
                            
                子类 1 -> Extract Method                  [2] Pull Up Method : 推入 Base 类
                                         \              /
                                            commonFunc
                                         /              \
                子类 2 -> Extract Method                  [3] Template Method: 设计模式
        ———————————————————————————————————————————————————————————————————————————————————————                 
        (3) 不相关 class
            
                [4] Extract Class 
                        |
                        |   提取 重复 code 到
                        |/
                    `新 class` -> 被 不相关 class 用 
        ———————————————————————————————————————————————————————————————————————————————————————
        (4) 不同算法    
            
                [5] Substitute Algorithm
        ——————————————————————————————————————————————————————————————————————————————————————— 
        
        Note
            Extract 哪段 code ?  
    
            [1] 想要注释的 code -> function: 用途 命名
            
            [2] 条件表达式       -> Decompose Conditional
                          
            [3] 循环          -> 及 其内code 

        `中间层` 好处
            
            解释/共享/选择 
                
                由 `小函数` 支持
                        |
                        |   理解的关键
                        |/
                    好名字
                
    2   Long Method
    
        ———————————————————————————————————————————————————————————————————————————————————————
        [1] Extract Method
        ———————————————————————————————————————————————————————————————————————————————————————
                                        消除 Temp var:         [2] Replace Temp with `Query`  
                                     /                                                   
                                    /                                                     
        (2) Temp var 和 Para 太多                           [3] Introduce `Para Object`     
                                    \                       /                            
                                     \  简化 Long Para List                           
                                                            \                       
                                                             [4] Preserve `Whole Object` 
                                |
                                |   Temp var 和 Para 仍 太多
                                |/      
                                
                        [5] Replace Method with `Method Object` 
        ———————————————————————————————————————————————————————————————————————————————————————

    3   Long Para List
        
        —————————————————————————————————————————————————
        [1] Replace Para with Method
        
            Para -> 替换为 -> 向 另一 对象请求: obj.f()
        —————————————————————————————————————————————————
        [2] Preserve Whole Object
            
            `多 data` 归属 `同一对象`
            
                以 该对象 代替
        —————————————————————————————————————————————————
        [3] Introduce Para Object
            
            data `缺 Object 归属` 
                
                `引入` 新 `Para Object`    
        —————————————————————————————————————————————————
    
    4   Large Class
                                                    
        ——————————————————————————————————————————————————————                                  
        (1) 类内 data 太多 
                
                相关 data 属 同一组件 // 如 前缀 或 后缀 相同
                                                
                    [1] Extract Class 
                    [2] Extract Subclass
        ——————————————————————————————————————————————————————
        (2) 类内 code 太多
        
                Extract Class
                Extract Subclass
            
            先确定 client 如何 使用 它们
                
                [3] Extract Interface 
                    
                    为 每种使用方式 提出 1 个 接口   
        ——————————————————————————————————————————————————————
        (3) 5 个 "百行函数" 
                    |
                    |   分解
                    |/
                    
            为 5 个 "十行函数"  + 10 个 "双行函数"
        ——————————————————————————————————————————————————————          
        (4) GUI 类
            
            data 和 func 移到 独立对象 
            
            两侧 
                1]  部分 重复数据
                2   同步
        ——————————————————————————————————————————————————————
        
    5   Primitive Obsession (基本类型偏执)

        Object 价值: 打破了 basic 类型 与 class 类型 间 界限

            考虑以 class 类型 -> 代替 -> basic 类型
            
            —————————————————————————————————————————————————————————————————————————————
                    data                    |   Replace Data Value with Object
                    —————————————————————————————————————————————————————————————————————
            想替换 type code               |   Replace Type code with Subclass         
                    —————————————————————————————————————————————————————————————————————   
                    type code 相关的 Expr  |   Replace Type code with State/Strategy
            —————————————————————————————————————————————————————————————————————————————   
            
    6   Switch Statements: switch -> 多态

        OOP 明显特征
            少用 switch/case
                本质上, switch 问题: 重复  
                    每添加 1 个 新 case, 就要找到 所有 switch 语句 并修改


        switch -> type code -> 要的是: 与 type code 相关的 func 或 class
                                                                                                             
        ————————————————————————————————————————————————————————————————                                                                                                                                
        switch 语句 
            Extract Method : 提到 独立函数
                Move Method 移到 需 多态性 的 class                                
        ————————————————————————————————————————————————————————————————    
                    确定是否要               
                        (1) 
                            ————————————————————————————————————————————
                            [1] Replace Type code with Subclass 
                            ————————————————————————————————————————————
                            [2] Replace Type code with State/Strategy
                            ————————————————————————————————————————————
                        (2)
                            ————————————————————————————————————————————
                            [3] Replace Conditional with Polymorphism        
        ————————————————————————————————————————————————————————————————             
        case 之一是 null
            [4] Introduce Null Object   
        ————————————————————————————————————————————————————————————————
        
    7   Lazy Class
    
        class 存在价值 不大
            ————————————————————————
            [1] Collapse Hierarchy
            ————————————————————————
            [2] Inline Class
            ————————————————————————

    8   Divergent (分离式) Change 
    
        不同的 `需求 变化`
            
            =>  1个 class 内 不同的 `函数集 变化` 
            
                Extract class
                    每个函数集 对应 1 个新 Class 
                
                        单一职责原则
                            引起类 变化 的原因 只有 1个
                            变化方向 隐含着 类的责任
        
    9   Shotgun Surgery (散单式修改): 
    
        需求变 => 多 个 class 内 变

                                                     Move Method
                                                   /
                                            已有类
                                          /        \
                                         /           Move Field
            要修改的代码 放进 1 个类 
                                         \
                                          \
                                            新建类: Inline class -> Divergent Change -> ....
                                    
    10  Parallel Inheritance Hierarchies : Shotgun Surgery 的 特例

        类 增加 子类, 另一个类 必须相应增加 1子类

            双继承体系 + 引用关系 ( 如 composition )

                Move Method
                Move Field
        
    11  Feature Envy 依恋情结
     
        memFunc 对 other Class 兴趣 更大

            Extract Method -> 该 part 的 新函数 ->

            Move Method 
                
                到 兴趣类
                    |
                    |/
                    拥有最多 被此 Func 使用的 数据


    12  Data Clumps (数据泥团)

                                两个 class 的 相同 field
                              /                          
        总 绑在一起 的 data                               
            |                 \                          
            |                   多个 func  的 相同 paras 
            |   绑定 data 
            |/
        ——————————————————————————————————————————————
        [1] Extract Class + [2] Introduce Para Object
        ——————————————————————————————————————————————
        [1] Extract Class + [3] Preserve Whole Object
        ——————————————————————————————————————————————

        Note
            不必在意 Data Clumps 只用上 新对象 1部分字段, 
            
                只要以新对象取代 >= 2 个 字段 就值了

    13  Temporary Field

        (1) 对象 内 的 某 field 仅 为 某种特定情况而设 

            Extract Class 为其 建个 class
            
                所有 与 该 field 相关的 code 放进去

        (2) Introduce Null Object   

        (3) 算法 需 多个变量 -> 放进 临时字段 
        
            -> Extract Class 把 这些变量 和 相关函数 提到 独立 class -> 新 obj 就是 函数对象


    14  Middle Man
        
        过度委托
        
            [1] Remove Middle Man
            
            (2) 少数函数
            
                [2] Inline Method 将其放入 调用端

            [3] Replace Delegation with Inheritance

    15  过多注释
    
        Extract     Method
        Rename      Method
        Introduce   Assertion

    16  Speculative Generality (夸夸其谈通用性)

        (1) 抽象类 没太大作用
            
            Collapse Hierarchy

        (2) 不必要的 委托
            
            Inline Clase

        (3) Para 没用上
            
            Remove Para

        (4) funcName 太抽象
            
            Rename Method
        
    17  Message Chains

        msg 从 srcObject 到 dstObject 经历太多 对 objects 的 请求
            => client code 与 查找过程 强耦合 
                => object 间关系变化, 则 client code 变化

                -> 对 最终对象 -> Extract Method 把 使用该 对象 的 code 提到 独立 func -> Move Method 将 func 移到 msg chains
                => 链上 client 航行 剩余部分时, 加 1 函数 即可

chapter 6 重新组织函数

    (1) Extract Method <-> (2)Inline Method 相反 => 可相互 回溯
                |
                |                                       某 temp var 在 多个地方用 -> (3) Split Temporary variable 将其变得 易替换 -> (4) Replece Temp with Query -> 多半 含 (5)Inline Temp var <---相反--->Introduce Explaining Var  
                |                                     /
                |                            temp var  
               \|/                         /          \     
                                          /             temp var 实在太乱, 难替换 -> (6) Replace Method with Method Object 
            
       之前, 最大困难: 处理 local variable
                                          \
                |                          \
                |                            para: 若在 func 内 赋值 para => (7) Remove Assignments to Para
                |
                |
               \|/
            提取出 func 后 -> 发现 算法 可改进 -> (8) Substitute Algorithm
            
(1) Extract Method

    一段 code 可组织在一起 -> 提取 到 独立 func + 以 用途命名 
    
    动机
        小函数 优势
            (1) 易 复用
            (2) 使高层 func 读起来 就像 一系列 注释
            (3) 易 override
            
    void printSomeObj(int amount)
    {
        printObj1();
        
        // print details
        System.out.println("name:" + _name);
        System.out.println("amount:" + amount);
        
    }
       |
       |
      \|/
    void printSomeObj(int amount)
    {
        printObj1();    
        printDetails(amount)    
    }

    void printDetails(int amount)
    {
        System.out.println("name:" + _name);
        System.out.println("amount:" + amount);
    } 
    
(2) Inline Method

    func body 与 name 同样 清晰易懂
    
        C++ inline 机制 
        
    动机
        (1) func 的 body 与 name 同样 清晰易懂
        
        (2) 间接层 / 委托 没有意义
        
        (3) 先 Inline Method -> 再 Extract Method
            
                以 `重新组织` 组织不合理 的 多个 func
        
            Replace Method with Method Object 前 先这么做很有效果

    int getRating() { return ( moreThanFive() ) ? 2 : 1; }
    boolean moreThanFive(){ return _num > 5;}
       |
       |
      \|/
    int getRating() { return ( _num > 5 ) ? 2 : 1; }  

(3) Split Temporary variable

    某 Temp var 被 赋值 超过 1 次, 它 既不是 循环变量 也不用于 收集计算结果

    对 每次赋值, 创造 1 个 独立的 Temp var

    double temp = 2* (_height + _width);
    System.out.println(temp);
    ...
    temp = _height * _width;
    System.out.println(temp);
       |
       |
      \|/   
    double perimeter = 2* (_height + _width);
    System.out.println(perimeter);
    ...
    double area = _height * _width;
    System.out.println(area);

    动机
        Temp var (非 循环变量/结果收集变量) 被 赋值 超过 1 次 => 承担 1 个以上 责任 => 责任分解 
    
(4) Replece Temp with Query

    Temp var 保存 expr 结果

    将 expr 提取 到 1个 独立 func 中 -> 所有引用 Temp var 的 地方 替换为 调 该 func

    double basePrice = _quantity * _itemPrice;
    if(basePrice > 1000)
        return basePrice * 0.9;
    else
        return basePrice * 0.8;
        
       |
       |
      \|/   

    if(basePrice() > 1000)
        return basePrice() * 0.9;
    else
        return basePrice() * 0.8;

    double basePrice()
    {
        return _quantity * _itemPrice;
    }

    动机
        Temp var 的 scope 只在 所属 func 可见 (scope) -> 替换为 查询, 则 同一 class 中 所有函数 都可以 获得这份信息
    
(5) Inline Temp var
    Temp var 只被 simple expr 赋值 1 次, 而 妨碍了 其他 重构手法

    将 所有对 该 Temp var 的 引用, 替换为 对它赋值的 expr 

    double price = order.price();
    return (price > 1000);

       |
       |
      \|/

    return (order.price() > 1000);

    动机
        多半作为 Replece Temp with Query 的 一部分, 真正动机 在 Replece Temp with Query
        Temp var 妨碍了 其他 重构手法
    
(6) Replace Method with Method Object 
    动机
        大 func 中 local var 杂乱, 无法用 Extract Method

    做法
        将 `func 放进 函数对象`, local var + IncludedObject + para 成为 Obj 内 mem -> `同一对象内` 对 大 func 用 Extract Method 

    class Order ...
        double price(int quantity)
        {
            double primaryPrice;
            double secondaryPrice;
            // long compution including memFuncOfOrder()
            ...
        }
        
           |
           |
           |    Replace Method with Method Object
          \|/


    class Order ...
        double price(int quantity)
        {
            return new Price(this, quantity).compute();
        }

    class Price
    {
    private:
        // (1) IncludedObject + para -> ctor 的 para
        Order _order; // 1) IncludedObject: call _order.memFuncOfOrder()
        int quantity; // 2) para
        
        // (2) local variable -> Init unneeded
        double primaryPrice;   
        double secondaryPrice;
        
    public: 
        Price(Order order, int quantity_) { /* ... */ }
        
        // (3) compute() 只用 Price 的 mem ======> 易用 Extract Method -> computeKey(): 作 Price 的 mem func
        int compute(); 
    };

     ———————————        \    ———————————————
    |   Order   | -------   |  Price        |
     ———————————        /    ———————————————
    |           |           | _order        |
     ———————————            | quantity      |
    |           |           | primaryPrice  |
    | price(int)|           | secondaryPrice|
    |_____|_____|            ———————————————      Extract Method   \
          |                 | compute()     |   --------------------     computeKey()
          |                  ———————————————                       /
          |
          |
    return new Price(this, quantity).compute()

(7) Remove Assignments to Para

    Java 中 对 para 赋值 

    以 Temp var 代替 para

    int discount (int input, int quantity, int yearToDate)
    {
        if(input > 50) input -= 2;
    }
           |
           |
          \|/
    int discount (int input, int quantity, int yearToDate)
    {
        int result = input;
        if(input > 50) result -= 2;
    }

    动机
                    对象 (basic / class 类型) 都是 引用, 相当于 C++ 中 对象的引用 => 对 func 的 para 赋值, 会 modify caller 中 相应的 实参 => Java 中, 若不是想 改 arg, 就不要 给 相应 para 赋值
                 /
        Java 中 
                 \
                    Java 的 按值传递, 指的是 对象(的引用) 按值传递
                    
        note: 这是 Java 和 C/C++ 值传递 的本质区别
        
(8) Substitute Algorithm    

    想把算法 替换为 更清晰的 算法
    
    把 func body 替换为 另一个
    
    String foundPerson(String[] people)
    {
        for(int i = 0; i < people.length; i++)
        {
            if(people[i].equals("lilei")) { return "lilei"; }
            
            if(people[i].equals("hanmei")) { return "hanmei"; }
        }
        return "";
    }

    String foundPerson(String[] people)
    {
        for(int i = 0; i < people.length; i++)
        {
            if(people[i].equals("lilei")) { return "lilei"; }
            
            if(people[i].equals("hanmei")) { return "hanmei"; }
        }
        return "";
    }

               |
               |
              \|/
              
    String foundPerson(String[] people)
    {
        LargeIST candidates = Arrays.asList(new String[] {"lilei", "hanmei"} );
        for(int i = 0; i < people.length; i++)
            if ( candidates.contains(people[i]) )
                return people[i];

        return "";
    }

chapter7 在 对象间 搬移特性

    summary
        "决定 把责任放在哪" 很重要, 但 很难一开始就保证做对。
        重构 改变原先的设计, 可以逐步把 责任放到合适位置

            先 (1) Move Field -> 后 (2) Move Method
         /
        |—— 类 承担过多责任  -> (3) Extract Class 将 一部分责任分离出去 
                                        |
        |                               | 相反 / 回溯
                                        |
        |                       (4) Inline Class 将 类 融入 另一个类 <- 类 太 "不负责任"

        |—— 类 使用了 另一个类 -> (5) Hide Delegate 以 隐藏委托类
                                        |
        |                               | 相反 / 回溯
                                        |
        |                         (6) Remove Middle Man <- 隐藏委托类 若 导致 Owner 的 interface 经常变换

        |                                                                     <= 2 -> (7) Introduce Foreign Method
         \                                                                  /
            不能访问 类 的 源码, 却又想 把责任移进该类 -> 想加入的 函数个数 
                                                                            \
                                                                              > 2  -> (8) Introduce Local Extension

(1) Move Field

    某 字段 被其 所驻类 之外的 另一类 更多地 使用 (可能通过 set/get 间接使用)
                                                                                                    
    在 目标类 建一 字段, 让 源字段 所有 client 用 新字段:
                                                                                
                                         dstObj.getField()
                                       /    
                                      / no
    srcClass 中 很多函数 已用该字段 ?
                                      \ yes   
                                       \    
                                         srcObj.getField()   --- forward/转调 ---> dstObj.getField()
                                         
                                         
    1)                                   
     ———————————        \    ——————————— 
    |   C1      | ——————    |   C2      |
     ———————————        /    ——————————— 
    |  _c2      |           |           |
    |  field1   |           |           |
     ———————————             ———————————
    |   func1() |           |           |
    |       |   |           |           |
    |_______|__ |           |__________ |
            |
            |           
          use field1         

               |
               | field1 与 C2 交互更多
              \|/


     ———————————        \    —————————————                          
    |   C1      | ——————    |   C2       |                  
     ———————————        /    —————————————                  
    |   _c2     |           |  field1    |                  
     ———————————             —————————————                  
    |  func1()  |           | setField1()|                  
    |     |     |           | getField1()|                  
    |_____|____ |           |____________|                  
          |                                                 
          |                                                 
        use _c2.getField1()                                                 
          
    2)   SelfEncapsulate Field + Move Field

     ———————————        \    ——————————— 
    |   C1      | ——————    |   C2      |
     ———————————        /    ——————————— 
    |  _c2      |           |           |
    |  field1   |           |           |
     ———————————             ———————————
    |   func1() |           |           |
    |func2()    |           |           |         
    |______|_|__|           |__________ |
           | |
           | |          
      use field1         

               |
               |
              \|/


     ———————————————       \     ———————————————
    |      C1       | ——————    |   C2         |
     ———————————————       /     ——————————————— 
    |     _c2       |           |   field1     |        
     ———————————————             ———————————————
    |       func1() |           |              |
    |     func2() | |           | setField1()  |          
    |             | |           | getField1()  |
    |setField1()  | |           |              |
    || getField1()| |            ——————————————
    ||__|_________|_|             
     |  |         |
     |  |         | 
     |  |    getField1()
     |  |
     |  |
     |  _c2.getField1()
     | 
    _c2.setField1()   
      
(2) Move Method  

    func 与 所驻类 之外的 另一个类 交流更多
                                                                变成 委托函数
                                                              /
    在 func 最常引用的 类 中 建一类似行为的 新函数 -> 旧 函数 
                                                              \
                                                                完全删除



    class Account ...
        private AccountType _type;
        private int         _daysOverdrawn; // draw: 取款   deposit: 存款    overdraw: 透支
        
        double overdraftCharge()
        {
            if (_type.isPremium() )
            {
                double result = 10;
                if (_daysOverdrawn > 7)
                    result += (_daysOverdrawn - 7) * 0.8;
                return result;
            }
            else    
                return _daysOverdrawn * 1.75;
        }
        
        double bankCharge() // charge: 收费 
        {
            double result = 4.5;
            if(_daysOverdrawn > 0)
                result += overdraftCharge();
            return result;
        }
        
               |   overdraftCharge() 与 AccountType 类 交流更多
               |
               |   _daysOverdrawn 字段 随 Account 而变 => 留在 Account 类
               |
               |
               |   => overdraftCharge() 提到 AccountType 类 + _daysOverdrawn 做其 arg => para 名为 daysOverdrawn
               |
              \|/

    class AccountType ...
        double overdraftCharge(int daysOverdrawn) // add para
        {
            if ( isPremium() )
            {
                double result = 10;
                if (daysOverdrawn > 7)
                    result += (daysOverdrawn - 7) * 0.8;
                return result;
            }
            else    
                return daysOverdrawn * 1.75;
        }


    class Account ...
        double overdraftCharge()
        {
            return _type.overdraftCharge(_daysOverdrawn);
        }
        
        double bankCharge()
        {
            double result = 4.5;
            if(_daysOverdrawn > 0)
                result += _type.overdraftCharge(_daysOverdrawn);
            return result;
        }
        
               |
               |  搬移 函数中 引用 不止 1 个字段
               | => 所驻类 对象 作 para
              \|/
              
    class AccountType ...         
        double overdraftCharge(Account account) // add para
        {
            if ( isPremium() )
            {
                double result = 10;
                if (account.getDaysOverdrawn() > 7)
                    result += (account.getDaysOverdrawn() - 7) * 0.8;
                return result;
            }
            else    
                return account.getDaysOverdrawn() * 1.75;
        }         

(3) Extract Class

    类 责任太多

    将 相关 mem + func 搬到 提取的 新类

                         ——————————————————— 
                        |   Person          |
                         ——————————————————— 
                        |  name             |
                        |  officeAreaCode   |
                        |  officeNumber     |
                         ———————————————————|
                        |   getOffice()     |
                         ———————————————————

                                   |    /|\
                    Extract Class  |     |   Inline Class
                                  \|/    |

     ———————————————————                     ——————————————————— 
    |   Person          |            \      |   Office          |
     ———————————————————    ——————————       ——————————————————— 
    |  name             |            /      |  _areaCode        |
    |  _office          |                   |  _number          |
     ———————————————————|                    ———————————————————|
    |   getOffice()     |                   |   getOffice()     |
    ———————|————————————                    |   getAreaCode()   |
           |                                |   setAreaCode()   |
           |                                |   getNumber()     |
        _office.getOffice()                 |   setNumber()     |
                                             ————————|———————————
                                                     |
                                                     |
                                            return ( "(" _areaCode + ")" + _areaCode);

(4) Inline Class

    Extract Class 的 回溯

    martin.getOffice().setAreaCode("029");
              |
              |   找到 Office 所有 client, 让它们转而使用 Person 的 interface
              |   反复用 Move Method 和 Move Field 直到 Office 消失
             \|/
        martin.setAreaCode("029")    
         
         
(5) Hide Delegate
    动机
        想 对 Client 隐藏 Server 与 Delegate 的 `委托关系`, 从而 去除 Client 与 Delegate 的 依赖, 
        
    做法
        只要在 Server 中 放一 `委托函数`

    说明
        Client 通过 Server 对象 get 另一 Delegate 对象, 再 调用 后者的 func
        => Client 就 知道了 Server 与 Delegate 的 `委托关系`
        => Client 依赖 (与 ... 耦合) Delegate


                         ——————————————————— 
                        |   Client          |
                         ——————————————————— 
                        |                — —|— — — server.getDelegate().func
                         ———————————————————
                           |            |                               
                            
                _ _ _  _  _|            |_ _ _ _ _  依赖
               |                                  |
               |                                  |
              \|/                                \|/
     ———————————————————                     ——————————————————— 
    |   Server          | /             \   |   Delegate        |
     ———————————————————  ———————————————    ——————————————————— 
    |  _delegate        | \             /   |   _server         |                                           
     ———————————————————|                    ———————————————————|
    |   getDelegate()   |                   |   func()          |
     ———————————————————                     ———————————————————
     
                                   |    /|\
                    Hide Delegate  |     |   Remove Middle Man
                                  \|/    |

     
     ——————————————————— 
    |   Client          |
     ——————————————————— 
    |                — —|— — — server.func()
     ———————————————————
         |
         |
        \|/
     
     ———————————————————                     ——————————————————— 
    |   Server          |                   |   Delegate        |
     ———————————————————  /             \    ——————————————————— 
    |  _delegate        | ---------------   |   _server         |   
     ———————————————————  \             /    ———————————————————
    |   func():委托函数 |                   |   func()          |
     ——————|—————————————                    ———————————————————
           |
           |
     _delegate.func()
 
 
(6) Remove Middle Man
    动机
        类 做了 `过多的 简单委托`

    做法
        让 Client 直接调用 Delegate 类
        
    
(7) Introduce Foreign Method

    动机
        想在 Server 类 中 add 1 个函数, 但 无法 修改 Server 类
        
    做法
        在 Client 类 add 1 个函数, 并以 第1参数 传入 Server 对象
                                             ———————————
     ———————————————————                    |   Server  |
    |   Client          |            \       ———————————
     ———————————————————    ----------      |           |
    |                   |            /       ———————————
     ———————|————————————                   |   func1() |
            |                               |   func2() |
            |                                ———————————
    Server(server.func1(), 
           server.func2()

                             | 
                             | Introduce Foreign Method
                            \|/
     
                                             ———————————
     ———————————————————                    |   Server  |
    |   Client          |            \       ———————————
     ———————————————————    ----------      |           |
    |                   |            /       ———————————
     ———————|————————————                   |   func1() |
            |                               |   func2() |
            |                                ———————————
            |                               
    func(server) // 外加函数, 将来 有机会 搬到 Ssrver 类 中 
        return Server(arg.func1(), 
                      arg.func2()

(8) Introduce Local Extension
    动机
        想在 Server 类 中 add > 2 个函数, 但 无法 修改 Server 类
        
    做法
        将 想 add 的 函数 组织起来, 放到 为 Server 类 新建的 `子类 或 WrapperClass 中`

        首选 子类
            必须 产生1个 子类对象 -> 若 旧对象(Server) 也被 引用 
            => 同时有 2 个对象 保存了 original data 
                |
                |  若 original data 允许被 修改 => 出现问题
                | 
        再选 包装类 
            
                                             ———————————
     ———————————————————                    |   Server  |
    |   Client          |            \       ———————————
     ———————————————————    ----------      |           |
    |                   |            /       ———————————
     ———————|————————————                   |   func1() |
            |                               |   func2() |
            |                                ———————————
    Server(server.func1(), 
           server.func2()
                             | 
                             | Introduce Foreign Method
                            \|/
                                             ———————————
     ———————————————————                    |   Server  |
    |   Client          |            \       ———————————
     ———————————————————    ----------      |           |
    |                   |            /       ———————————
     ———————|————————————                   |   func1() |
            |                               |   func2() |
            |                                ———————————
            |                               
    func(server) 
                             | 
                             | 1) Introduce Local Extension (Subclass) 
                            \|/
                                             ———————————
     ———————————————————                    |   Server  |
    |   Client          |            \       ———————————
     ———————————————————    ----------      |           |
    |                   |            /       ———————————
     ————————|———————————                   |   func1() |
             |                              |   func2() |
             |                               ———————————
         subServer.func()                        /\         
        子类 对象                               /__\
                                                 |
                                                 |
                                                 |
                                             ———————————————————————                
                                            | SubServer             |
                                             ———————————————————————
                                            |                       |
                                             ———————————————————————
                                            |subServer(Server serv)-|— — — 转型 Ctor
                                            |                       |
                                            |   func()              |
                                             ———————————————————————
                 
    2) wrapperClass                                              
        
     ———————————————————    
    |   Client          |   
     ———————————————————    
    |                — —|— — — serverWrapper.func1() / func2()
     ————————|———————————   
             |              
             |  
            \|/
     ——————————————————————————                          ———————————
    | ServerWrapper            |                   \    |   Server  |
     ——————————————————————————     ————————————————     ———————————
    |   _server                |                   /    |           |
     ——————————————————————————                          ———————————
    |ServerWrapper(Server serv)|----转型 Ctor         |   func1() |
    |                   |      |                        |   func2() |
    | func1()           |                                ———————————
    |  | func2()               |    
     ——|————————————————|——————
       |                |
       |                |
    _server.func1   _server = serv

Chapter8 重新组织 数据


                        被 直接访问
                      /        |
                     /         |    
        对象 的 data          |  (1) SelfEncapsulate Field
     /               \         |
                      \       \|/
    |                   通过 访问函数 来访问

    |—— 哑 数据 -> 善表达的 对象
            (2) Replace Data Value with Object                                       
    |

    |—— 多个 相等 object, 想 将其替换为 1 个对象
            (3) Change Value (Object) to Reference (Object)

    |—— Array 行为像 数据结构 / Array 容纳 不同对象 -> 数组 替换为 对象, 数组中 每个 element 用 field 表示
            (4) Replace Array with Object -> Move Method 为 Object 加入 func 时, 好处才得以体现

    |—— (5) Replace Magic Number with Symbolic Constant

    |—— GUI 类 处理 不该它处理的 业务逻辑 -> 业务逻辑 移到 合适的 领域类 
            领域类 保存 逻辑相关的 data + (6) Duplicate Observed Data 提供对 GUI 的支持
    |       
                    public 数据   -> (7) Encalsulate Field        
    |             /
    |—— 类 公开了 — public 数据集 -> (8) Encalsulate Collection
                  \
    |               一整条记录    -> (9) Replace Record with Data Class

    |
    |               不影响 类的行为 -> (10) Replace Type Code with Class
     \            /
        type code - 影响 类的行为   -> (11) Replace Type Code with SubClass
                  \
                    影响 类的行为, 且 无法用 继承手法消除之 -> (12) Replace Type Code with Sate/Strategy
                    
                            
(1) SelfEncapsulate Field

    2种方法的优势
        1) 直接访问字段
                易读

        2) 通过 get()/set() 函数 间接访问 字段
            1) 子类 可将 该字段 的访问 改为 1个计算后的值 (即 子类类 Override 1个 函数 来 访问)
            2) 更灵活的 数据管理, 如 延迟初始化

    动机
        想 访问 Base 的 字段, 又想 在 子类中 将 该字段 的访问 改为 1个计算后的值 时, 用 SelfEncapsulate Field

    note
        ctor 与 set() 函数 不同, set() 函数 应该在 对象创建后 才使用 => ctor 可 调 另一 initialize() 函数

    做法
        private int _low, _high;
        boolean includes(int arg)
        {
            return arg >= low && arg <= _high;
        }
            |
            | 
           \|/

        private int _low, _high;

        boolean includes(int arg)
        {
            return arg >= getLow() && arg <= getHigh();
        }

        int getLow() { return _low; }
        int getHigh() { return _high; }


(2) Replace Data Value with Object                  
    动机
        数据项 的 content 不再 简单
        
    做法
        把 数据项 (及 相关信息) 变为 对象

     ———————————————————————    
    |   Order(订单)           |   
     ———————————————————————  
    | _customer: String     |   
     ———————————————————————|   
    | Order(String customer)|   
     ———————————————————————    
            |
            |
           \|/

     ———————————————————————————                     ——————————————————— 
    |   Order                   |               \   |   Customer        |
     ———————————————————————————  ———————————————    ——————————————————— 
    | _customer: Customer       |               /   |   _name           |
    |                           |                   |              — — -|— — — 后续加 _address 等               
     ———————————————————————————                     ———————————————————|
    |Order(String customerName) |                   |   func()          |
     ——————|—————————————————————                    ———————————————————
           |
           |
        _customer = new Customer(customerName)

    目前: 每个 Order 对象 都拥有自己的 Customer 对象,
        为给 Customer 类 加上 地址 电话 等 属性, 要用 Change Value to Reference 
        使得 属于 同一 Customer 的 `所有 Order 共享 同一 Customer 对象`
        
(3) Change Value (Object) to Reference (Object)         

    值对象: 每个对象 代表 真实世界 中的 1个实物
        "客户" "账户"
        
    引用对象: 完全由 自身所含 数据值 定义, 并不在意 copy 的 存在       
        "日期" "钱"

    何时该用 值/引用 对象?
                存 不可修改的数据 -> 值对象
             /
        对象 
             \
                存 不可修改的数据, 且 修改能 影响 所有 引用此对象的地方 -> 引用对象
            

                 多个 Customer 对象: 值对象 
               /        
              / 对
    1 个 客户 
              \ 应
               \
                 1 个 Customer 对象: 引用对象
                    1 个 客户的 所有 订单 (Order) 共享 同一 Customer 对象
                
     ———————————————————————————                     ——————————————————————————————— 
    |   Order                   |               \   |   Customer                    |
     ———————————————————————————  ———————————————    ——————————————————————————————— 
    | _customer: Customer       |               /   |   _name                       |
    |                           |                   |                               |           
     ———————————————————————————                     ——————————————————————————————— 
    |Order(String customerName) |                   |Customer(String customerName)  |
     ——————|—————————————————————                    —————————|—————————————————————
           |                                                  |
           |                                                  |
    _customer = new Customer(customerName)              _name = customerName
        
                                        | Replace Ctor with Factory Method
    Order:                              |    Customer
        Ctor 改为 调 Factory Method        |       1) 加 Factory Method: static create() 函数
                                        |       2) ctor 变 private
                                        |
                                       \|/
                

     ———————————————————————————                     ——————————————————————————————————————— 
    |   Order                   |               \   |   Customer                            |
     ———————————————————————————  ———————————————    ——————————————————————————————————————— 
    | _customer: Customer       |               /   |   _name                               |
    |                           |                    ———————————————————————————————————————                                        
     ———————————————————————————                    | - Customer(String customerName)       |
    |                           |                   |                |                      |
    |Order(String customerName) |                   | + create(String name): static Customer|
     ——————|—————————————————————                    ———————|————————|——————————————————————
           |                                                |           
           |                                                |        | 
    _customer = Customer::create(customerName)      return new Customer(name)

                |  
                |   (1) 如何访问 Customer 对象 ?  
                |   注册表 保存 所有 Customer 对象, 以 注册表 为访问点
                |
                |   public static Dictionary _instances = new Hashtable();
                |
                |                                   请求时创建
                |                                /
                |   (2) 何时创建 Customer 对象 ?
                |                                \
                |                                   预先创建好: APP 启动时, 预先加载 Customer 对象 —— 可能来自 数据库/文件
               \|/

             ——————————————————————————————————————— 
            |   Customer                            |
             ——————————————————————————————————————— 
            |   _name                               |
             ———————————————————————————————————————  
            | - Customer(String customerName)       |
            | loadCustomers(): static          -----|---- new Customer("lilei").store()
            | store()                          -----|---- _instances.put(this.getName(), this)  
            | create(String name): static Customer  |
             ———————|——————————————————————————————
                    |           
                    |        
            return (Customer) _instances.get(name)
                    |
                    | create() 总返回 已有对象 -> Rename Method
                    |
                   \|/
                getCustomerByName(String name)          
                    return (Customer) _instances.get(name)
        
        
Change Reference to Value:
    动机
        引用对象 小且不可变, 且 不易管理
        
    做法
        引用对象 变为 值对象

    不可变的 含义
        对象 本身不可变, 但 其 ClientObject 与 对象 间 关系可变
        
                Money1
              / 
        Person   
              \
                Money2

(4) Replace Array with Object                       

    String[] row = new String[3];
    row[0] = "Liverpool";
    row[1] = "15";
         |
         |
         |
        \|/
    String[] row = new Performance();
    row.setName("Liverpool");
    row.setWins("15");
        
(5) Replace Magic Number with Symbolic Constant

    double func(double mass, double height)
    {
        return mass * 9.81 * height;
    }
                 |
                 | Replace Magic Number with Symbolic Constant
                 |
                \|/
    static double GRAVITATIONAL = 9.81;

    double func(double mass, double height)
    {
        return mass * GRAVITATIONAL * height;
    }

(6) Duplicate Observed Data
    动机
        领域数据 在 GUI对象 中, 而 领域函数 要 访问 领域数据
        
    做法
        领域数据 copy 到 领域对象, 用 Observer 模式, 以 同步 领域对象 和 GUI 对象 中的 重复数据
        
    用户界面 与 业务逻辑 分离 的 好处
        (1) 可用不同界面 表现 相同业务逻辑
        (2) 两侧 维护和演化 更容易

    不完善的例子

     ———————————————————
    |   GUI             |
     ———————————————————
    |   GUI_field1      |
     ——————————————————— 
    | getText()         |
    | setText()         |
    | logicFunc()       |
     ———————|———————————
            |   
            |
        GUI_field1.getText()
        GUI_field1.setText()

            |
            |   想 不引用 GUI 类, 又能 getField1() -> 唯一办法: field1 copy 到 领域类, 并 与 GUI 类 field 同步
            |   
            |   Duplicate Observed Data
           \|/
    ———————————————————                                     ———————————————————                 
    |   Subject         |                                   |   GUI(Observer)   |                   
    ———————————————————     /\  
    |                   |  /  \___________________________  ———————————————————                 
    |   vec<Observer*>  |  \  /                             |   GUI_field1      |                   
    |   GUI_field1      |   \/                              |   _subject        |                   
    ———————————————————                                      ———————————————————                    
    | getText()         |                                   | Observer(Subject*)|— — —  _subject = new Subject();  
    | setText()         |                                   | update(Subject*)  |       _subject.attach(this); 
    | logicFunc()       |                                   |                   |       update(_subject)                
    | attach(Observer*) |                                   |                   |
    | setAndNotify()    |                                   |                   |                   
    ——————————————————                                       ——————————————————                     

(7) Encalsulate Field     
    动机
        封装 / 数据隐藏
    做法
        提供 set()/get() 函数

        public String _name;
             |
             | Encalsulate Field
             |
            \|/
        private String _name;
        public String getName() { return _name };
        public String setName(String arg) { _name = arg; }

(8) Encalsulate Collection
    动机
        函数 返回 集合
    做法
        让 函数 返回 集合的只读副本 + 类中 提供 addElem()/removeElem() 函数

    note
        集合 处理方式的 特殊性
            1) get() 函数 不应该 返回 集合自身, 否则, 对 Client 过多暴露 内部数据结构
            2) 不应该 为 集合 提供 set() 函数, 但 应提供 addElem()/removeElem() 函数

     ———————————————————————                             ———————————————————————————————    
    |   Person              |                           |   Person                      | 
     ———————————————————————                  \          ———————————————————————————————
    |                       |       - - - - - -         |                               |
     ———————————————————————                  /          ———————————————————————————————
    | getCourse(): Set      |                           | getCourse(): Unmodified Set   |
    | setCourse(): void     |                           | addCourse(:Course): void      | 
    |                       |                           | removeCourse(:Course)         |
     ———————————————————————                             ———————————————————————————————

(10) Replace Record with Data Class
    动机
        遗留程序, 要用 传统API 与 记录 交流, 或 处理 数据库 读出的 记录
        
    做法
        新建 接口类, 表示 记录
        对 记录中 每项数据, 在 类中 新建 private 字段 + get()/set() 函数

(11) Replace Type Code with Class
    动机
        类 中 type code 为 数值, 不影响 类 的 行为
    做法
        数值 type code -> Type 类


                         ———————————————————————————
                        |   Person                  |
                         ———————————————————————————
                        |   _bloodType: int         |
                        |   O: static int         ——| —— ——  = 0
                        |   A: static int           |
                         ———————————————————————————
                        | getBloodType(): int       |
                        | setBloodType(int ): void  |
                         ————————————————————————————
                             | 
                             | 
                            \|/

     ———————————————————————————————                         ———————————————————————————————————————
    |   Person                      |                    \  |   BloodType                           |
     ———————————————————————————————    ——————————————————  ————————————————————————————————————————
    |   _bloodType: BloodType       |                    /  |   _code: int                          |
    |   O: static int =         Bloo|dType:O:getCode()      |   O: static BloodType                 |
    |   A: static int               |                       |   A: static BloodType                 |
    |                               |                       |   _types = {O, A}: static BloodType[] |
     ———————————————————————————————                         ———————————————————————————————————————
    | getBloodTypeCode():int    ----|--_bloodType.getCode() | getCode() : int                       |
    | setBloodType(int ): void      |                       | getType(int): static BloodType    — — |— — return _types[arg]     
    | Person(int arg)               |                       |                                       |
     ———|————————————————————————————                        ———————————————————————————————————————
        |
        |
     _bloodType = BloodType::getType(arg)


(12) Replace Type Code with SubClass
    动机
        类 中 type code 为 数值, 影响 类 的 行为(据 不同 type code 执行 不同动作)
    做法
        以 多态 处理 变化
        
            Replace Type Code with SubClass
                以 type code 宿主类 为 Base 类, 对 每种 type code 建相应 Derived 类
                
                        +

            Replace Conditional with Polymorphism


     ———————————————————————————————————————
    |   Employee                            |
    ————————————————————————————————————————
    |   _type: int                          |
    |   ENGINEER: static int = 0            |
    |   SALESMAN: static int = 1            |
     ———————————————————————————————————————
    | Employee(int type)                    |
    | getType(int): int                     | 
     ———————————————————————————————————————
        | 
        |  1) Factory Method
        |/
     ———————————————————————————————————————
    |   Employee                            |
     ————————————————————————————————————————
    |   _type: int                          |
    |   ENGINEER: static int = 0            |
    |   SALESMAN: static int = 1            |
     ———————————————————————————————————————
    | - Employee(int type)                  |
    | + create(int type): static Employee   | 
     —————|——————————————————————————————————
          |
      return new Employee(type)  

             |   2) 建子类 Engineer + override getType() { return Employee::ENGINEER; }
             |   3) 修改 Factory Method, 以 return 合适 对象
             |   
            \|/
     
     ———————————————————————————————————————
    |   Employee                            |
     ————————————————————————————————————————
    |   _type: int                          |
    |   ENGINEER: static int = 0            |
    |   SALESMAN: static int = 1            |
     ———————————————————————————————————————
    | - Employee(int type)                  |     // switch 只在 创建 对象 时有
    | + create(int type): static Employee  —|— —  switch(type) {
     ———————————————————————————————————————            case ENGINEER:
                    /\                                      return new Engineer();
                   /__\                           } 
                    |
                    |
         ———————————————————
        |   Engineer        |
         ———————————————————
        |                   |
         ———————————————————
        | - getType(): int  |
         —————|——————————————
              | 
              |
             return Employee::ENGINEER;
                     
                              | 
                              | Push Down Method/Field 将 特定雇员 相关的 func/field 下推到 相关子类
                              | 
                              |  4) 对 除过 Factory Method 之外的 func, 若有 switch -> 由 Employee 的 vf 多态 地 派遣到 各 Derived 类 去具体实现
                              |     Replace Conditional with Polymorphism
                             \|/



(13) Replace Type Code with Sate/Strategy
    动机
        type code 可变 => 不能用 继承 消除它
    做法
        type code 替换为 状态对象

         ———————————————————————————————
        |   Employee                    |
         ———————————————————————————————
        |   _type: int                  |
        |   ENGINEER: static int = 0    |
        |   SALESMAN: static int = 1    |
         ———————————————————————————————
        | Employee(int type)            |
        | func()                      ——|— — switch(getType() ) {
        | getType()                     |       case ENGINEER:  return ...
         ——————————————————————————————— 
            |
            |
            |/
         
         ———————————————————————————————                         ———————————————————————————————
        |   Employee                    | 新建类, 据 type code  |   EmployeeType                |
         ———————————————————————————————                      \  ———————————————————————————————
        |   _type: EmployeeType         |   ——————————————————  |                               |
        |   ENGINEER: static int = 0    |   命名,即 状态对象  /     ———————————————————————————————
        |   SALESMAN: static int = 1    |                       | getTypeCode():virtual int = 0 |— — — 虚 查询函数, 返回 type code
         ———————————————————————————————                        |                               |
        | Employee(int type)            |                        ——————————————————————————————— 
        | func()                        |                                   /\  
        | getType(): int                |                                  /__\
        | setType(int arg)              |                                   |    add 子类: 每个 子类 对应1中 type code
         ————|———————————————————————————                                   |
             |                                                      ———————————————————————————————
             |                                                      |   Engineer                    |
        switch (arg){                                                ———————————————————————————————
            case ENGINEER:                                          |                               |
                _type = new Engineer();                             ———————————————————————————————
                break;                                              | getTypeCode(): int         — —|— — return Employee::ENGINEER
        }                                                           |                               |
                                                                     ——————————————————————————————— 
            |   
            |
            |/

         ———————————————————————————————                         —————————————————————————————————————————
        |   Employee                    |                       |   EmployeeType                          |
         ———————————————————————————————                     \   —————————————————————————————————————————
        |   _type: EmployeeType         |   ——————————————————  |       ENGINEER: static int = 0          |
        |                               |                    /   —————————————————————————————————————————
        |                               |       - - - - - - - - |-  getTypeCode():virtual = 0             |
         ———————————————————————————————       /   - - - - - - -| - newType(int code): static EmployeeType|  switch(code) {
        | Employee(int type)            |     /   /              —————————————————————————————————————————      case ENGINEER: return new Engineer();     
        | func()                        |    /   /                          /\  
        | |         getType(): int      |   /   /                          /__\
        | |  setType(int arg)   |       |  /   / 源类 查询/setType 函数       |
         —|———|—————————————————|———————  /   /     转发 给 状态对象       |
          |   |         _type.getTypeCode()  /                      ———————————————————————————————
          |   |                             /                       |   Engineer                    |
          |  _type = EmployeeType::newType(arg)                     ———————————————————————————————
          |                                                         |                               |
          |                                                         ———————————————————————————————
        switch(getType() ) {                                        | getTypeCode()              — —|— — return EmployeeType::ENGINEER
            case EmployeeType::ENGINEER :                           |                               |
                return ...                                           ——————————————————————————————— 

                                        |
                                        |  Replace Conditional with Ploymorphism
                                        |
                                        |/
                                

(14) Replace Subclass with Fields
    动机
        子类 只有常数函数
    做法
        把 子类 的 常数函数 变为 父类 的 field + 相应 func

                 ———————————————————————————    
                |   Person                  |   
                 ———————————————————————————  
                |                           |   
                 ———————————————————————————
                | isMale(): bool            |
                | getCode(): char vitual = 0| 
                 ———————————————————————————    
                          /\
                         /——\
                          | 
                    _ _ _ | _ _ _ _ _ _ _ _
                   |                       |
     ———————————————————                 ———————————————————    
    |   Male            |               |   Female          |   
     ———————————————————                 ——————————————————— 
    |                   |               |                   |   
     ———————————————————                 ———————————————————
    | isMale(): bool    |               | isMale(): bool    |
    | |  getCode():char |               | |  getCode(): char| 
     —|————————————|—————                —|—————————|————————   
      |            |                      |         |
      |            |                      |         |
    return true   return 'M'         return true return 'F'
     
                         |  
                         |
                         | Derived 类 每个 常量函数 -> 在 Base 类中 加 1 个 field
                         |
                         | (1) Relpace Ctor with Factory Method
                         | (2) Replace Subclass with Fields
                        \|/
         —————————————————————————————————  
        |   Person                        |     
         —————————————————————————————————  
        |   _isMale                       |     
        |   _code                         |
         —————————————————————————————————
        | isMale(): bool               — —| — —  return _isMale
        | createMale(): Person static  — —| — —  return new Male();
        | createFemale(): Person static   |
        | # Person(bool isMale, char code)| 
         ——————|——————————————————————————— 
               |         /\
    _isMale = isMale    /__\
    _code = code          |
                          | 
                    _ _ _ | _ _ _ _ _ _ _ _
                   |                       |
     ———————————————————                 ———————————————————    
    |   Male            |               |   Female          |   
     ———————————————————                 ——————————————————— 
    |                   |               |                   |   
     ———————————————————                 ———————————————————
    | Male()            |               | Female()          |
     —|—————————————————                |—————————|—————————    
      |                                           |         
      |                                           |         
    Person(true, 'M')                       Person(false, 'F')  
                         |  
                         |
                         | (3) Inline Method
                        \|/
     
             —————————————————————————————————  
            |   Person                        |     
             —————————————————————————————————  
            |   _isMale                       |     
            |   _code                         |
             —————————————————————————————————
            | isMale(): bool               — —| — —  return _isMale
            | createMale(): Person static  — —| — —  return new Person(true, 'M');
            | createFemale(): Person static   |
            | # Person(bool isMale, char code)| 
             ——————|——————————————————————————— 
                   |
                _isMale = isMale 
                _code = code 

Chapter9 简化 条件表达式 (Conditional Expression)

    条件逻辑 可能很复杂

        分离 分支逻辑 与 操作细节
            (1) Decompose(分解) Conditional
     /
    |—— 多处测试有相同结果
            (2) Consolidate(合并) Conditional
                   
    |—— 条件代码中 重复
            (3) Consolidate Duplicate Conditional Fragments(重复条件代码段)    
                   
    |—— 想 非单一出口
            标识 特殊情况
    |           (4) Replace Nested Conditional(嵌套条件) with Guard Clause(卫语句)    
            +   
    |       去除 控制标记
                (5) Remove Control Flag (控制标志)
                   
    |—— OO 中 条件行为 被 多态 替换为
            多态的好处: caller 无需了解 条件行为的细节 => 条件的 扩展更容易 
    |       (6)Replace Conditional with Ploymorphism(多态)
     \      
        去除对 null 值 的 检验
            (7) Introduce Null Object      
           
(1) Decompose Conditional              
    动机
        条件太复杂
        
    做法
        条件 -> 条件函数: 更好地表达用途
               

    if(data.before(SUMMER_START) || data.after(SUMMER_END))
        charge = quantity * _winterRate + _winterServiceCharge;
    else
        charge = quantity * _summerRate;
        
        |
        |   bool notSummer(Date date){
        |       return data.before(SUMMER_START) || data.after(SUMMER_END); 
        |   }   
       \|/
            
    if ( notSummer(date) )
        charge = winterCharge(quantiy);
    else
        charge = summerCharge(quantiy);

(2) Consolidate Conditional        
    动机
        d多个 条件, 得 相同结果
    做法
        条件 合并 -> Extract Method 提炼为 函数
        
    1) 或
    double func(){
        if(_field1 < 2) return 0;
        if(_field2 > 12) return 0;
        // compute other
    }
        | 
        |  
       \|/ 

    double func(){
        if(_field1 < 2 || _field2 > 12) return 0;
        // compute other
    }
        |   bool isDisabled(){
        |       return (_field1 < 2 || _field2 > 12)
        |   }
       \|/

    double func(){
        if( isDisabled() ) return 0;
        // compute other
    }
        
    2) 与
    if( isConditional1() )
        if( isConditional2() )
            return 1;
    return 0.5;

        | 
        |  
       \|/ 

    if( isConditional1() && isConditional2() ) return 1;
    else return 0.5;

        | 
        |  
       \|/ 

    return ( isConditional1() && isConditional2() ) ? 1 : 0.5;  
            
    3) 条件复杂 -> Extract Method 先 提炼出 一部分, 使 条件简单
    

    
(3) Consolidate Duplicate Conditional Fragments            
    动机
        条件表达式 的 每个分支上 都有 一段相同代码
        
    做法         
        重复代码 搬到 条件表达式 外    
               
    if(isSpecialDeal(0 ){
        total = price * 0.95;
        send();
    }
    else{
        total = price * 0.98;
        send(); 
    }
        | 
        |  
       \|/ 

    if(isSpecialDeal(0 ){
        total = price * 0.95;
    }
    else{
        total = price * 0.98;   
    }
    send();
           
(4) Replace Nested Conditional with Guard Clause(卫语句)                      
    动机
        难以看清 条件的 执行路径
               
    做法
        卫语句 替换 特殊情况
        
    double get()
    {
        double result;
        
        if(_isConditioal1)
            result = func1();
        else
        {
            if(_isConditioal2)
                result = func2();
            else
                result = func3();
        }
        return result;
    }
            | 
            |  
           \|/ 
        
    double get()
    {
        if(_isConditioal1)
            return func1();     
        if(_isConditioal2)
            return func2();
        return func3(); 
    }

    
(5) Remove Control Flag        
           
    动机
        控制标记 使 可读性 变差
    做法
        Control Flag 替换为 break / return -> 条件语句的用途会清晰很多

    1) found 只是 control flag    
    void isFound(String[] people)
    {
        bool found = false;
        for(int i = 0; i < people.length; i++)
        {
            if(!found)
            {
                if(people[i] == "Lilei")
                {
                    // ...
                    found = true
                }
                
                if(people[i] == "hanmei")
                {
                    // ...
                    found = true
                }
            }
        }
    }
                |  1) found == true 时, 搜索结束 => 可 替换为 break
                |  2) 对 control flag 的 引用都去掉
               \|/  
    void isFound(String[] people)
    {
        for(int i = 0; i < people.length; i++)
        {
            if(people[i] == "Lilei")
            {
                // ...
                break;
            }
            
            if(people[i] == "hanmei")
            {
                // ...
                break;
            }
        }
    }          
               

    2) found 既是 control flag, 又是 运算结果
        -> found 计算代码 提到 1个 函数

    void checkAndCalc(String[] people)
    {
        String found = "";
        for(int i = 0; i < people.length; i++)
        {
            if(found == "")
            {
                if(people[i] == "Lilei")
                {
                    // ...
                    found = "Lilei"
                }
                
                if(people[i] == "hanmei")
                {
                    // ...
                    found = "hanmei"
                }
            }
        }
        
        laterFunc(found);
    }
                |  1) found == true 时, 搜索结束 => 可 替换为 break
                |  2) 对 control flag 的 引用都去掉
               \|/  
               
    void checkAndCalc(String[] people)
    {
        String found = foundPerson(people);
        laterFunc(found);
    }          
               
    String foundPerson(String[] people)
    {
        for(int i = 0; i < people.length; i++)
        {
            if(people[i] == "Lilei")
            {
                // ...
                return "Lilei";
            }
            
            if(people[i] == "hanmei")
            {
                // ...
                return "hanmei";
            }
        }
        return "";
    }              
           
(6) Replace Conditional with Ploymorphism
    动机
        条件表达式 据 对象的不同类型 采取 不同的行为
    做法
        把 条件表达式的 每个分支 放进 子类的 OverrideFunc, 原 函数 变为 vf
        
    note
        多态的好处
            // 说法 1
            使得不必写 explicit 条件表达式
            
            // 说法 2
            不必再 询问 对象 "你是什么类型", 再跟进得到的答复 调 对象的 某 func —— 直接调 该行为 即可
            
            // 说法 3
                              条件表达式: find + update `所有 条件表达式`
                            /
            增加1种 类型 时 
                            \
                              多态: 只需 增加1个 `子类`, 并在其中提供适当 `函数`
                          
     ———————————————————————————————                         —————————————————————————————————————————
    |   Employee                    |                       |   EmployeeType                          |
     ———————————————————————————————                     \   —————————————————————————————————————————
    |   _type: EmployeeType         |   ——————————————————  |       ENGINEER: static int = 0          |
    |                               |                    /   —————————————————————————————————————————
    |                               |       - - - - - - - - |-  getTypeCode():virtual = 0             |
     ———————————————————————————————       /   - - - - - - -| - newType(int code): static EmployeeType|  switch(code) {
    | Employee(int type)            |     /   /              —————————————————————————————————————————      case ENGINEER: return new Engineer();     
    | func()                        |    /   /                          /\  
    | |         getType(): int      |   /   /                          /__\
    | |  setType(int arg)   |       |  /   / 源类 查询/setType 函数       |
     —|———|—————————————————|———————  /   /     转发 给 状态对象       |
      |   |         _type.getTypeCode()  /                      ———————————————————————————————
      |   |                             /                       |   Engineer                    |
      |  _type = EmployeeType::newType(arg)                     ———————————————————————————————
      |                                                         |                               |
      |                                                         ———————————————————————————————
    switch(getType() ) {                                        | getTypeCode()              — —|— — return EmployeeType::ENGINEER
        case EmployeeType::ENGINEER:                            |                               |
            return _monthlySalary;                              ——————————————————————————————— 

                                            |
                                            |  1) Employee::func 中 switch 从 Employee 移到 EmployeeType
                                            |
                                            |/      


     ———————————————————————————————                         —————————————————————————————————————————
    |   Employee                    |                       |   EmployeeType                          |
     ———————————————————————————————                     \   —————————————————————————————————————————
    |   _type: EmployeeType         |   ——————————————————  |       ENGINEER: static int = 0          |
    |                               |                    /   —————————————————————————————————————————
    |                               |       - - - - - - - - |-  getTypeCode():virtual = 0             |
     ———————————————————————————————       /   - - - - - - -| - newType(int code): static EmployeeType|— — —  switch(code) { case ENGINEER: return new Engineer();     }
    | Employee(int type)            |     /   /      /------|-- func(Employee emp):int               —|— — switch(getTypeCode()){
    |                               |               /        —————————————————————————————————————————          case ENGINEER: 
    | func():int                    |    /   /     /                    /\                                          return emp.getMonthlySalary();
    | |         getType(): int      |   /   /     /                    /__\                                     
    | |  setType(int arg)   |       |  /   /     /                      |
     —|———|—————————————————|———————  /   /     /                       |
      |   |         _type.getTypeCode()  /     / 转发          ———————————————————————————————
      |   |                             /     /                 |   Engineer                    |
      |  _type = EmployeeType::newType(arg)  /                   ———————————————————————————————
      |                                     /                   |                               |
      return _type.func(this) —— —— —— —— ——                     ———————————————————————————————
                                                                | getTypeCode()              — —|— — return EmployeeType::ENGINEER
                                                                |                               |
                                                                 ——————————————————————————————— 
                |
                |  2) Base 类 switch 语句 — — — 相应某 Derived 类 的分支 -> copy 到 Derived 类 
                |     Base 类 switch 语句 所在 func -> virtual func(vf)
                |/

     ———————————————————————————————                         —————————————————————————————————————————
    |   Employee                    |                       |   EmployeeType                          |
     ———————————————————————————————                     \   —————————————————————————————————————————
    |   _type: EmployeeType         |   ——————————————————  |       ENGINEER: static int = 0          |
    |                               |                    /   —————————————————————————————————————————
    |                               |       - - - - - - - - |-  getTypeCode():virtual int = 0         |
     ———————————————————————————————       /   - - - - - - -| - newType(int code): static EmployeeType|— — —  switch(code) { case ENGINEER: return new Engineer();     }
    | Employee(int type)            |     /   /      /- ----|---func(Employee emp): virtual int = 0   |
    |                               |               /        —————————————————————————————————————————          
    | func():int                    |    /   /     /                    /\                                          
    | |         getType(): int      |   /   /     /                    /__\                                     
    | |  setType(int arg)   |       |  /   /     /                      |
     —|———|—————————————————|———————  /   /     /                       |
      |   |         _type.getTypeCode()  /     /                 —————————————————————————
      |   |                             /     /                 |   Engineer              |
      |  _type = EmployeeType::newType(arg)  /                   —————————————————————————
      |                                     /                   |                         |
      return _type.func(this) —— —— —— —— ——                     —————————————————————————
                                                                | getTypeCode()           | 
                                                                | func(Employee emp): int |
                                                                 —————|———————————————————
                                                                     |
                                                                     |
                                                                return emp.getMonthlySalary();
                      
(7) Introduce Null Object
    动机
        需要 多次 check 对象 是否为 null
    做法
        null 值 替换为 null 对象
        
        
     ———————————————————————————        
    |   Customer                |       
     ———————————————————————————  
    |                           |   
     ———————————————————————————                    if (customer == null) plan = INVALID;
    |                           |                   else plan = customer.getPlan();
    |   getSalary(): double     |   
     ———————————————————————————                        
     |                                                          |                   
     |  1) Base/Derived 均增加 isNull()                        | 3) 对象 == null 的 条件测试 -> 替换为 -> 无条件 动作
     |  2) Derived 再增加 null 条件时 相应的 overrideFunc       | 
     |/                                                         |/
     
     ———————————————————————————                        plan = customer.getPlan();
    |   Customer                |   
     ———————————————————————————                    
    |                           |   
     ———————————————————————————    
    |   isNull():bool        — —|— — return false;
    |   getSalary():double      |   
     ———————————————————————————    
             /\     
            /__\        
             |
             |
      ———————————————————————————   
     |  getSalary()             |   
      ———————————————————————————  
     |                          |   
      ———————————————————————————   
     |   isNull():bool       — —|— — return true;
     |   getPlan():double    — —|— — return INVALID;
      ———————————————————————————   
      

Chapter10 简化函数调用: OO 中 简化 interface 的 重构手法

        函数名 未揭示 函数用途 
     /      (1) Rename Method
    | 
    |—— func 修改后 需要 以前没有的信息
            (2) Add Para
                    |
    |               | 相反
                    |
    |—— func body 不再需要 某 Para 
            (3) Remove Para
    |   
            特例: 多态 func 的 另一份 又要用 该 para -> 不要 Remove Para
    |
                                    来自 同一对象的 -> 改为 传递 整个对象
                                 /      (4) Preserve Whole Object
    |——  多个 mem 被当 para 传递
                                 \
                                    先前 不存在 这样的对象 -> 创建之
    |                                   (5) Introduce Para Object

    |—— func 的 para 来自 func 可获取的 另一 func1 
            (6) Replace Para with Method

    |—— para 有 多个取值, 而 func 内 条件表达式 据 不同 para 值 做不同行为 -> 对 para 的每个可能值, 建一 func
            (7) Replace Para with Explicit Methods
    |       好处: 编译期检查
              
    |—— 2 个函数 做 类似工作, body 中 包含不同值 -> 用 para 处理变化 + 合并 2 个函数
            (8) Parameterize Method 
            
    |—— func 既返回 对象状态, 又修改 对象状态 -> 用 get() / set() 函数 分别处理 查询 / 修改
            (9) Separate Query from Modifier
    |       note
                并发
    |                                            query()
                                               /    
    |                                         / 调
                    3 个函数: queryAndModify()
    |                                         \ 用
                                               \
    |                                            modify()
                                                     
    |                       
                                类 某 field 只在 对象创建时 set, 后续 不再改变 -> 去掉 该 field 的 set() 函数
    |                               (10) Remove Setting Method      
                            /
    |—— 隐藏不必要暴露的东西                                       
                            \
                                memFunc 从没被 other 类 用过 -> memFunc 改为 private
    |                               (11) Hide Method        
                
    |               client 直接调 Ctor: client 需知道 对象类型
     \            /
        对象 创建   
                  \
                    client 通过调 Factory Method  间接调 Ctor: client 无需知道 对象类型
                        (12) Replace Ctor with Factory Method
                        
(4) Preserve Whole Object

    int low = Range().getLow();
    int high = Range().getHigh();
    result = plan.withinRange(low, high);
         |
         | 
         | 
         |/
    result = plan.withinRange( Range() );

(5) Introduce Para Object                           

     ———————————————————————————————    
    |   Customer                    |   
     ———————————————————————————————    
    |                               |   
     ———————————————————————————————    
    |   func(start: Date, end: Date)|   
     ———————————————————————————————    
                 |
                 | 
                 | 
                 |/
      ———————————————————————————   
     |  Customer                |   
      ———————————————————————————    
     |                          |   
      ———————————————————————————   
     |  func(DateRange)         |
      ——————————————————————————    

(6) Replace Para with Method

    int basePrice = _quantity * _itemPrice;
    discountLevel = getDiscountLevel();
    double price = discountedPrice(basePrice, discountLevel);
             |
             |  
             | discountedPrice() 可直接调 getDiscountLevel()
             |/

    int basePrice = _quantity * _itemPrice;
    double price = discountedPrice(basePrice);

(7) Replace Para with Explicit Methods
    void setValue(String name, int value)
    {
        if(name == "height")
        {
            _height = value;
            return;
        }
        if(name == "width")
        {
            _width = value;
            return;
        }
    }
             |
             | 
             | 
             |/

    void setHeight(int arg)
    {
        _height = arg;
    }

    void setWidth(int arg)
    {
        _width = arg;
    }

(8) Parameterize Method

     ———————————————————————————    
    |       Employee            |   
     ———————————————————————————    
    |                           |   
     ———————————————————————————    
    |   fivePercentRaise()      |   
    |   tenPercentRaise()       |   
     ———————————————————————————    
                 |
                 | 
                 | 
                 |/
      ———————————————————————————   
     |      Employee            |   
      ———————————————————————————    
     |                          |   
      ———————————————————————————   
     |  raise(percent: double)  |
      ——————————————————————————    


(9) Separate Query from Modifier

     ———————————————————————————    
    |   Customer                |   
     ———————————————————————————    
    |                           |   
     ———————————————————————————    
    |   getAndSet()             |   
    |                           |   
     ———————————————————————————    
                 |
                 | 
                 | 
                 |/
      ———————————————————————————   
     |  Customer                |   
      ———————————————————————————    
     |                          |   
      ———————————————————————————   
     |  get(): int              |
     |  set(): void             |
      ——————————————————————————    
  
  
(12) Replace Ctor with Factory Method

    public Employee (int type)
    {
        _type = type;
    }

            | 1) ctor: public -> private
            | 2) 增加 static Factory Method
            |/

    static Employee create(int type)
    {
        return new Employee(type);
    }


    private Employee (int type)
    {
        _type = type;
    }

Chapter11 处理 ( 类的 ) 概况关系


                                        (1/2) Pull Up Field / Method
                                     /          两个 Derived 类 拥有 `共同 memData/memFunc` -> memData/memFunc 上移 到 Base 类
                                    
                                    |—— (3/4) Pull Down Field
                                                Base 类 中 某 memData/memFunc 只被 部分 Derived 类 用到 -> 该 memData/memFunc 下移到 需要它的 Derived 类
继承体系中 上/下 移 field / method  |   
                                    
                                    |               (5) Pull Up Ctor Body
                                     \            /     各 Derived 类 的 Ctor Body 大体相同 -> Derived Ctors 的 Common Part 上移到 Base 类 `新建的 Ctor` +  Derived Ctors 调用之
                                        Ctor 特殊     note: Ctor 不会被继承 => 这里不能用 Pull Up Method
                                                  \
                                                    不会下推 Ctor, Replace Ctor with Factory Method 更管用
                        
                                    (6) Extract DerivedClass
                                  /         class 中 `某些 特性` 只被 `部分 instance 用到`
                                 /          -> 将这些 特性 移到 新建的 子类
                                /                           
继承体系 不同位置 新建/消除类    ——  (7) Extract BaseClass                                   
                                \           2 个类 有相似特性 -> 相似特性 移至 新建的 Base 类
                                 \
                                    (8) Collapse(折叠) Hierarchy
                                            Derived 类 价值                           不大 -> 合并到 Base 类: mem Pull Up
                                            
                                            (9) Replace Inheritance with Delegation
                                          /         Base 中 许多行为 并不真正适用于 Derived
                                                    -> Derived 中 放 Base 类型的 mem + Derived 中 func 改为 委托 _baseMem 去调用 
最佳选择 并非 继承(委托), 而是 委托(继承)           
                                          \
                                            (10) Replace Delegation with Inheritance 
                                            
                                            
2个 Derived 类 中 均有 `某段 code 大体相同` -> 分离 共同点 和 不同点 
    (11) Form Template Method                                                                                       
            commonPartFunc 作 non-vf 上移至 Base 
                                    \
                                     \ 调
                                      \/ 
                            Base 中 作 vf
                          /              \_ _ _ _ _ _ _ _ 延迟(到 Derived) 计算
            diffPartFunc                                 \
                          \                               \/
                            Derived1/Derived2 中 不同计算: 多态
                            
(6) Extract DerivedClass
        
     ———————————————————————————    
    |   JobPrice                |   
     ———————————————————————————    
    | _unitPrice: int           |   
    | _quantity : int           |
    | _isLabor  : bool (按工时) | 
    | _employee : Employee      |
     ———————————————————————————
    |   getUnitPrice():int   — —|— — — return (_isLabor) ? _employee.getRate() : _unitPrice
    | + JobPrice(4 paras)       |
     ———————————————————————————    
        |
        | class 中 某些特性(_isLabor 和 _employee) 只被 部分(按工时) instance 用到
        | => 将这些 特性 移到 新建的 子类
        | 1) 新建 Derived 类
        | 2) _employee 字段 只在 `继承体系 内部用` => 设为 protected
        |/
     ———————————————————————————————————————————    
    |   JobPrice                                |   
     ———————————————————————————————————————————    
    |  _unitPrice: int                          |   
    |  _quantity : int                          |
    |  _isLabor  : bool (按工时)               | 
    |# _employee : Employee                     |
     ———————————————————————————————————————————
    | + JobPrice(2 paras: unitPrice, quantity) —|— — JobPrice(unitPrice, quantity, false, null)
    |     |                                     |
    | # JobPrice(4 paras)                       |
    |   getUnitPrice():int                   — —|— — — return (_isLabor) ? _employee.getRate() : _unitPrice
     ———————————————————————————————————————————    
                /\                                  
               /__\                                 
                |   
                |   
     —————————————————————————————————
    |   Labor                         | 
     —————————————————————————————————  
    |                                 |
     —————————————————————————————————
    | + Labor(quantity, employee)    —|— — JobPrice(0, quantity, true, employee)
     —————————————————————————————————  
            |
            |   3) _isLabor 字段 只在 `继承体系 内部用`, 且 `只作为 Conditional 的 type code`
            |     => 移除 
            |           1> SelfEncapsulate Field
            |           2> 访问函数 -> 多态常量函数
            |/
     ———————————————————————————————————————————    
    |   JobPrice                                |   
     ———————————————————————————————————————————    
    |   _unitPrice: int                         |   
    |   _quantity : int                         |
    | # _employee
     ———————————————————————————————————————————
    | + JobPrice(2 paras: unitPrice, quantity) —|— — JobPrice(unitPrice, quantity, null)
    |     |                                     |
    | # JobPrice(3 paras)                       |
    |   getUnitPrice():int                   — —|— — — return ( isLabor() ) ? _employee.getRate() : _unitPrice
    | # isLabor():bool                       — —|— — — return false
     ———————————————————————————————————————————    
                /\                                  
               /__\                                 
                |   
                |   
     —————————————————————————————————
    |   Labor                         | 
     —————————————————————————————————  
    |                                 |
     —————————————————————————————————
    | + Labor(quantity, employee)    —|— — JobPrice(0, quantity, employee)
    | # isLabor():bool             — —|— — — return true
     —————————————————————————————————  
            |
            | 4) 对 条件表达式 isLabor() 的 Cient getUnitPrice() 
            |    用 Replace Coditional with Ploymorphism 重构
            |/

     ———————————————————————————————————————————    
    |   JobPrice                                |   
     ———————————————————————————————————————————    
    |   _unitPrice: int                         |   
    |   _quantity : int                         |
    | # _employee: Employee                     |
     ———————————————————————————————————————————
    | + JobPrice(2 paras: unitPrice, quantity) —|— — JobPrice(unitPrice, quantity, null)
    |     |                                     |
    | # JobPrice(3 paras)                       |
    |   getUnitPrice():int                   — —|— — — return _unitPrice
    | # isLabor():bool                       — —|— — — return false
     ———————————————————————————————————————————    
                /\                                  
               /__\                                 
                |   
                |   
     —————————————————————————————————
    |   Labor                         | 
     —————————————————————————————————  
    |                                 |
     —————————————————————————————————
    | + Labor(quantity, employee)  — —|— — JobPrice(0, quantity, employee)
    | # isLabor():bool             — —|— — — return true
    |   getUnitPrice(): int        — —|— — — return _employee.getRate()
     —————————————————————————————————  
            | 
            |   5) _employee 字段 只在 `继承体系 的 Derived 类 用` 
            |   => 从 Base 类 移至 Derived 类  
            |/
     ———————————————————————————————————————————    
    |   JobPrice                                |   
     ———————————————————————————————————————————    
    |   _unitPrice: int                         |   
    |   _quantity : int                         |
     ———————————————————————————————————————————
    | + JobPrice(2 paras: unitPrice, quantity)  |
    |   getUnitPrice():int                   — —|— — — return _unitPrice
    | # isLabor():bool                       — —|— — — return false
     ———————————————————————————————————————————    
                /\                                  
               /__\                                 
                |   
                |   
     —————————————————————————————————
    |   Labor                         | 
     —————————————————————————————————  
    | # _employee: Employee           |
     —————————————————————————————————
    | + Labor(quantity, employee)  — —|— — JobPrice(0, quantity); _employee = employee;
    | # isLabor():bool             — —|— — — return true
    |   getUnitPrice(): int        — —|— — — return _employee.getRate()
     —————————————————————————————————  

(9) Replace Inheritance with Delegation
动机
    Base 中 许多行为 并不真正适用于 Derived
    
     ———————————————————
    |   Base            |   
     ———————————————————    
    |                   |   
     ———————————————————
    |   func()          |
     ———————————————————    
            /\                                  
           /__\                                 
            |                   
            |                   
     ———————————————            
    |   Derived1    |           
     ———————————————            
    |               |           
     ———————————————            
    |               |           
     ———————————————            
                | 
                |
                |
                |/
                
     ———————————————                     ———————————————————
    |   Derived1    |                   |   Base            |   
     ———————————————                     ———————————————————    
    |   _base: Base | /\______________\ |                   |   
     ———————————————  \/              /  ———————————————————
    |   func        |                   |   func()          |
     ————|———————————                    ———————————————————    
         |  委托 _base 去 调用
         | 
        _base.func()

(11) Form Template Method   

             ———————————————————
            |   Base            |   
             ———————————————————    
            |                   |   
             ———————————————————
            |                   |
             ———————————————————    
                        /\                                  
                       /__\                                 
                        |   
         _ _ _ _ _ _ _ _|_ _ _ _ _ _ _ _ _              
        |                                 |
 ———————————————                     ———————————————
|   Derived1    |                   |   Derived1    |   
 ———————————————                     ———————————————    
|               |                   |               |
 ———————————————                     ———————————————
|   func()      |                   |   func()      |
 ————|———————————                    ————|———————————   
     |                                   |
     |                                   |
double base = _units * _rate;       double base = _units * _rate * 0.5;
double tax = base * Rate;           double tax = base * Rate * 0.2;
return base + tax;                  return base + tax;

                    |    commonPartFunc 作 non-vf 上移至 Base 
                    |                           \
                    |                            \ 调
                    |                             \/ 
                    |                   Base 中 作 vf
                    |                 /              \_ _ _ _ _ _ _ _ 延迟(到 Derived) 计算
                    |    diffPartFunc                                \
                    |                 \                               \/
                    |/                  Derived1/Derived2 中 不同计算: 多态

             ———————————————————————————
            |   Base                    |   
             ———————————————————————————    
            |                           |   
             ———————————————————————————
            | func()                 — —|— — — return getBase() + getTax()
            | getBase(): double virtual |
            | getTax() : double virtual |
             ———————————————————————————    
                        /\                                  
                       /__\                                 
                        |   
         _ _ _ _ _ _ _ _|_ _ _ _ _ _ _ _ _              
        |                                 |
 ———————————————                     ———————————————        
|   Derived1    |                   |   Derived1    |       
 ———————————————                     ———————————————        
|               |                   |               |       
 ———————————————                     ———————————————        
| getBase( )    |                   | getBase()    —|— — return  getUnits() * getRate() * 0.5;
| getTax( )     |                   | getTax()     —|— — return getBase() * Rate * 0.2;
 ———————————————                     ———————————————    

Chapter12 大型重构

    1. 分解继承体系:
     
        Bridge 模式
                    is-a 属性: 继承
                  / 
            分离
                  \
                    has-a 属性: 委托
        
                 ———————————————————
                |   Shape           |   
                 ———————————————————    
                |                   |   
                 ———————————————————
                |                   |
                 ———————————————————    
                            /\                                  
                           /__\                                 
                            |   
             _ _ _ _ _ _ _ _|_ _ _ _ _ _ _ _ _              
            |                                 |
     ———————————————                     ———————————————
    |   Circle      |                   | Rectangle     |   
     ———————————————                     ———————————————    
    |               |                   |               |
     ———————————————                     ———————————————
    |               |                   |               |
     ———————————————                     ———————————————    
        /\                                      /\  
       /__\                                    /__\
        |                                       |   
        |                                       |
     ———————————————                         ———————————————
    |   RedCircle   |                       | RedRectangle  |   
     ———————————————                         ———————————————    
    |               |                       |               |
     ———————————————                         ———————————————
    |               |                       |               |
     ———————————————                         ———————————————    
                        |   
                        |   
                        |/  
                 ———————————————————                                    ———————————————————
                |   Shape           |                                   |   Color           |   
                 ———————————————————                                     ———————————————————    
                |   _pColor:Color   |/\_______________________________\ |                   |   
                 ——————————————————— \/                               /  ———————————————————
                |   func():vf       |                                   |   func():vf       |
                 ———————————————————                                     ———————————————————    
                            /\                                                  /\                                  
                           /__\                                                /__\                                 
                            |                                                   `|  
             _ _ _ _ _ _ _ _|_ _ _ _ _ _ _ _ _                       _ _ _ _ _ _ |_ _ _ _ _ _ _ _ _             
            |                                 |                     |                               |
     ———————————————                     ———————————————             ———————————————         ———————————————
    |   Circle      |                   | Rectangle     |           |   Red         |       |       Blue    |   
     ———————————————                     ———————————————             ———————————————         ———————————————    
    |               |                   |               |           |               |       |               |
     ———————————————                     ———————————————             ———————————————         ———————————————
    |  func()       |                   |               |           |  func()       |       |               |
     ———|————————————                    ———————————————             ———————————————         ———————————————
        |
      pColor->func()
上一篇下一篇

猜你喜欢

热点阅读