Factory Pattern in C++ -- doing this correctly?
Asked Answered
A

5

14

I am relatively new to "design patterns" as they are referred to in a formal sense. I've not been a professional for very long, so I'm pretty new to this.

We've got a pure virtual interface base class. This interface class is obviously to provide the definition of what functionality its derived children are supposed to do. The current use and situation in the software dictates what type of derived child we want to use, so I recommended creating a wrapper that will communicate which type of derived child we want and return a Base pointer that points to a new derived object. This wrapper, to my understanding, is a factory.

Well, a colleague of mine created a static function in the Base class to act as the factory. This causes me trouble for two reasons. First, it seems to break the interface nature of the Base class. It feels wrong to me that the interface would itself need to have knowledge of the children derived from it.

Secondly, it causes more problems when I try to re-use the Base class across two different Qt projects. One project is where I am implementing the first (and probably only real implementation for this one class... though i want to use the same method for two other features that will have several different derived classes) derived class and the second is the actual application where my code will eventually be used. My colleague has created a derived class to act as a tester for the real application while I code my part. This means that I've got to add his headers and cpp files to my project, and that just seems wrong since I'm not even using his code for the project while I implement my part (but he will use mine when it is finished).

Am I correct in thinking that the factory really needs to be a wrapper around the Base class rather than the Base acting as the factory?

Aoristic answered 14/2, 2011 at 12:46 Comment(4)
@sbi If you look at some other comments I've made in the past, I tend to agree. However, when I have a question regarding code architecture, I've got to do my best to use the nomenclature of the community in order to convey the problem. It seems there is a consensus that my thoughts are correct: doing it the current way is limiting and will cause problems. By using the "factory" terminology, I was able to convey my question. Do you see the advantage in my doing this?Aoristic
I wasn't trying to judge what you've asked about here. I was merely making a general statement. I now see that this must have seemed like an assault against your question. Sorry for that.Hayfork
@Hayfork I'd say it was more that your comment left me asking "is it your opinion that it is wrong to try to use the common terminology for a technique, or is it that I shouldn't be using this technique?" than that I felt assaulted. Your answers and comments on SO are usually rather terse, so while I seek out your writings when they are applicable to something I'm looking up, I often wish you'd share as much reasoning as you can for your statements since I know that you personally have good reasoning. Thus my comment to your comment.Aoristic
Thank you very much for this feedback! In the future I will try to not to be terse in my answers.Hayfork
B
20

You do NOT want to use your interface class as the factory class. For one, if it is a true interface class, there is no implementation. Second, if the interface class does have some implementation defined (in addition to the pure virtual functions), making a static factory method now forces the base class to be recompiled every time you add a child class implementation.

The best way to implement the factory pattern is to have your interface class separate from your factory.

A very simple (and incomplete) example is below:

class MyInterface
{
public:
    virtual void MyFunc() = 0;
};

class MyImplementation : public MyInterface
{
public:
    virtual void MyFunc() {}
};

class MyFactory
{
public:
    static MyInterface* CreateImplementation(...);
};
Buchanan answered 14/2, 2011 at 12:56 Comment(15)
Exactly right – except there's no reason for CreateImplementation to be static. It should either be a non-static method or a free function.Stewart
Ok. Thanks. This was my thought. I'll start the move before he gets in. The less work he has to do, the more likely he is to accept the alternative :)Aoristic
+1 Although, I would like to see a smart_ptr or copy being returned by CreateImplementation and not a raw pointer.Carlacarlee
What T33c says: just return a plain value rather than a pointer, and rely on the compiler doing RVO for performance - unless you have specific needs requiring otherwise, and then use a smart pointer container.Epigenesis
@Fred: Correct. It could be a free function. I left it in its own class to show the point that you do not want it in your interface definition.Buchanan
@Eamon: no, you can't return an abstract base class by value; the factory has to return a pointer, smart or otherwise.Thorson
In general CreateImplementation can't return by value. The runtime type of an object created by a factory function might depend on the arguments to the factory function (or if the factory function is a member function, also on dependencies injected into the object it's called on). That's the whole point of calling a factory function rather than a constructor - you don't care what class is returned. Returning a smart pointer is OK (within a DLL) only if either: everyone uses the same smart ptr for all purposes; or you choose a smart pointer with a release() function. Beware shared_ptr.Jourdain
Devils advocate: why does it matter that the base class must be recompiled every time a class is added? How is this worse than requiring the Factory class to be recompiled every time a class is added? After all, the class interface isn't changing, so this won't cause cascading other updates and lots of compile-time slowdown.Epigenesis
@Eamon: Why do we put things in classes at all? Why not make every application a single massive monolithic entity. It is not just compilation, it also requires every child class to be relinked, and logically, just puts a method in a place it doesn't below. Having worked on a project where the previous engineer had done this exact bad practice, it is far better to have the factory method outside the base class.Buchanan
@Eamon: as well as what Zac says, in a design that isn't rubbish it's likely that more things use the interface than use the factory, since some things will take objects as parameters and act on them, but won't create the objects themselves. So you can reduce coupling/dependencies by ensuring that things that only need the interface don't also depend on the factory function. Fundamentally the idea of "the" factory function is flawed. If the interface is a worthwhile abstraction, there's probably more than one conceivable way to create an object implementing it.Jourdain
Thanks for the feedback! To be clear: I'm brainstorming and could be spouting nonsense (e.g. the return-by-value nonsense :-) ). Including the (static) factory method in the interface would not require child classes to be relinked: effectively, the interface is no more than an easily-remembered namespace, right? So isn't this just a tradeoff between simplicity in the sense of avoiding large APIs and fine-grained control? E.g. many interfaces could be split into components, but at some point the extra precision isn't worth the complexity.Epigenesis
@Eamon: You aren't increasing the size of the API; you are organizing the API such that each interface/implementation serves 1 purpose. When you start having objects serve multiple purposes, you increase the complexity of your code (and usually end up having to make special cases for certain states).Buchanan
But there's no object involved - it's a static method, after all. The factory method might well be in a seperate compilation unit from other code concerning the interface - it's just namespacing. And it seems natural enough to avoid namespace pollution by having the interface be the namespace for the factory method for that interface.Epigenesis
@Eamon: This comes from experience - it is not natural to do that. Group your code logically and other programmers will thank you for it. Try to group it "out of convenience", and you will have your picture on the wall with darts thrown at it regularly.Buchanan
So the argument is that it's conventional to have all implementation details concerning an abstract base class in one file; and if so, having a factory method on the ABC means recompiling the ABC whenever a subclass is added (though that's probably cheap if your ABC has a small implementation). Additionally, Steve suggests making the factory a separate API to minimize the API surface. On the other hand, an extra code file and extra namespace have their own intrinsic costs. Which suggests to me that the more widely used the interface is, the more worthwhile it is to separate the factory out.Epigenesis
H
4

I'd have to agree with you. Probably one of the most important principles of object oriented programming is to have a single responsibility for the scope of a piece of code (whether it's a method, class or namespace). In your case, your base class serves the purpose of defining an interface. Adding a factory method to that class, violates that principle, opening the door to a world of shi... trouble.

Harlequinade answered 14/2, 2011 at 13:5 Comment(1)
Very true indeed. A base class is a just a base class, not a factory for itself or descendants.Tiphani
S
3

Yes, a static factory method in the interface (base class) requires it to have knowledge of all possible instantiations. That way, you don't get any of the flexibility the Factory Method pattern is intended to bring.

The Factory should be an independent piece of code, used by client code to create instances. You have to decide somewhere in your program what concrete instance to create. Factory Method allows you to avoid having the same decision spread out through your client code. If later you want to change the implementation (or e.g. for testing), you have just one place to edit: this may be e.g. a simple global change, through conditional compilation (usually for tests), or even via a dependency injection configuration file.

Be careful about how client code communicates what kind of implementation it wants: that's not an uncommon way of reintroducing the dependencies factories are meant to hide.

Smoothtongued answered 14/2, 2011 at 12:57 Comment(0)
P
2

It's not uncommon to see factory member functions in a class, but it makes my eyes bleed. Often their use have been mixed up with the functionality of the named constructor idiom. Moving the creation function(s) to a separate factory class will buy you more flexibility also to swap factories during testing.

Phylis answered 14/2, 2011 at 12:58 Comment(1)
If my colleague would like, I will suggest to combine this idiom in the factory itself, but the coupling of the modules that I won't even use in a different set of code seems bad to me.Aoristic
Q
1

When the interface is just for hiding the implementation details and there will be only one implementation of the Base interface ever, it could be ok to couple them. In that case, the factory function is just a new name for the constructor of the actual implementation.

However, that case is rare. Except when explicit designed having only one implementation ever, you are better off to assume that multiple implementations will exist at some point in time, if only for testing (as you discovered).

So usually it is better to split the Factory part into a separate class.

Quiet answered 14/2, 2011 at 12:59 Comment(1)
If there is only one implementation of an interface, ever, you don't really need an interface. You could use the PIMPL pattern (though overuse of it has its own drawbacks).Klaxon

© 2022 - 2024 — McMap. All rights reserved.