一.适用环境=»5ùÝ<www.netcsharp.cnM·0Þ1„+Íiz
=»5ùÝ<www.netcsharp.cnM·0Þ1„+Íiz
=»5ùÝ<www.netcsharp.cnM·0Þ1„+Íiz
    有些函数,在各个子类(subclass)中产生完全相同的结果.
=»5ùÝ<www.netcsharp.cnM·0Þ1„+Íiz
=»5ùÝ<www.netcsharp.cnM·0Þ1„+Íiz
=»5ùÝ<www.netcsharp.cnM·0Þ1„+Íiz
二.解决方案=»5ùÝ<www.netcsharp.cnM·0Þ1„+Íiz
    将该函数移至父类(superclass).=»5ùÝ<www.netcsharp.cnM·0Þ1„+Íiz
=»5ùÝ<www.netcsharp.cnM·0Þ1„+Íiz
=»5ùÝ<www.netcsharp.cnM·0Þ1„+Íiz
三.动机=»5ùÝ<www.netcsharp.cnM·0Þ1„+Íiz
    避免行为重复是重要的,因为重复很可能会成为错误的滋生地.只要系统内出现重复,就意味着你会面临修改一个却未能修改另一个的风险.=»5ùÝ<www.netcsharp.cnM·0Þ1„+Íiz
=»5ùÝ<www.netcsharp.cnM·0Þ1„+Íiz
=»5ùÝ<www.netcsharp.cnM·0Þ1„+Íiz
四.范例=»5ùÝ<www.netcsharp.cnM·0Þ1„+Íiz
=»5ùÝ<www.netcsharp.cnM·0Þ1„+Íiz
=»5ùÝ<www.netcsharp.cnM·0Þ1„+Íiz
=»5ùÝ<www.netcsharp.cnM·0Þ1„+Íiz
=»5ùÝ<www.netcsharp.cnM·0Þ1„+Íiz
=»5ùÝ<www.netcsharp.cnM·0Þ1„+Íiz
using System;=»5ùÝ<www.netcsharp.cnM·0Þ1„+Íiz
public class PreferredCustomer :Customer              //贵宾顾客=»5ùÝ<www.netcsharp.cnM·0Þ1„+Íiz
{=»5ùÝ<www.netcsharp.cnM·0Þ1„+Íiz
      =»5ùÝ<www.netcsharp.cnM·0Þ1„+Íiz
    public double ComputeMoney(double Money)      //打折算法:贵宾打7折=»5ùÝ<www.netcsharp.cnM·0Þ1„+Íiz
    {=»5ùÝ<www.netcsharp.cnM·0Þ1„+Íiz
        return Money*0.7;=»5ùÝ<www.netcsharp.cnM·0Þ1„+Íiz
    }=»5ùÝ<www.netcsharp.cnM·0Þ1„+Íiz
    public void creatBill(double money)          //创建帐单:输出打折后应付的金额=»5ùÝ<www.netcsharp.cnM·0Þ1„+Íiz
    {=»5ùÝ<www.netcsharp.cnM·0Þ1„+Íiz
        Console.WriteLine("你应该交纳的金额为"+ComputeMoney(money));=»5ùÝ<www.netcsharp.cnM·0Þ1„+Íiz
    }=»5ùÝ<www.netcsharp.cnM·0Þ1„+Íiz
    =»5ùÝ<www.netcsharp.cnM·0Þ1„+Íiz
}=»5ùÝ<www.netcsharp.cnM·0Þ1„+Íiz
=»5ùÝ<www.netcsharp.cnM·0Þ1„+Íiz
public class RegularCustomer :Customer                //普通顾客  =»5ùÝ<www.netcsharp.cnM·0Þ1„+Íiz
{=»5ùÝ<www.netcsharp.cnM·0Þ1„+Íiz
    public double ComputeMoney(double Money)      //打折算法:普通顾客不打折=»5ùÝ<www.netcsharp.cnM·0Þ1„+Íiz
=»5ùÝ<www.netcsharp.cnM·0Þ1„+Íiz
    {=»5ùÝ<www.netcsharp.cnM·0Þ1„+Íiz
        return Money;=»5ùÝ<www.netcsharp.cnM·0Þ1„+Íiz
    }=»5ùÝ<www.netcsharp.cnM·0Þ1„+Íiz
    public void creatBill(double money)          //创建帐单:输出打折后应付的金额=»5ùÝ<www.netcsharp.cnM·0Þ1„+Íiz
  =»5ùÝ<www.netcsharp.cnM·0Þ1„+Íiz
    {=»5ùÝ<www.netcsharp.cnM·0Þ1„+Íiz
        Console.WriteLine("你应该交纳的金额为"+ComputeMoney(money));=»5ùÝ<www.netcsharp.cnM·0Þ1„+Íiz
    }=»5ùÝ<www.netcsharp.cnM·0Þ1„+Íiz
    =»5ùÝ<www.netcsharp.cnM·0Þ1„+Íiz
    =»5ùÝ<www.netcsharp.cnM·0Þ1„+Íiz
}=»5ùÝ<www.netcsharp.cnM·0Þ1„+Íiz
=»5ùÝ<www.netcsharp.cnM·0Þ1„+Íiz
public class Customer                            //顾客=»5ùÝ<www.netcsharp.cnM·0Þ1„+Íiz
{=»5ùÝ<www.netcsharp.cnM·0Þ1„+Íiz
    =»5ùÝ<www.netcsharp.cnM·0Þ1„+Íiz
}=»5ùÝ<www.netcsharp.cnM·0Þ1„+Íiz
public class App=»5ùÝ<www.netcsharp.cnM·0Þ1„+Íiz
{=»5ùÝ<www.netcsharp.cnM·0Þ1„+Íiz
    public static void Main()=»5ùÝ<www.netcsharp.cnM·0Þ1„+Íiz
    {=»5ùÝ<www.netcsharp.cnM·0Þ1„+Íiz
        PreferredCustomer rm=new PreferredCustomer ();    //生成一个普通顾客=»5ùÝ<www.netcsharp.cnM·0Þ1„+Íiz
        rm.creatBill(100);                                //他买了100元的东西,现在创建帐单,看他应该付多少钱=»5ùÝ<www.netcsharp.cnM·0Þ1„+Íiz
        =»5ùÝ<www.netcsharp.cnM·0Þ1„+Íiz
        Console.ReadLine();=»5ùÝ<www.netcsharp.cnM·0Þ1„+Íiz
    }=»5ùÝ<www.netcsharp.cnM·0Þ1„+Íiz
    =»5ùÝ<www.netcsharp.cnM·0Þ1„+Íiz
}
=»5ùÝ<www.netcsharp.cnM·0Þ1„+Íiz
=»5ùÝ<www.netcsharp.cnM·0Þ1„+Íiz
=»5ùÝ<www.netcsharp.cnM·0Þ1„+Íiz
=»5ùÝ<www.netcsharp.cnM·0Þ1„+Íiz
=»5ùÝ<www.netcsharp.cnM·0Þ1„+Íiz
=»5ùÝ<www.netcsharp.cnM·0Þ1„+Íiz
在代码中,我们发现PreferredCustomer类和RegularCustomer 类中的creatBill()这个函数是一模一样的,所以我们就想到用Pull Up Method,也就是把这个函数上移到父类Customer当中去,=»5ùÝ<www.netcsharp.cnM·0Þ1„+Íiz
不过,这里不仅仅是移上去那么简单,我们仔细观察会发现:creatBill()函数中又调用了一个函数ComputeMoney(),并且这个函数只出现在子类里面,不在父类里面.所以在我们把creatBill()上移前,要作一些准备工作:=»5ùÝ<www.netcsharp.cnM·0Þ1„+Íiz
  Martin Fowler重构一书中提供如下做法:=»5ùÝ<www.netcsharp.cnM·0Þ1„+Íiz
  当待提升函数又调用了一个只出现在子类,未出现在父类的函数,你可以在父类中为被调用的函数声明一个抽象函数.=»5ùÝ<www.netcsharp.cnM·0Þ1„+Íiz
  所以,我们只需在父类Customer中声明一个抽象函数public abstract double ComputeMoney(double Money) ,然后把待提升的函数Copy到父类,再把子类中的函数Delete就可以了.=»5ùÝ<www.netcsharp.cnM·0Þ1„+Íiz
=»5ùÝ<www.netcsharp.cnM·0Þ1„+Íiz
=»5ùÝ<www.netcsharp.cnM·0Þ1„+Íiz
=»5ùÝ<www.netcsharp.cnM·0Þ1„+Íiz
=»5ùÝ<www.netcsharp.cnM·0Þ1„+Íiz
=»5ùÝ<www.netcsharp.cnM·0Þ1„+Íiz
public class PreferredCustomer :Customer          //贵宾=»5ùÝ<www.netcsharp.cnM·0Þ1„+Íiz
=»5ùÝ<www.netcsharp.cnM·0Þ1„+Íiz
{=»5ùÝ<www.netcsharp.cnM·0Þ1„+Íiz
=»5ùÝ<www.netcsharp.cnM·0Þ1„+Íiz
    =»5ùÝ<www.netcsharp.cnM·0Þ1„+Íiz
=»5ùÝ<www.netcsharp.cnM·0Þ1„+Íiz
    public override double ComputeMoney(double Money)=»5ùÝ<www.netcsharp.cnM·0Þ1„+Íiz
=»5ùÝ<www.netcsharp.cnM·0Þ1„+Íiz
    {=»5ùÝ<www.netcsharp.cnM·0Þ1„+Íiz
=»5ùÝ<www.netcsharp.cnM·0Þ1„+Íiz
        return Money*0.7;=»5ùÝ<www.netcsharp.cnM·0Þ1„+Íiz
=»5ùÝ<www.netcsharp.cnM·0Þ1„+Íiz
    }=»5ùÝ<www.netcsharp.cnM·0Þ1„+Íiz
=»5ùÝ<www.netcsharp.cnM·0Þ1„+Íiz
    =»5ùÝ<www.netcsharp.cnM·0Þ1„+Íiz
=»5ùÝ<www.netcsharp.cnM·0Þ1„+Íiz
}=»5ùÝ<www.netcsharp.cnM·0Þ1„+Íiz
=»5ùÝ<www.netcsharp.cnM·0Þ1„+Íiz
=»5ùÝ<www.netcsharp.cnM·0Þ1„+Íiz
=»5ùÝ<www.netcsharp.cnM·0Þ1„+Íiz
public class RegularCustomer :Customer            //普通顾客  =»5ùÝ<www.netcsharp.cnM·0Þ1„+Íiz
=»5ùÝ<www.netcsharp.cnM·0Þ1„+Íiz
{=»5ùÝ<www.netcsharp.cnM·0Þ1„+Íiz
=»5ùÝ<www.netcsharp.cnM·0Þ1„+Íiz
    public override double ComputeMoney(double Money)=»5ùÝ<www.netcsharp.cnM·0Þ1„+Íiz
=»5ùÝ<www.netcsharp.cnM·0Þ1„+Íiz
    {=»5ùÝ<www.netcsharp.cnM·0Þ1„+Íiz
=»5ùÝ<www.netcsharp.cnM·0Þ1„+Íiz
        return Money;=»5ùÝ<www.netcsharp.cnM·0Þ1„+Íiz
=»5ùÝ<www.netcsharp.cnM·0Þ1„+Íiz
    }=»5ùÝ<www.netcsharp.cnM·0Þ1„+Íiz
=»5ùÝ<www.netcsharp.cnM·0Þ1„+Íiz
    =»5ùÝ<www.netcsharp.cnM·0Þ1„+Íiz
=»5ùÝ<www.netcsharp.cnM·0Þ1„+Íiz
}=»5ùÝ<www.netcsharp.cnM·0Þ1„+Íiz
=»5ùÝ<www.netcsharp.cnM·0Þ1„+Íiz
=»5ùÝ<www.netcsharp.cnM·0Þ1„+Íiz
=»5ùÝ<www.netcsharp.cnM·0Þ1„+Íiz
public abstract class Customer                    //顾客=»5ùÝ<www.netcsharp.cnM·0Þ1„+Íiz
=»5ùÝ<www.netcsharp.cnM·0Þ1„+Íiz
{=»5ùÝ<www.netcsharp.cnM·0Þ1„+Íiz
=»5ùÝ<www.netcsharp.cnM·0Þ1„+Íiz
    public abstract double ComputeMoney(double Money);=»5ùÝ<www.netcsharp.cnM·0Þ1„+Íiz
=»5ùÝ<www.netcsharp.cnM·0Þ1„+Íiz
    public void creatBill(double money)            //此函数已被提升=»5ùÝ<www.netcsharp.cnM·0Þ1„+Íiz
=»5ùÝ<www.netcsharp.cnM·0Þ1„+Íiz
    {=»5ùÝ<www.netcsharp.cnM·0Þ1„+Íiz
=»5ùÝ<www.netcsharp.cnM·0Þ1„+Íiz
        Console.WriteLine("你应该交纳的金额为"+ComputeMoney(money));=»5ùÝ<www.netcsharp.cnM·0Þ1„+Íiz
=»5ùÝ<www.netcsharp.cnM·0Þ1„+Íiz
    }=»5ùÝ<www.netcsharp.cnM·0Þ1„+Íiz
=»5ùÝ<www.netcsharp.cnM·0Þ1„+Íiz
}
=»5ùÝ<www.netcsharp.cnM·0Þ1„+Íiz
=»5ùÝ<www.netcsharp.cnM·0Þ1„+Íiz
五.作法=»5ùÝ<www.netcsharp.cnM·0Þ1„+Íiz
  1.检查待提升函数,确定它们是完全一致的.=»5ùÝ<www.netcsharp.cnM·0Þ1„+Íiz
  2.如果待提升函数的签名不同,将那些签名都修改为你想要在父类中使用的签名.=»5ùÝ<www.netcsharp.cnM·0Þ1„+Íiz
  3.将待提升函数拷贝到父类中,并做适当调整.=»5ùÝ<www.netcsharp.cnM·0Þ1„+Íiz
              当待提升函数又调用了一个只出现在子类,未出现在父类的函数,你可以在父类中为被调用的函数声明一个抽象函数.=»5ùÝ<www.netcsharp.cnM·0Þ1„+Íiz
    4.逐一移除待提升的函数,直至只剩下父类中的函数为止.=»5ùÝ<www.netcsharp.cnM·0Þ1„+Íiz
    5.观察该函数的调用者,看看是否可以将它所索求的对象型别改为父类.=»5ùÝ<www.netcsharp.cnM·0Þ1„+Íiz