12

What are the pros and cons of having static object creation methods over constructors?

class Foo {
  private Foo(object arg) { }

  public static Foo Create(object arg) {
    if (!ValidateParam(arg)) { return null; }
    return new Foo(arg);
  }
}

Few that I can think of:

Pros:

  • Return null instead of throwing an exception (name it TryCreate). This can make code more terse and clean on the client side. Clients rarely expect a constructor to fail.
  • Create different kinds of objects with clear semantics, e.g. CreatFromName(String name) and CreateFromCsvLine(String csvLine)
  • Can return a cached object if necessary, or a derived implementation.

Cons:

  • Less discoverable, more difficult to skim code.
  • Some patterns, like serialization or reflection are more difficult (e.g. Activator<Foo>.CreateInstance())
4
  • 1
    It's slower. You have to handle null reference anyway. Nov 16, 2010 at 18:43
  • 1
    @Amir Handling null is (Foo x = Foo.TryCreate(); if (x == null) { ... }). Handling a ctor exception is (Foo x; try { x = new Foo(); } catch (SomeException e) { ... }). When calling a normal method, I prefer exceptions to error codes, but with object creation, TryCreate seems cleaner.
    – dbkk
    Nov 16, 2010 at 19:06
  • Would you in your validation make any type checking? Nov 16, 2010 at 19:18
  • With regards to the second Pro, "Create different kinds of objects with clear semantics, e.g. CreatFromName(String name) and CreateFromCsvLine(String csvLine)", you might be better to create Name and CsvLine types, rather than express requirements via method names. This would allow you to overload Create. Using strings for both could be considered to be "primitive obsession" (assuming you've not made this choice for known performance reasons). Check out Object Calisthenics for a fun way to explore this. Sep 4, 2019 at 18:36

2 Answers 2

7

The biggest drawback with static 'creators' is probably limiting inheritance. If you or the user of your library derives a class from your Foo, then Foo::Create() becomes pretty much useless. All logic defined there will have to be rewritten again in the inherited Create().

I'd suggest a compromise: define a constructor with trivial object initialization logic that never fails/throws, then define creator(s) with caching, alternate construction etc. That leaves the possibility of deriving and you benefit from having creators for a given class.

1
  • 3
    In practice it's not really an issue, because most classes aren't designed to be inherited from (and thus should be sealed/final). If it later turns out you want to open the class up to inheritance, you can always move any initialization logic to a protected constructor.
    – Doval
    Aug 18, 2016 at 13:17
7

Create is a Factory method. When I feel a need for this, I implement the Factory pattern, and define an interface to represent the contract for creating the object as well as an implementing class, which then gets injected where needed. This retains the advantages of moving the creation responsibility out of the class, but avoids (or at least makes more obvious) the limitations of performing object creation outside the class constructor.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Not the answer you're looking for? Browse other questions tagged or ask your own question.