• Replace Type Code With Class和Replace Type Code With Subclass和Replace Type Code With State/Strategy


      周末闲来写写看书总结,今天写《重构》中的3个重要手法,分别是Replace Type Code With Class、Replace Type Code With Subclass和Replace Type Code With State/Strategy。

      1、Replace Type Code With Class

      重构前的主体代码如下:

     1 package nelson;
     2 
     3 public class Person {
     4     
     5     public static final int O = 0;
     6     public static final int A = 1;
     7     public static final int B = 2;
     8     public static final int AB = 3;
     9     
    10     private int _bloodGroup;
    11     
    12     public Person(int bloodGroup){
    13         _bloodGroup = bloodGroup;
    14     }
    15     
    16     public void setBloodGroup(int arg){
    17         _bloodGroup = arg;
    18     }
    19     
    20     public int getBloodGroup(){
    21         return _bloodGroup;
    22     }
    23 }
    View Code

      重构前的应用代码如下:

     1 package nelson;
     2 
     3 public class HelloJava {
     4 
     5     public static void main(String[] args) {
     6             
     7         System.out.println("Hello,Java");
     8         
     9         Person xiaoming = new Person(Person.A);  //小明A型血
    10         
    11         System.out.println("小明的血型是:"+xiaoming.getBloodGroup());
    12     }
    13 
    14 }
    View Code

      重构前的代码有什么问题呢,在Person中使用public static final修饰了几个变量,这几个变量是血型的类型值。在new对象或者setBloodGroup时可以将此作为参数传入。问题有如下:在New对象或者setBloodGroup时,可以传入其他参数,另外Person.A这样的形式不能直观反映A的含义,如果取为BloodGroup.A--血型,血型中的A型血,是不是更直接明了。

      重构后的主体代码:

     1 package nelson;
     2 
     3 public class Person {
     4     
     5     private BloodGroup _bloodGroup;
     6     
     7     public Person(BloodGroup bloodGroup){
     8         _bloodGroup = bloodGroup;
     9     }
    10     
    11     public void setBloodGroup(BloodGroup arg){
    12         _bloodGroup = arg;
    13     }
    14     
    15     public BloodGroup getBloodGroup(){
    16         return _bloodGroup;
    17     }
    18 }
    19 
    20 class BloodGroup
    21 {
    22     public static final BloodGroup O = new BloodGroup(0);
    23     public static final BloodGroup A = new BloodGroup(1);
    24     public static final BloodGroup B = new BloodGroup(2);
    25     public static final BloodGroup AB = new BloodGroup(3);
    26     public static final BloodGroup[] _values = {O,A,B,AB};
    27     
    28     private final int _code;
    29     
    30     private BloodGroup(int code)
    31     {
    32         _code = code;
    33     }
    34     
    35     public int getCode()
    36     {
    37         return _code;
    38     }
    39     
    40     public BloodGroup getBloodGroup(int arg)
    41     {
    42         return _values[arg];
    43     }
    44 }
    View Code

      重构后的应用代码:

     1 package nelson;
     2 
     3 public class HelloJava {
     4 
     5     public static void main(String[] args) {
     6             
     7         System.out.println("Hello,Java");
     8         
     9         Person xiaoming = new Person(BloodGroup.A);  //小明A型血
    10         
    11         System.out.println("小明的血型是:"+xiaoming.getBloodGroup().getCode());
    12     }
    13 }
    View Code

           重构后比重构前有哪些优势呢?

           new Person时需要传入BloodGroup类型参数而不再是int类型参数,这样就有参数类型检查了。参数为BloodGroup.A这样就更容易理解了。

           其实以上就是用class来完成枚举enum的实现了。

      2、Replace Type Code With Subclass

         重构前的主体类Employee,代表员工,有3中类型(Type)。

     1 package nelson;
     2 
     3 public class Employee {
     4     
     5     private int _type;   //员工类型
     6     public static final int ENGINEER = 0;
     7     public static final int SALEMAN = 1;
     8     public static final int MANAGER = 2;
     9     
    10     public Employee(int type)
    11     {
    12         _type = type;
    13     }
    14     
    15     public int getType()
    16     {
    17         return _type;
    18     }
    19 }
    View Code

            重构前的应用代码:

     1 package nelson;
     2 
     3 import java.util.ArrayList;
     4 import java.util.List;
     5 
     6 public class HelloJava {
     7 
     8     public static void main(String[] args) {
     9             
    10         System.out.println("Hello,Java");
    11         
    12         Employee xiaotang = new Employee(Employee.ENGINEER);   //小唐是工程师
    13         Employee xiaoFang = new Employee(Employee.SALEMAN);    //小方是销售
    14         Employee laozhou = new Employee(Employee.MANAGER);     //老周是经理
    15         
    16         List<Employee> allStaffs = new ArrayList<Employee>();  //所有员工
    17         
    18         allStaffs.add(xiaotang);
    19         allStaffs.add(xiaoFang);
    20         allStaffs.add(laozhou);
    21         
    22         //为所有员工发年终奖,喜闻乐见
    23         System.out.println("
    为所有员工发年终奖");
    24         for(Employee staff : allStaffs)
    25         {
    26             switch(staff.getType())
    27             {
    28             case Employee.ENGINEER: System.out.println("多发一个月工资");break;
    29             case Employee.SALEMAN: System.out.println("多发1.5个月工资");break;
    30             case Employee.MANAGER:System.out.println("多发2个月工资");break;
    31             default:break;
    32             }
    33         }
    34         
    35         System.out.println("
    确定所有员工的春节放假时间");
    36         for(Employee staff : allStaffs)
    37         {
    38             switch(staff.getType())
    39             {
    40             case Employee.ENGINEER: System.out.println("休息7天");break;
    41             case Employee.SALEMAN: System.out.println("休息10天");break;
    42             case Employee.MANAGER:System.out.println("休息5天");break;
    43             default:break;
    44             }
    45         }
    46     }
    47 }
    View Code

      这里有什么问题呢,看起来逻辑也是很清晰的。问题在于,应用代码中需要不断地判断员工类型。也可以将发放年终奖做成一个函数定义在Employee中,如PaidAnnualBonus(),将春节休假时间做成一个函数定义在Employee中,如SpringFestivalVacationTime(),可以确定是这两个函数里依然会对员工类型做判断。

      重构后的主体类:

     1 package nelson;
     2 
     3 public abstract class Employee {
     4     
     5     public static final int ENGINEER = 0;
     6     public static final int SALEMAN = 1;
     7     public static final int MANAGER = 2;
     8     
     9     public Employee()
    10     {
    11     }
    12     
    13     public static Employee Create(int type)
    14     {
    15         switch(type)
    16         {
    17         case ENGINEER: return new Engineer();
    18         case SALEMAN: return new Salesman();
    19         case MANAGER: return new Manager();
    20         default:throw new IllegalArgumentException("Incorrect type code value");
    21         }
    22     }
    23     
    24     abstract int getType();
    25     abstract void PaidAnnualBonus();  //发年终奖
    26     abstract void SpringFestivalVacationTime(); //春节放假时间
    27 }
    28 
    29 class Engineer extends Employee
    30 {
    31 
    32     public Engineer() {
    33         super();
    34     }
    35     
    36     public int getType()
    37     {
    38         return Employee.ENGINEER;
    39     }
    40     
    41     public void PaidAnnualBonus()
    42     {
    43         System.out.println("我是工程师,我年终奖多发一个月工资");
    44     }
    45     
    46     public void SpringFestivalVacationTime()
    47     {
    48         System.out.println("我是工程师,我春节放假7天");
    49     }
    50 }
    51 
    52 class Salesman extends Employee
    53 {
    54 
    55     public Salesman() {
    56         super();
    57     }
    58     
    59     public int getType()
    60     {
    61         return Employee.SALEMAN;
    62     }
    63     
    64     public void PaidAnnualBonus()
    65     {
    66         System.out.println("我是销售员,我年终奖多发一个半月工资");
    67     }
    68     
    69     public void SpringFestivalVacationTime()
    70     {
    71         System.out.println("我是销售员,我春节放假10天");
    72     }
    73 }
    74 
    75 class Manager extends Employee
    76 {
    77 
    78     public Manager() {
    79         super();
    80     }
    81     
    82     public int getType()
    83     {
    84         return Employee.MANAGER;
    85     }
    86     
    87     public void PaidAnnualBonus()
    88     {
    89         System.out.println("我是经理,我年终奖多发两个月工资");
    90     }
    91     
    92     public void SpringFestivalVacationTime()
    93     {
    94         System.out.println("我是经理,我春节放假5天");
    95     }
    96 }
    View Code

      重构后的应用代码:

     1 package nelson;
     2 
     3 import java.util.ArrayList;
     4 import java.util.List;
     5 
     6 public class HelloJava {
     7 
     8     public static void main(String[] args) {
     9             
    10         System.out.println("Hello,Java");
    11         
    12         Employee xiaotang = Employee.Create(Employee.ENGINEER);   //小唐是工程师
    13         Employee xiaoFang = Employee.Create(Employee.SALEMAN);    //小方是销售
    14         Employee laozhou = Employee.Create(Employee.MANAGER);     //老周是经理
    15         
    16         List<Employee> allStaffs = new ArrayList<Employee>();  //所有员工
    17         
    18         allStaffs.add(xiaotang);
    19         allStaffs.add(xiaoFang);
    20         allStaffs.add(laozhou);
    21         
    22         //为所有员工发年终奖,喜闻乐见
    23         System.out.println("
    为所有员工发年终奖");
    24         
    25         for(Employee staff : allStaffs)
    26         {
    27             staff.PaidAnnualBonus();
    28         }
    29         
    30         System.out.println("
    确定所有员工的春节放假时间");
    31         for(Employee staff : allStaffs)
    32         {
    33             staff.SpringFestivalVacationTime();
    34         }
    35     }
    36 }
    View Code

      重构后的应用代码变得很简洁,利用了Employee的Create函数,应用类根本不用知道Engineer类、Salesman类、Manager类的存在。

      3、Replace Type Code With State/Strategy

      关于这一点的动机,参照《重构》好好理解吧。参见下图:

      Replace Type Code With Subclass和Replayce Type Code With State/Strategy很类似,Replace-State/Strategy更彻底,将type单独列出来作为一个类,并将它作为宿主类的一个参数,好处就是上图中介绍的,“类型吗的值在对象生命周期中发生变化”和“其他原因使得宿主类不能被继承”。这两句话比较难懂,但考虑这样一个问题就好理解了。上面的Replace-Subclass例子中,如果一个对象被定义为了工程师,现在他得到了提升变为了经理,上面的代码就很难做到。后面“其他原因使得宿主类不能被继承”这里的其他原因确实还没想好(囧)。

      重构前的代码跟上面Replace Type Code With Subclass一样,也就是Replace Type Code With State/Strategy是Repace Type Code With Subclass的升级版。

      重构后的主体代码如下:

      1 package nelson;
      2 
      3 public class Employee {
      4     
      5     EmployeeType employeeType;
      6     
      7     public Employee()
      8     {
      9     }
     10     
     11     public void setType(int arg)
     12     {
     13         employeeType = EmployeeType.Create(arg);
     14     }
     15     
     16     public void PaidAnnualBonus()
     17     {
     18         employeeType.PaidAnnualBonus();
     19     }
     20     
     21     public void SpringFestivalVacationTime()
     22     {
     23         employeeType.SpringFestivalVacationTime();
     24     }
     25 }
     26 
     27 abstract class EmployeeType
     28 {
     29     public static final int ENGINEER = 0;
     30     public static final int SALEMAN = 1;
     31     public static final int MANAGER = 2;
     32     
     33     abstract int getType();
     34     abstract void PaidAnnualBonus();  //发年终奖
     35     abstract void SpringFestivalVacationTime(); //春节放假时间
     36     
     37     public static EmployeeType Create(int type)
     38     {
     39         switch(type)
     40         {
     41         case ENGINEER: return new Engineer();
     42         case SALEMAN: return new Salesman();
     43         case MANAGER: return new Manager();
     44         default:throw new IllegalArgumentException("Incorrect type code value");
     45         }
     46     }
     47 }
     48 
     49 class Engineer extends EmployeeType
     50 {
     51 
     52     public Engineer() {
     53         super();
     54     }
     55     
     56     public int getType()
     57     {
     58         return EmployeeType.ENGINEER;
     59     }
     60     
     61     public void PaidAnnualBonus()
     62     {
     63             System.out.println("我是工程师,我年终奖多发一个月工资");
     64     }
     65     
     66     public void SpringFestivalVacationTime()
     67     {
     68         System.out.println("我是工程师,我春节放假7天");
     69     }
     70 }
     71 
     72 class Salesman extends EmployeeType
     73 {
     74 
     75     public Salesman() {
     76         super();
     77     }
     78     
     79     public int getType()
     80     {
     81         return EmployeeType.SALEMAN;
     82     }
     83     
     84     public void PaidAnnualBonus()
     85     {
     86             System.out.println("我是销售员,我年终奖多发一个半月工资");
     87     }
     88     
     89     public void SpringFestivalVacationTime()
     90     {
     91         System.out.println("我是销售员,我春节放假10天");
     92     }
     93 }
     94 
     95 class Manager extends EmployeeType
     96 {
     97     public Manager() {
     98         super();
     99     }
    100     
    101     public int getType()
    102     {
    103         return EmployeeType.MANAGER;
    104     }
    105     
    106     public void PaidAnnualBonus()
    107     {
    108             System.out.println("我是经理,我年终奖多发两个月工资");
    109     }
    110     
    111     public void SpringFestivalVacationTime()
    112     {
    113         System.out.println("我是经理,我春节放假5天");
    114     }
    115 }
    View Code

      重构后的应用代码如下:

     1 package nelson;
     2 
     3 import java.util.ArrayList;
     4 import java.util.List;
     5 
     6 public class HelloJava {
     7 
     8     public static void main(String[] args) {
     9             
    10         System.out.println("Hello,Java");
    11         
    12         Employee xiaotang = new Employee();
    13         xiaotang.setType(EmployeeType.ENGINEER);   //小唐是工程师
    14         Employee xiaoFang = new Employee();
    15         xiaoFang.setType(EmployeeType.SALEMAN);    //小方是销售
    16         Employee laozhou = new Employee();
    17         laozhou.setType(EmployeeType.MANAGER);     //老周是经理
    18         
    19         List<Employee> allStaffs = new ArrayList<Employee>();  //所有员工
    20         
    21         allStaffs.add(xiaotang);
    22         allStaffs.add(xiaoFang);
    23         allStaffs.add(laozhou);
    24         
    25         //为所有员工发年终奖,喜闻乐见
    26         System.out.println("
    为所有员工发年终奖");
    27         
    28         for(Employee staff : allStaffs)
    29         {
    30             staff.PaidAnnualBonus();
    31         }
    32         
    33         System.out.println("
    确定所有员工的春节放假时间");
    34         for(Employee staff : allStaffs)
    35         {
    36             staff.SpringFestivalVacationTime();
    37         }
    38     }
    39 }
    View Code

      重构后的好处就像上面的两条动机那样,Employee类现在就可以动态改变员工类型属性了,还有就是Employee类也可以被方便的继承而不受约束。

  • 相关阅读:
    php插入日期到mysql失败
    CSS Triangle Arrow DIVs tooltilps
    转:javascript对json操作讲解
    bulletproof ajax:ajax 载入时显示动画
    javascript 和ajax创建bookmarket
    css 文字换行
    MySQL数据库在指定位置增加字段
    javascript获取网页URL地址及参数等
    Microsoft JScript runtime error: 'Sys' is undefined 的解决方法
    DetailsView的简单使用
  • 原文地址:https://www.cnblogs.com/kanite/p/7670305.html
Copyright © 2020-2023  润新知