0

Which one of the following way is recommended and why?

Date d = Date.from(curr);
Date d = new Date(curr);

Can you also provide some examples behind the reasoning?

hatellla
  • 171
  • 2
  • 8
  • 3
    Possible duplicate of [Why should I use a factory class instead of direct object construction?](https://softwareengineering.stackexchange.com/questions/253254/why-should-i-use-a-factory-class-instead-of-direct-object-construction) – Martin Maat Jan 12 '19 at 08:30
  • 1
    See also https://stackoverflow.com/questions/628950/constructors-vs-factory-methods – Martin Maat Jan 12 '19 at 08:30
  • @MartinMaat I'm not sure that's the same. Static factories are not the same as a factory class. – Philip Kendall Jan 12 '19 at 08:34
  • @PhilipKendall I agree the stackoverflow link is a better fit. I did not feel the OP even bothered to use Google first though so a close vote seemed appropriate. – Martin Maat Jan 12 '19 at 08:40

4 Answers4

9

Constructors are the expected way to well... construct a new object. If I'm creating a new object, the first thing I'll do is type in ClassName x = new ClassName( and see what my IDE suggests to me as some options. As such, use constructors unless there's a good reason not to.

That said, constructors do have some disadvantages. For example, let's say my my Date class had the ability to construct itself from either "seconds since 1970" or "milliseconds since 1970". In that case, I couldn't have constructors for both of those because they may well both use long as their parameter. However, I could use static factories:

Date d = Date.fromUnixTimeSeconds(secondsSince1970);
Date d = Date.fromUnixTimeMilliseconds(secondsSince1970 * 1000);
Philip Kendall
  • 22,899
  • 9
  • 58
  • 61
  • Imo your example isn’t great. The problem there isn’t constructors but representing different things with the same type. In this case switching to factory methods is hiding the symptoms instead of solving the problem. Use different types for seconds and milliseconds and constructors are back in business. – besc Jan 12 '19 at 09:08
  • @besc: The problem with using different types in this particular case is that `int`s are so ubiquitous, that your code becomes cluttered with calls to convert ints to longs just for the sake of "properly" using a constructor, rather than a properly named static method that does precisely what it says with a common data type. – Greg Burghardt Jan 12 '19 at 14:43
  • 1
    @GregBurghardt I’m not talking about int and long. That’s still not using your type system. I’m talking about a Seconds and Milliseconds type. – besc Jan 12 '19 at 16:49
  • 1
    This answer hits on the biggest advantage over constructors but fails to actually state it: Static factories are allowed to have their own names. – candied_orange Jan 13 '19 at 06:31
  • regarding the pro for constructors, that's mainly a habbit/convention thing: once you switch your default habbit to assuming there is a factory method, you spare yourself typing " new " each time and directly go for the classname. there shouldn't be many static methods to choose from so with code completion that is typically faster than using constructors. Especially in combination with differently named constructors for different sets of parameters and s.t. your IDE does not need to guess which parameters to show you when suggesting what to fill in. – Frank Hopkins Jun 05 '20 at 14:10
4

There are some differences for the consuming client: a factory method could return a new object, or it could lookup and return an old one.  Further, a factory method could return a subclass instead of the named class.  (A factory method could also return null, though that would be counter intuitive and probably counter productive.)

Whereas in most languages, a constructor must return a new object of the exact type specified by the new expression, with no possibility for (the above mentioned) alternatives that would be allowed a factory method.

(For example, a new expression must construct new reference unequal to any other reference of any currently existing object; in C# and Java, for example, this includes immutable objects like strings, so new String ("x") != new String ("x") where here I use != for reference inequality.)

However, we can't get away from constructors, someone somewhere has to use them to create objects or else we have no objects!

The question then is whether to make the constructor and factory or just constructor.  If you offer a factory method, that provides a level of indirection (and a place for doing maintenance) that allows for certain flexibility.  When offering a factory method, you can also make the constructors private (or protected) such that their usage is restricted, effectively forcing the consuming clients to use the factory method.

You're suggesting there's two alternatives, constructor vs. static factory method, though when it comes to factory methods, there are additional options if you really want to put flexibility into program architecture — one such option is an instance factory method: an instance method (of another class, a factory or context object).  This makes the factory a first class entity like any other object.  This approach offers yet one more level of decoupling and gives the consuming clients the most flexibility and control.  For example, multiple instances (of such factory objects) can coexist in the program, and be used, passed as parameters, etc... and the program (e.g. the consuming clients) have the control to use (or provide) the right one in the right places.

Erik Eidt
  • 33,282
  • 5
  • 57
  • 91
1

From an outside point of view, constructors are just static methods that are invoked with unusual syntax.

However, constructors are not ordinary methods from a viewpoint within that class: the constructor must fully initialize an object, so treating constructors specially allows the language to provide special checks. E.g. in Java, the constructor must assign all final fields. Because a constructor is focused on initialization, some people argue that a constructor should not be doing any meaningful work.

Furthermore, a constructor may play a special role in the language's semantics. E.g. C++ default constructors and copy constructors may be required by many standard library methods. C# interfaces can contain a constructor signature. A deserialization framework may discover constructors via reflection.

When designing a class, I tend to use the following approach to decide whether I should offer a public constructor or an ordinary static method (which would probably use a private constructor):

  • Do the language or some framework require a particular constructor such as a copy constructor? If yes, implement that constructor.
  • Is this a boring, ordinary class that has a single main constructor? If so, do whatever is customary in that language.
  • Do I want to prevent subclasses unless they are under my control? Then do not offer any public constructors but offer construction through some other method. E.g. in Java private constructors and nested classes can be used to simulate a sum type.
  • Do I need multiple constructors, or do the constructors have to perform complicated calculations before the object can be initialized, or would the constructor take an excessive amount of parameters? If so, offer construction through a different interface such as a static method with a meaningful name, a factory object, or via Bloch's Builder pattern.
amon
  • 132,749
  • 27
  • 279
  • 375
0

An advantage of a factory is you can reject invalid parameters without doing something like throwing an exception inside the constructor and/or or returning a partially built object. Theoretically someone could try and bypass your factory and call the constructor directly, but if you go with factories the use of the constructor directly should stick out in version control and/or bug hunting.

Also, if an unexpected error occurs in the constructor you can catch it (and maybe log it?) and just return nothing (this assumes you are more interested in keeping the program running than getting that particular object back).

You can do all these things without a factory, but a factory can centralize such code in a easy-to-find method.

However as noted by Erik, the factory method is only obligated to return something which matches the return type of the factory Create() method (as opposed to the constructor which must return that type), which could be a subclass of the class you want.

The Liskov Substitution Principle tells us that a subclass (what our factory might return) should be able to be used in the same place as the base class (what our constructor would return) without issue.

However in practice enforcing the LSP may be tricky. So the fact that the factory may return a subclass is still a potential issue. You could create a wrapper around all factory methods to check that the returned type is actually the class you expect, but then you must think of what to do when that issue occurs at runtime, rather than knowing at compile-time that your type will be what you expect.

Dev243
  • 86
  • 3
  • How would the Factory properly reject invalid parameters without throwing an Exception? – user949300 Jan 12 '19 at 21:29
  • The idea is to be able to throw the exception before beginning the work of constructing the object. How bad it actually will be if you throw the exception in the constructor will vary by language. If you want to avoid exceptions completely, you can wrap the returned object in a "generation result" object or use something equivalent to the out parameters of c#. This lets you provide information on whether the object was built successfully and/or validation messages. – Dev243 Jan 12 '19 at 22:01