Fork me on GitHub

重构手法之处理概括关系【2】

返回总目录

本小节目录

4Push Down Method(函数下移)

概要

基类中的某个函数只与部分(并非全部)子类有关。

将这个函数移到相关的那些子类去。

动机

Push Down Method与Pull Up Method恰恰相反。当我有必要把某些行为从基类中移至特定的子类时,就使用Push Down Method,它通常也只在这种时候有用。使用Extract Subclass之后可能会需要它。

范例

如下代码所示,Animal类中的方法Bark()只有在其子类Dog中使用,所以最好的方案就是把这个方法移到子类Dog中。

public class Animal
{
    public void Bark()
    {
        // code to bark
    }
}

public class Dog : Animal
{
}

public class Cat : Animal
{
}

重构后的代码如下,同时在父类Animal中如果没有其他的字段或者公用方法的话,可以考虑把Bark()方法做成一个接口,从而去掉Animal类。

public class Animal
{

}

public class Dog : Animal
{
    public void Bark()
    {
        // code to bark
    }
}

public class Cat : Animal
{
}

小结

面向对象三大特征(继承、封装、多态)很多时候可以帮助我们,但同时也可能会造成使用过度或者使用不当,所以如何把握好设计,这个就变得至关重要。在什么时候使用继承的方式,在什么时候使用组合和聚合,接口和继承类的选择等就成了我们的重点。

5Push Down Field(字段下移)

概要

基类中的某个字段只被部分(并非全部)子类用到。

将这个字段移到需要它的那些子类去。

动机

如果只有某些(而非全部)子类需要基类内的一个字段,就可以使用本项重构。

范例

如下代码所示,基类Task类中的_resolution字段只会在子类BugTask中用到,所以就考虑把它放到BugTask类中。

public class Task
{
    protected string _resolution;
}

public class BugTask : Task
{
}

public class FeatureTask : Task
{
}

重构后的代码如下所示,这样做的好处可以简化基类,同时让其他没有使用它的子类也变得更加简单,如果这样的字段比较多的话,使用此重构也能节约一部分内存。

public class Task
{
   
}

public class BugTask : Task
{
    protected string _resolution;
}

public class FeatureTask : Task
{
}

小结

此重构也是一个非常简单的重构,在很多时候我们都会不自觉的使用它。

6Extract Subclass(提炼子类)

概要

类中的某些特性只被某些(而非全部)实例用到。

新建一个子类,将上面所说的那一部分特性转移到子类中。

动机

使用本项重构的主要动机是:你发现类中的某些行为只被一部分实例用到,其他实例不需要它们。

Extract Class是Extract Subclass之外的另一种选择,两者之间的抉择其实就是委托和继承之间的抉择。Extract Subclass通常更容易进行,但它也有限制:一旦对象创建完成,你无法再改变与类型相关的行为。但如果使用Extract Class,你只需插入另一个组件就可以改变对象的行为。此外,子类只能用以表现一组变化。如果你希望一个类以几种不同的方式变化,就必须使用委托。

范例

当你的基类中存在一些方法不是所有的子类都需要访问,你想将它们调整到子类中时,这个重构会变得很有用了。如下代码所示,我们需要一个 Registration类用来处理学生选课的信息。但是当Registration类开始工作后,我们意识到我们会在两种不同的上下文中使用Registration类,NonRegistrationAction和Notes只有在我们处理未注册情况下才用到。

public class Registration
{
    public NonRegistrationAction Action { get; set; }
    public decimal RegistrationTotal { get; set; }
    public string Notes { get; set; }
    public string Description { get; set; }
    public DateTime RegistrationDate { get; set; }
}

重构后的代码如下所示,这样也满足面向对象五大原则之一的单一职责。同时也让类的结构变得更加清晰,增强了可维护性。

public class Registration
{
    public decimal RegistrationTotal { get; set; }
    public string Description { get; set; }
    public DateTime RegistrationDate { get; set; }
}

public class NonRegistration : Registration
{
    public NonRegistrationAction Action { get; set; }
    public string Notes { get; set; }
}

小结

这个重构方法经常用来规范类的职责,和之前的一些重构方法也有些类似。

 

To Be Continued……

posted @ 2017-12-07 08:59  NaYoung  阅读(634)  评论(5编辑  收藏  举报