4

I was reading on this SO page about when to check parameters when constructing an object. The accepted answer suggests throwing the exception from the constructor so that an invalid object cannot be constructed.

I agree with that approach, and I can't see how a Person can be constructed without a name.

However one of the comments suggested:

I also agree that second option is better because it is more reusable than the first one. The first option is violating Object Oriented Principles. Even the factory method is better designed than that.

Questions:

  1. Exactly what OOP principles are being violated when you throw an exception in the constructor? Is it the guideline that a constructor shouldn't do work?

  2. The other approach suggested by the OP was a PersonService, however, this is just speculation, but with this approach are you hoping that the client code will call public void addPerson(Person personToAdd) to verify that the person object doesn't contain a null? What happens if they find a way to circumvent that check? Or before public void addPerson(Person personToAdd) they use that object in another class not written by them that expects a valid Person object?

Again, this is all part of the speculation, but it seems you're putting a lot of responsibility on the client to ensure the Person object is valid when that should have been done when it was created.

  • 1
    I would not take that question and its answers too seriously, because option 2 is odd. The factory method accepts a Person object parameter in order to create a Person object. So, to create a Person you first have to new one, then call the factory method on that? Weird. (The factory method is also a void function -- apparently it would add the person to a collection, so not functionally equivalent to the new approach in option 1, obscuring the choice between which is better). – Erik Eidt Sep 18 '18 at 16:17
  • If you don't understand what Atıfcan Ergin meant then you should tag in them in a comment on the answer and ask. All we can do is speculate, and that won't be very helpful for users of SE. – Dan Wilson Sep 18 '18 at 16:21
  • 2
    "Exactly what OOP principles are being violated when you throw an exception in the constructor?" - none, the commenter was probably misguided. Don't overthink this, better take every comment here on this site with a grain of salt (including mine ;-) – Doc Brown Sep 18 '18 at 18:15
  • Constructors can’t return why a parameter is invalid. I would strongly avoid that design. – Telastyn Sep 19 '18 at 2:15
  • @Telastyn - Sorry, but which design? Throwing from the constructor? If you're going to avoid it, when would you validate the parameter? – user315575 Sep 19 '18 at 2:36
1

1) No OOP principle is broken when you throw an exception in a constructor.

Bjarne Stroustrup recalled in his book The design and evolution of C++ how exceptions were designed into the language between 1984 and 1989 in conjunction with experts from several companies like IBM and Sun:

To some, one of the most important spect of exceptions is that they provide a general mechanism for reporting errors detected in constructors

This is true for Java and other OO languages as well.

2) Using a service to create objects is also a valid approach: It is not uncommon to use builders or factories to create objects.

Factories can allow you to manage errors differently than throwing exceptions, and especially to control the consistency of parameters before the construction.

However, it is not always desirable to use such kind of services on the top of a constructor.

And moreover it is not possible to anticipate all errors. Suppose that during the creation some unexpected event not related to the parameters happen. For example, not enough memory left to create a big object, or some resources were checked but couldn't be allocated (especially in the RAII context).

3) Nevertheless, do not abuse exceptions

Exception is not a substitute for parameter validation. The most important principle with exception is they should fire only for exceptional situations. If a bad parameter is a common situation or if you expect that one out of three construction may cause an exception, then you should really question your design, and refactor it to reduce the risk.

If you use it for defensive programming, assuming that the name should be checked before, but provide this excpetion as safety net, then it's ok.

0
  1. The only principle that I can see being violated is Encapsulation, as the Exception thrown is going to expose some internal structure of the Object. If the Object is not exposed publicly, this may not be of concern. Historically, when a Object failed part way through Construction, it might be necessary to clean up any resources allocated to that point. Garbage collectors have minimized (but not eliminated) this impact. Note also that calling a Constructor explicitly couples your code to the Constructor's signature. This is largely trivial, but may require rework if the signature changes, as can happen when moving to newer versions of your dependencies.
  2. meh? This doesn't make much sense to me.

The current favored pattern (IMO) for cleanly Constructing an Object is the Builder Pattern. Among the benefits of the Builder is the ability to validate parameters before they are passed to the Constructor. This validation can happen when the particular param is set, or during the build() invocation. Validating in the param() call can act as a Circuit Breaker, failing fast and potentially eliminating work to obtain other param values before their use; ex.

...size(5).foo(getMassivelyComplexObject()).build

If 5 isn't a valid size, and the validation is implemented in the size() call, you've avoided the work required to obtain the value for foo().

In the case where a Constructor's signature changes, Builders insulate you in two ways:

  1. Builder param() calls are usually order independent.
  2. Individual Builder param() calls are optional if the Builder supplies default values for the particular param.

The Builder Pattern has lots of other goodness as well, but your question is about Failure during Construction, so I'll stop here.

  • Was it the way I described the problem in my second question or what the OP was doing that doesn't make sense? – user315575 Sep 19 '18 at 7:43
  • @BasementJoe - Wasn't your explanation, it was what the OP was suggesting. The xService idea is a bit antiquated, and what was expressed really didn't represent it IMO – WillD Sep 21 '18 at 20:43

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy