5

According to DDD-principles I use factory-methods to create consistent objects and to ensure that the objects are in the right state.

Now I'm in doubt about inner logic of setter methods. I'm tied up with an object, that's similar to the following code snippet, so let's take it as an example:

public class UserCredentials {

    private String username;

    private UserCredentials() {
        super();
    }

    public static UserCredentials create (final String username) {
        String username = username.toUpperCase();
        UserCredentials newInstance = new UserCredentials(username);
        return newInstance;
    }

    private UserCredentials(final String username) {
        this.username = username;
    }

    public String getUsername() {
        return this.username;
    }

    public void setUsername(final String username) {
        this.username = username;
    }

    public void checkConsitency() {
        ...
        isUppercase();
        ...
    }
}

We do have an invariant: The username of the credentials must always be uppercase. Now I want to make sure, that changing the username doesn't violate the invariant.

But how do I guarantee the rule?

  1. I do rewrite the setter method and add the conversion logic to the setter. Drawback: Setter contains logic.

  2. I rely on clients, that they always provide uppercase username and I will throw consistency exceptions in the case of violation. Drawback: Origin of the wrong usage is hard to discover, moreover its bad practice at all.

  3. I remove the setter method and replace it with a domain method like changeUsername(String username) that contains the conversion logic. Drawback: external developers may miss the setter method.

Because of the statement "username of credential must always be uppercase" I tend to prefer alternative 3.

But is there a smarter solution?

gnat
  • 21,442
  • 29
  • 112
  • 288
shylynx
  • 2,124
  • 3
  • 13
  • 16
  • 1
    What's the point of a `setter` that doesn't have any logic? Make it public then. – Mahdi Apr 08 '14 at 09:42
  • 1
    Possible duplicate of [Is it considered a bad practice to add logic in a property setter?](https://softwareengineering.stackexchange.com/questions/204739/is-it-considered-a-bad-practice-to-add-logic-in-a-property-setter) – gnat Oct 27 '17 at 13:50

1 Answers1

6

Choose solution #1. There is nothing wrong with setters containing validation or coercion logic. In fact, that is the only reason why we'd use setters and getters instead of public member fields!

Your create factory method is also a bit awkward, as there is no reason not to use the constructor instead:

public class UserCredentials {

    private String username;

    public UserCredentials(final String username) {
        super();
        this.username = coerceUsername(username);
    }

    public String getUsername() {
        return this.username;
    }

    public void setUsername(final String username) {
        this.username = coerceUsername(username);
    }

    private static String coerceUsername(final String username) {
        return username.toUpperCase();
    }
}
amon
  • 132,749
  • 27
  • 279
  • 375
  • It's bad practice to use logic in constructors that can throw exceptions. Especially the example can throw NPE, if username is null. Not really smart. – shylynx Apr 08 '14 at 09:47
  • 1
    @shylynx good point, but sometimes throwing exceptions is the best thing to do, even in constructors – constructing an object in an illegal state is a worse problem. If you really want to avoid this, you need the [builder pattern](https://en.wikipedia.org/wiki/Builder_pattern). – amon Apr 08 '14 at 09:49
  • 1
    @shylynx Not a problem if `null` is forbidden. – Doval Apr 08 '14 at 11:55
  • 1
    Why don't you call the setter from the constructor? – inf3rno Feb 14 '17 at 15:07
  • 1
    @inf3rno Calling instance methods inside a constructor is generally considered an antipattern. When the method is called, the object is in a half-initialized state. However, methods may reasonably assume that the object they are receiving is complete, just like they can assume that `this != null`. That is particularly ugly if a subclass overrides the method. This is not an issue for static methods since they do not have access to `this` object and cannot be overridden. – amon Feb 14 '17 at 15:14