标志参数反图案
#初学者 #编程 #java #patterns

在实施新功能时,我在两个无关的地方遇到了 flag参数抗模式。我想将其作为一个仔细研究这个反图案的机会。

一个简单的例子

假设我们要通过API方法加载所有PDF文档。看起来像这样:

public interface DocumentService {

    Document[] loadDocuments();
}

它开始闻起来

在下一步中,我们需要一种加载所有TIFF文档的方法。由于实现的差异可能只是一行代码,因此结果可能是这样的:

public interface DocumentService {

    /**
     * @param loadTiff true: loads TIFF documents - false: loads PDF documents
     */
    Document[] loadDocuments(boolean loadTiff);
}

也可以通过额外的块进行非常快速修改实现:

public Document[] loadDocuments(boolean loadTiff) {
    int format = 1; // load PDF documents by default
    if (loadTiff) {
        format = 2; // except when TIFFs are requested
    }
    ...
}

但是,如果我们看一下此API的客户端,我们已经注意到了令人不愉快的气味:

Document[] documents = documentService.loadDocuments(false);

在此代码点,您能说出false的含义,而不查看该方法的定义?如果我们将其更改为true

会发生什么情况

气味开始发臭

在下一步中,我们还需要一种加载RTF文档的方法。同样,实现的差异仅是一行代码。但是,我们如何在不重新实现逻辑的情况下重复使用现有方法?标志参数妨碍了我们! boolean参数只能采用两个状态,即truefalse。 (好吧,聪明的Java开发人员将其更改为Boolean参数,并将truefalsenull作为选择)。

但是,标志参数也向我们展示了其他东西:这里违反了单一责任原则。实际上,该方法目前具有多个责任。一方面,它知道如何加载PDF文档。另一方面,它还知道如何加载TIFF文档。或更一般:这样的方法做两种不同的事情 - 一次在true上,一次在false上。

可能的解决方案

自发地,我可以想到两种摆脱标志参数的简单方法。

选项1:我们为文档类型定义一个接口以查询信息。然后,我们可以通过使用文档类型作为参数来概括该方法。但是,有可能不必要的over-generalization of the business logic

public interface DocumentService {

    Document[] loadDocuments(DocumentType documentType);
}

选项2:我们为每个可能的域上下文创建一个特定方法。

public interface DocumentService {

    Document[] loadPdfDocuments();

    Document[] loadTiffDocuments();

    Document[] loadRtfDocuments();
}

在两种情况下,从客户的方面,这都会产生可读的代码:

Document[] documents = documentService.loadDocuments(DocumentType.PDF);
Document[] documents = documentService.loadPdfDocuments();

那设定器方法呢?

如果我们严格,那么我们也必须更改

public class Action {

    private boolean enabled;

    public void setEnabled(boolean enabled) {
        this.enabled = enabled;
    }
}


public class Action {

    private boolean enabled;

    public void enable() {
        this.enabled = true;
    }

    public void disable() {
        this.enabled = false;
    }
}

但是,我们不必比这里的教皇更重要。如果我必须在
之间进行选择

action.setEnabled(actionCheckBox.isChecked());


if (actionCheckBox.isChecked()) {
    action.enable();
} else {
    action.disable();
}

对于客户端代码,我会留在第一个。

进一步阅读

我希望这篇文章对您有帮助。欢迎发表评论。有关更多Java的内容,请在Twitter上关注我。