`

重构36计(13-18)

阅读更多
第十三计:为集合类型的成员变量提供增删改查函数
  对于集合类型的成员变量,直接提供一个函数将其暴露出去是不够妥当的,缺点包括以下几点:
  1、添加集合元素时无法校验它的合法性,例如类型是否符合要求、该元素是否已存在等。
  2、无法控制集合的容量,集合的容量可能是动态分配的。
  所以,更好的做法是为集合类型的成员变量提供增删改查等函数,例如某个类中有名为userList的数组,则可以为它增加几个函数:
public void add(User user){
  if(user == null) // 如果对象为不合法,则不添加
     return;
  if(userList == null) // 如果集合还未初始化,则新建
    userList = new ArrayList();
  if(isUserExisted(user)) // 如果该用户已经存在,则不添加
    return;
  // 将该用户添加到集合中
  userList.add(user);
}

public void delete(User user){
  if(userList == null)
    return;
  userList.remove(user);
}

第十四计:避免一个临时变量充当多种角色
  当在函数中声明一个临时变量的时候,其实已经设定了该变量的角色,这或多或少能从它的命名中看出来,例如下面变量的声明:
String userName = null;  

可以看出这个临时变量是存储用户名用的,有些人认为声明多个临时变量会浪费空间,所以在函数中会多次使用该变量,例如用这个变量存储了用户的密码:
userName = “*******”;

这种方式很容易引入Bug,而且降低了可理解性。因此,一个变量应该只充当一种角色。

第十五计:引入NULL Object来避免大量的对象合法性判断
  当我们获得对象的引用后,在调用该对象的函数前一般都会检查它是否为NULL来避免程序崩溃,这样也会导致程序中出现大量类似下面的代码段:
EventRecorder recorder = EventRecorderFactory.getRecorderByType(0);
if( recorder ==null ){
  Log.error("Recorder对象为空");
  lastErrorCode =0;
}
else{
  recorder.record("记录点啥...");
}

而NULL Object模式则可以避免这种情况

第十六计:函数命名有语法
  大部分函数的命名尽量采用动词+名词的形式,并使其具有自注释性,例如:findUserById,从函数名中不仅能看出函数的功能,甚至连参数也能猜出来,另外,有些命名方式是有一定意义的,例如作为回调的函数一般以on开头,如:onUserPasswordChanged,说明该函数会在用户密码变化时被调用。对于返回布尔值的函数尽量采用疑问句式,如:isNameValid。

第十七计:去除只是内部状态不同的派生类
  当某些派生类与父类相比只是状态不同时,那就应该考虑去掉这些派生类,把这些状态作为父类的成员变量,并且可以为原来派生类所表示的对象准备一些构造函数或者工厂方法,例如下面表示员工的类:
public abstract class Employee{
  private int id;
  private String name;

  // 获取薪水
  public abstract int getSalary();

  // 获取是否有解雇员工的权利
  public abstract boolean canFireOthers();
}

public class Programmer extends Employee{
  public int getSalary(){
    return 5000;
  }

  public boolean canFireOthers(){
    return false;
  }
}

public class Manager extends Employee{
  public int getSalary(){
    return 10000;
  }

  public boolean canFireOthers(){
    return true;
  }
}

可以看出,Employee的派生类实质上只是状态与父类不同,应该将它们合并为一个类:
public class Employee{
  private int id;
  private String name;
  private int salary;
  private boolean canFireOthers;

  public static Employee newProgrammer(String name){
    return new Employee(name,5000,false);
  }

  public static Employee newManager(String name){
    return new Employee(name,10000,true);
  }

  public Employee(String name,int salary,boolean   canFireOthers){
    this.name = name;
    this.salary = salary;
    this.canFireOthers = canFireOthers;
  }

  // 获取薪水
  public int getSalary(){
    return salary;
  }

  // 获取是否有解雇员工的权利
  public boolean canFireOthers(){
    return canFireOthers;
  }
}

第十八计:少用标记变量
  标记变量一般都是布尔类型的变量,主要用来在某类事件或者操作发生后做个标记,然后其他地方会用到这个标记,用完之后很可能会重置这个标记到初始状态。少量并恰当合理地使用标记变量可以达到很好的效果,能解决一些难题,不过,用的多了就会出乱子,尤其是一个类中有多个成员变量是标记变量,成员函数的实现不得不“看它们的眼色行事“了,它们所产生的标记值的组合会让实现者越来越头大,它们的同时存在增加了程序的复杂性。所以,当类中出现多个标记变量而隐约感觉到不对头时,应该果断干掉它们,然后认真分析处理逻辑是否存在问题,避免再次引入标记变量。
分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics