136

Like whatsisname said, I believe this is case of cargo cult software design. Factories, especially the abstract kind, are only usable when your module creates multiple instances of a class and you want to give user of this module ability to specify what type to create. This requirement is actually quite rare, because most of the time you just need one ...


82

The Factory pattern vogue stems from an almost-dogmatic belief among coders in "C-style" languages (C/C++, C#, Java) that use of the "new" keyword is bad, and should be avoided at all costs (or at least centralized). This, in turn, comes from an ultra-strict interpretation of the Single Responsibility Principle (the "S" of SOLID), and also of the Dependency ...


61

Factory classes are often implemented because they allow the project to follow the SOLID principles more closely. In particular, the interface segregation and dependency inversion principles. Factories and interfaces allow for a lot more long term flexibility. It allows for a more decoupled - and therefore more testable - design. Here is a non-exhaustive ...


58

The solution is to bundle up the parameters into composite types. Width and Height are conceptually related - they specify the dimensions of the enemy and will usually be needed together. They could be replaced with a Dimensions type, or perhaps a Rectangle type that also includes the position. On the other hand, it might make more sense to group position ...


51

While I'm in favor of using the constructor to merely initialize the new instance rather than to create multiple other objects, helper objects are ok, and you have to use your judgement as to whether something is such an internal helper or not. If the class represents a collection, then it may have an internal helper array or list or hashset. It would ...


50

Code Complete (and many other software engineering resources) emphasizes matching your classes to real world objects. I believe the fundamental reason for this is that it makes it more likely that you have a true grasp of what it is that you're implementing, rather than hacking away at an intangible idea. If you're a subscriber to this theory, I don't see ...


47

The calling code which instantiated a FooRepository object is passing an IDbConnection object and therefore has the right to access this information later on This is not true when you're dealing with things like the factory pattern, where the instantiator of the object is not the handler of the object. Factory patterns quite often exist specifically because ...


44

A Start() method (like Run(), Execute() or anything similar) is appropriate when the cost of constructing the object is low, but the cost of using it is high. For example: A class which encapsulates a best-path-optimization algorithm. It's trivial to set it up with a set of parameters (X squares by Y squares, with suchandsuch evaluation method), but it may ...


40

A constructor with arguments isn't just a handy shorthand for using setters. You write a constructor in order to ensure that an object will never, ever exist without certain data being present. If there is no such requirement, fine. But if there is one, as indicated by the fact that you've written such a constructor, then it would be irresponsible to ...


39

Very general philosophical reasoning Typically, we ask that a constructor provide (as post-conditions) some guarantees about the state of the constructed object. Typically, we also expect that instance methods can assume (as pre-conditions) that these guarantees already hold when they're called, and they only have to make sure not to break them. Calling ...


38

There are always exceptions, and I take issue with the 'always' in the title, but yes, this guideline is generally valid, and also applies outside of the constructor as well. Using new in a constructor violates the D in SOLID (dependency inversion principle). It makes your code hard to test because unit testing is all about isolation; it is hard to isolate ...


36

Yes, it's fine (actually, it's good) to make the default constructor unusable if there's no sensible way to initialize the object without any arguments. But don't "disable" it by throwing an exception. Make it private instead. Ideally your interface won't contain any methods or constructors people "aren't supposed to" call.


34

Constructors are fine when they contain short, simple code. When initialization becomes more than assigning a few variables to the fields, a factory makes sense. Here are some of the benefits: Long, complicated code makes more sense in a dedicated class (a factory). If the same code is put in a constructor which calls a bunch of static methods, this will ...


28

And, besides what Ross Patterson suggested, consider this position which is the exact opposite: Take maxims such as "Thou Shalt Not Do Any Real Work In Thy Constructors" with a grain of salt. A constructor is, really, nothing but a static method. So, structurally, there is really not much difference between: a) a simple constructor and a bunch of complex ...


27

Not all collaborators are interesting enough to unit-test separately, you could (indirectly) test them through the hosting/instantiating class. This may not align with some people's idea of needing to test each class, each public method etc. especially when doing test after. When using TDD you may refactor out this 'collaborator' extracting out a class ...


25

In the 2nd approach you will never have a half-initialised Foo. Putting all the construction in one place seems a more sensible, and obvious place. But... the 1st way isn't so bad, and is often used in many areas (there's even a discussion of the best way to dependency-inject, either property-injection like your 1st way, or constructor injection like the ...


25

The Builder Pattern does not solve the “problem” of many arguments. But why are many arguments problematic? They indicate your class might be doing too much. However, there are many types that legitimately contain many members that cannot be sensibly grouped. Testing and understanding a function with many inputs gets exponentially more complicated – ...


24

You might want to take a look at the Builder pattern. From the link (with an examples of the pattern versus alternatives): [The] Builder pattern is a good choice when designing classes whose constructors or static factories would have more than a handful of parameters, especially if most of those parameters are optional. Client code is much easier ...


24

Both approaches bundle the initialization code into a single function call. So far, so good. However, there are two issues with the second approach: The second one does not actually construct the resulting object, it initializes another object on the stack, which is then copied over to the final object. This is why I would see the second approach as ...


24

I prefer multiple constructors over default values and personally I don't like your two constructor example, it should be implemented differently. The reason for using multiple constructors is that the main one can just check if all parameters are not null and whether they are valid whereas other constructors can provide default values for the main one. ...


23

Always use the constructor unless there is a good reason not to. It's "The C++ Way" (tm). Regarding your points to consider: Constructors are always more or equally efficient as having code outside in separate init() functions. Constructors tend to be easier to use for other developers. Without looking at your source or docs, I would expect new YourClass(...


22

Your question is composed from two completely separate parts: Should I throw exception from constructor, or should I have method fail? This is clearly application of Fail-fast principle. Making constructor fail is much easier to debug compared to having to find why the method is failing. For example, you might get the instance already created from some ...


21

A constructor should establish the initial invariant of your object, that is, put it in a valid and usable state. If your object is not really usable as an instance of the type it is after construction, it's a sign that you've got a bit of a smear between initialization of the object and use of the object. If it's impossible to provide all the information ...


20

Ugh. A constructor should do as little as possible - the issue being that exception behavior in constructors is awkward. Very few programmers know what the proper behavior is (including inheritence scenarios), and forcing your users to try/catch every single instantiation is... painful at best. There's two parts to this, in the constructor and using the ...


18

This is a valid test (although rather overzealous) and I sometimes do it to test constructor logic, however as Laiv mentioned in the comments you should ask yourself why. If your constructor looks like this: public Person(Guid guid, DateTime dob) { this.Guid = guid; this.Dob = dob; } Is there a lot of point in testing whether it throws? Whether the ...


17

A constructor is basically a method, yes, but it is a special method. For example, in C++ a constructor isn't simply a function that returns a new instance of that type. If it was, inheritance wouldn't work. You couldn't call into the base constructors, because they'd return a new instance as well. You'd end up with a new instance of A, which is then ...


17

Considering the only thing you're doing in the constructor is simple assignment, the single constructor solution may be a better choice in your case. The other constructor provides no extra functionality and it's clear from the design of the constructor with two parameters that the second argument does not need to be supplied. Multiple constructors do make ...


16

Excuse me while I react to everyone suggesting the builder pattern here: This is C#, not Java! A main reason for Joshua Bloch's builder pattern is to hack around Java's lack of named arguments. This gives Java a way around the evil telescoping constructor pattern. You're in C#. You have named arguments! Another reason for Joshua Bloch's builder pattern ...


16

When seeing a class with a constructor signature like EnglishWordsListGenerator(const std::string &wordFileName) I think it is pretty obvious that this constructor will read the given file (and so need some time), and it should not be to hard to understand that the caller has to care for possible exceptions from this (because file IO can fail). So ...


14

You may use lazy initialization. In computer programming, lazy initialization is the tactic of delaying the creation of an object, the calculation of a value, or some other expensive process until the first time it is needed. That way you avoid temporal-coupling, meaning the consumer of your class has to call certain methods in certain order. Having ...


Only top voted, non community-wiki answers of a minimum length are eligible