简体   繁体   English

创建采用布尔值isX并根据isY需要布尔值的构造函数的最佳实践是什么?

[英]What are some best practices for a creating a constructor that takes a boolean isX and depending on that value would need a boolean for isY?

In this hypothetical problem I'm creating a class to represent Sausage which can be: A. Fresh and Packaged B. Fresh and Not Packaged C. Not Fresh and Not Packaged 在这个假设的问题中,我正在创建一个表示香肠的类,该类可以是:A.新鲜和包装B.新鲜和未包装C.不新鲜和未包装

Note: It can't be Not Fresh and Packaged. 注意:它不能不是新鲜包装的。

I'm looking for the best practice to create constructor with this in mind. 我正在寻找考虑到这一点来创建构造函数的最佳实践。

The way I tried is below, but I think there should be a better solutions. 我尝试的方法如下,但是我认为应该有更好的解决方案。

public class Sausage {
    Meat meat;
    boolean isFresh;
    boolean isPackaged;

    public Sausage(Meat meat, Boolean isFresh, Boolean isPackaged) {
        this.meat = meat;
        if (!isFresh) {
            this.isFresh = false;
            this.isPackaged = false;
        }
        else if (isPackaged) {
            this.isFresh = true;
            this.isPackaged = true;
        }
        else {
            this.isFresh = true;
            this.isPackaged = false;
        }
    }
}

I'm looking for a cleaner way to provide this functionality. 我正在寻找一种更清洁的方式来提供此功能。

You can represent the possible states as an enumeration type: 您可以将可能的状态表示为枚举类型:

enum SausageType {
    FreshPackaged,
    FreshUnpackaged,
    NotFresh;
}

Then change your constructor to take a SausageType instead of two Boolean s. 然后将构造函数更改为采用SausageType而不是两个Boolean

The advantage of this method is that it is not possible to call the constructor with the wrong combination of states, it is obvious to users of your class what the possible values are, and you do not need to remember to keep brittle runtime checking of arguments up to date with changing requirements. 此方法的优点是不可能用错误的状态组合调用构造函数,对于类的用户来说很明显可能的值是什么,并且您无需记住对参数进行脆弱的运行时检查与最新的需求变化。

There are few problems with your current approach: 您当前的方法存在一些问题:

  1. There is a way to create write new object which makes no sense eg new Sausage(..., false, true) where packaged will be silently converted to false . 有一种方法可以创建没有意义的写new对象,例如new Sausage(..., false, true) ,其中打包的内容将被悄悄地转换为false This is confusing and makes code harder to understand. 这令人困惑,并使代码更难以理解。

  2. You are mixing Boolean object type and boolean primitive type which will result in unnecessary auto-boxing. 您正在混合Boolean对象类型和boolean元类型,这将导致不必要的自动装箱。 If you don't need to support null use boolean . 如果您不需要支持null使用boolean

  3. boolean fields probably don't need is prefix. boolean领域也许并不需要is前缀。

Since there are two boolean flags and 4 possibilities they can be set ( true true , true false , false true , false false ) but only 3 valid options perhaps named factory methods would be more suitable: 由于存在两个布尔标志和4种可能性,因此可以设置它们( true truetrue falsefalse truefalse false ),但是只有3个有效选项(可能是工厂方法)更合适:

public class Sausage {

    public static Sasuage newFreshPackaged(Meat meat) {
      return new Sasuage(meat, true, true);
    }

    public static Sasuage newFreshNotPackaged(Meat meat) {
      return new Sasuage(meat, true, false);
    }

    public static Sasuage newNotFreshNotPackaged(Meat meat) {
      return new Sasuage(meat, false, false);
    }

    private Sausage(Meat meat, boolean fresh, boolean packaged) {
        this.meat = meat;
        this.fresh = fresh;
        this.packaged = packaged;
    }
}

Silently changing isPackaged to false may be a surprise to calling code. isPackaged静默更改为false可能会使调用代码感到惊讶。 Here, you may choose to throw an exception if the combination (not fresh, packaged) is chosen. 在这里,如果选择了组合(不是新鲜包装),则可以选择引发异常。

if (!isFresh && isPackaged) {
    throw new IllegalArgumentException("Can't be both not fresh and packaged!");
}
this.isFresh = isFresh;
this.isPackaged = isPackaged;

You may also decide to use factory methods (making your constructor private ) that enforce your requirements. 您也可以决定使用工厂方法(将构造函数设为private )来满足您的要求。 This would avoid needing an exception to be thrown. 这将避免需要引发异常。

public static Sausage createFreshSausage(Meat meat, boolean isPackaged) {
    return new Sausage(meat, true, isPackaged);
}

public static Sausage createNotFreshSausage(Meat meat) {
    return new Sausage(meat, false, false);
}

Incidentally, normally the primitive boolean would be used in the constructor's parameters' types, not the object wrapper Boolean , like your instance variables. 顺便说一句,通常在构造函数的参数类型中使用基本boolean ,而不是像实例变量那样使用对象包装Boolean A null value here that would be allowed by Boolean doesn't make any sense. Boolean值允许的null值没有任何意义。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM