Avoiding nulls, immutability, object state

I like the concept of immutability. I also like the concept of no nulls (and if possible also no NullDesignPattern, no NullObjects... as much as possible).

But what about the following scenario:

I have an object User , which has two fields: birthday and dateInLifeMarried (could be any similar field; the important thing is that at first this field is null and changes at some point in object life).

As it's immutable I want both fields to be in the constructor:

public User(birthday, dateInLifeMarried)

Now:

  • I don't want to pass null to the second parameter
  • I don't want to add a setter becuase its immutable
  • i don't want to call the constructor with NullObjectPattern instead of null
  • Am i just contradicting myself or is there an elegant way to have it which i'm not thinking of?


    Well you need to consider what you want the representation to be - not just the constructor signature. I suspect you will need to use a null reference (or at least something similar) for the field. But you could then have two constructors:

    User(birthday)               // Unmarried user
    User(birthday, marriageDate) // Married user; marriageDate must not be null
    

    As the user of an API, I'm not sure that I'd really like that though - I think I'd rather allow marriageDate to be null. In particular, it would be annoying to have to write:

    LocalDate marriageDate = getMarriageDateOrNull();
    User user = marriageDate == null ? new User(birthday)
                                     : new User(birthday, marriageDate);
    

    Alternatively, as people can get married more than once, you could always take an Iterable<LocalDate> marriageDates , then a never-married user would have an empty sequence :) (You'd need to consider married-then-divorced and married-then-widowed users though. Modelling real life is hard.)


    What about a second constructor

    User(birthday)
    

    that calls the first

    this(birthday, null)
    

    ?


    Don't just avoid null for the sake of avoiding it. Think about what null means and then use it where it makes sense. The value null represents an unknown, undefined or unspecified value. If you use null consciously you can make your code easier to use and more readable, and at the same time prevent null pointer exceptions.

    In your example the marriage date can be unspecified, and therefore you should allow null . However, you don't want the birthday to be unspecified, so you don't allow null there. You could specify the constructors like this:

    User(LocalDate birthday)
    {
        this(birthday, null);
        // That's it! Nothing more to do here.
    }
    
    User(LocalDate birthday, LocalDate marriageDate)
    {
        if (birthday == null)
            throw new IllegalArgumentException();
        // Use it...
    }
    

    Now you (or anyone that uses your code) can do stuff like this:

    LocalDate marriageDate = getMarriageDateOrNull();
    User user = new User(birthday, marriageDate);
    

    See? Cleaner code because you empower null instead of avoiding it.

    链接地址: http://www.djcxy.com/p/20878.html

    上一篇: 指针与Java和字符串变量

    下一篇: 避免空值,不变性,对象状态