具有少量布尔参数的重构方法

Refactoring method with few boolean parameters

有一个很好的重构方法。例如,我们有这个带有标志的方法:

public void process(boolean hasLicense){
        if (hasLicense){
            System.out.println("has");
        }else {
            System.out.println("has not");
        }
    }

我们可以拆分成两种方法:

public void processWithLicense() {
    System.out.println("has");
}

public void processWithoutLicense() {
    System.out.println("has not");
}

但是这种方法呢?

public void process(boolean hasLicense, boolean isAdmin) {
        if (hasLicense && isAdmin) {
            System.out.println("success");
        }
        
        System.out.println("some code");
        
        if (isAdmin){
            System.out.println("add grants");
        }

        System.out.println("10 lines code");
        
        if (isAdmin && !hasLicense){
            System.out.println("something");
        }
    }

如何重构此方法并删除布尔参数?

How can I refactor this method and remove boolean parameters?

关于重构的事情是,这个决定在很大程度上取决于你想做什么,以及实际代码是什么样的:我可以提出建议,但这些可能或者可能不合适。

你可以在这里使用的东西是 Template Pattern:你可以定义一个类似这样的接口:

interface Template {
  void part1();
  void part2();
  void part3();
}

然后将您的方法重构为:

public void process(Template template) {
    template.part1();
    
    System.out.println("some code");
    
    template.part2();

    System.out.println("10 lines code");
    
    template.part3();
}

然后为 (admin/non-admin) x (license/no 许可证传入该接口的实现。

显然,如果您需要表示所有可能性,这会变得很大,因此您可能不想这样做。


如果反对传递 布尔值,您可以使用其他类型。 Effective Java 建议传递双元素枚举而不是布尔值,原因有很多,包括:

  • 更具描述性:调用站点是自我记录的,其中使用了文字值
  • 将来添加更多选项更容易
  • 因为相邻参数的类型不同,所以更不容易弄错顺序
enum AdminState { IS_ADMIN, NOT_ADMIN }
enum LicenceState { HAS_LICENCE, NO_LICENCE }

public void process(AdminState adminState, LicenceState licenceState) {
    if (licenceState == HAS_LICENCE && adminState == IS_ADMIN) {
        System.out.println("success");
    }
    // ...
}

或者,如果您希望避免传递许多参数,您可以创建一个class 来保存许多参数:

class ProcessArgs {
  boolean isAdmin() { ... }
  boolean hasLicense() { ... }
}

然后传入:

public void process(ProcessArgs args) {
    if (args.hasLicense() && args.isAdmin()) {
        System.out.println("success");
    }
    // ...
}

这提出了如何初始化 ProcessArgs 的实例的问题:如果您只是有一个采用 2 个布尔值的构造函数,它对实现“不传递布尔值”,因为您刚刚将 2 个布尔值从方法移动到构造函数。

但是,它确实具有允许您在多个位置传递同一组参数的优势,而无需担心转置参数之类的事情。