zoukankan      html  css  js  c++  java
  • 重构手法之处理概括关系【1】

    返回总目录

    本小节目录

    1Pull Up Field(字段上移)

    概要

    两个子类拥有相同的字段。将该字段移至基类。

    动机

    如果各个子类是分别开发的,或者是在重构过程中组合起来的,你常常会发现它们拥有重复性,特别是字段容易重复。判断若干字段是否重复,唯一的办法就是观察函数如何使用它们。如果它们被使用的方式很相似,就可以将它们归纳到基类中去。

    范例

    如下代码所示,Employee的两个子类Salesman和Enginner都有_name字段,所以可以考虑把这个字段提到基类中。

    class Employee
    {
    
    }
    
    class Salesman : Employee
    {
        private string _name;
    }
    
    class Enginner : Employee
    {
        private string _name;
    }

    重构后的代码如下,这样提的前提是这些子类有一个基类或者有很多相似的字段和方法,不然为了一个字段而单独建立一个抽象类是不可取的,所以这个就需要具体权衡。

    class Employee
    {
        protected string _name;
    }
    
    class Salesman : Employee
    {
     
    }
    
    class Enginner : Employee
    {
    
    }

    小结

    本项重构主要是减少重复:首先它去除了重复的数据声明;其次它使你可以将该字段的行为从子类移至基类,从而去除重复的行为。

    2Pull Up Method(函数上移)

    概要

    有些函数,在各个子类中产生完全相同的结果。将该函数移至基类。

    动机

    避免行为重复是很重要的。尽管重复的两个函数也可以各自工作得很好,但重复自身只会成为错误的滋生地,此外别无价值。无论何时,只要系统中出现重复,你就面临“修改其中一个却未能修改另一个”的风险。

    使用本项重构的场合:(1)如果某个函数在各个子类中的函数体都相同;(2)子类的函数覆写了基类的函数,但却仍然做相同的工作。

    范例

    以Customer表示“顾客”,它有两个子类:表示“普通顾客”的RegularCustomer和表示“贵宾”的PreferredCustomer。

    public abstract class Customer
    {
        protected DateTime _lastBillDate;
        public void AddBill(DateTime date, double amount)
        {
    
        }
    }
    
    class RegularCustomer : Customer
    {
        void CreateBill(DateTime date)
        {
            double chargeAmount = ChargeFor(_lastBillDate, date);
            AddBill(date, chargeAmount);
        }
    
        public double ChargeFor(DateTime start, DateTime end)
        {
            return 0;
        }
    }
    
    class PreferredCustomer : Customer
    {
        void CreateBill(DateTime date)
        {
            double chargeAmount = ChargeFor(_lastBillDate, date);
            AddBill(date, chargeAmount);
        }
    
        public double ChargeFor(DateTime start, DateTime end)
        {
            return 100;
        }
    }

    两个子类中都有一个CreateBill()函数,并且代码完全一样,但我不能直接把这个函数上移到基类中,因为各个子类的ChargeFor()函数并不相同。必须先在基类中声明一个ChargeFor()抽象函数:

    public abstract class Customer
    {
        protected DateTime _lastBillDate;
        protected void AddBill(DateTime date, double amount)
        {
    
        }
        protected void CreateBill(DateTime date)
        {
            double chargeAmount = ChargeFor(_lastBillDate, date);
            AddBill(date, chargeAmount);
        }
        public abstract double ChargeFor(DateTime start, DateTime end);
    }
    
    class RegularCustomer : Customer
    {
        public override double ChargeFor(DateTime start, DateTime end)
        {
            return 0;
        }
    }
    
    class PreferredCustomer : Customer
    {
        public override double ChargeFor(DateTime start, DateTime end)
        {
            return 100;
        }
    }

    小结

    这个重构要根据具体情况使用,如果不是每个子类都有这个方法的话,可以考虑使用接口或者其他方式。

    3Pull Up Constructor Body(构造函数本体上移)

    概要

    你在各个子类中拥有一些构造函数,它们的本体几乎完全一致。

    在基类中新建一个构造函数,并在子类构造函数中调用它。

    动机

    如果你看见各个子类中的函数有共同行为,第一个念头应该是将共同行为提炼到一个独立函数中,然后将这个函数提升到基类。对于构造函数而言,它们彼此的共同行为往往就是“对象的建构”。这时候你需要在基类中提供一个构造函数,然后让子类都来调用它。

    范例

    class Employee
    {
        protected string _name;
    
        protected string _id;
    
    }
    
    class Manager:Employee
    {
        private int _grade;
        public Manager(string name,string id,int grade)
        {
            _name = name;
            _id = id;
            _grade = grade;
        }
    }

    Employee的字段应该在Employee构造函数中设值。因此定义了一个Employee构造函数,并将它声明为Protected,表示子类应该调用它:

    class Employee
    {
        protected string _name;
    
        protected string _id;
    
        protected Employee(string name, string id)
        {
            _name = name;
            _id = id;
        }
    }
    
    class Manager : Employee
    {
        private int _grade;
        public Manager(string name, string id, int grade) : base(name, id)
        {
            _grade = grade;
        }
    }

    小结

    这个重构手法和提升字段、提升方法很相似。只不过是将“对象的建构”提升到基类中。

    To Be Continued……

  • 相关阅读:
    (笔试题)关于C++的虚函数和多态性
    (笔试题)只用逻辑运算实现乘法运算
    (笔试题)只用逻辑运算实现加法运算
    (C++)浅谈多态基类析构函数声明为虚函数
    (C++)C++多态性中的静态绑定和动态绑定
    (C++)C++类继承中的构造函数和析构函数
    (C++)浅谈using namespace std
    (笔试题)不用除法操作符,实现两个整数的除法
    (笔试题)不用除法操作符,实现两个正整数的除法
    当你学会专注,人生才算真正成熟
  • 原文地址:https://www.cnblogs.com/liuyoung/p/7955645.html
Copyright © 2011-2022 走看看