Good day to you all...
I'm working on a complex project on my company which I use some wringled Factory Design pattern in the project. Omiting the details; I have some classes (I call them "Devices") which can only be created by "Readers":
class DeviceBase // this is a virtual base class
{
public:
//some stuff
friend class ReaderBase; // this is OK and necessary I guess?
private:
DeviceBase(); // cannot create a device directly
//some more stuff
}
class Device1: public DeviceBase // some extended device
{
public:
//some stuff
private:
//some more stuff
}
class Device2: public DeviceBase // some other extended device
{
public:
//some stuff
private:
//some more stuff
}
Now the "Reader", which happens to be factory for devices:
class ReaderBase
{
private:
DeviceBase[] _devices; // to keep track of devices currently "latched"
public:
// some other methods, getters-setters etc ...
// this method will create the "Devices" :
virtual bool PollforDevice ( DeviceType, timeout) = 0;
}
Now, this is my factory class; but it's (as you can see) pure virtual. I have special Readers inherit from this one:
class InternalReader: public ReaderBase
{
public:
// define other inherited methods by specifics of this reader
bool PollforDevice( DeviceType dt, timeout ms)
{
switch(dt)
{
case Device1: { /* create new device1 and attach to this reader */ } break;
case Device2: { /* create new device2 and attach to this reader */ } break;
}
// show goes on and on...
}
}
class ExternalReader: public Reader
{
public:
// define other inherited methods by specifics of this reader
bool PollforDevice( DeviceType dt, timeout ms)
{
switch(dt)
{
case Device1: { /* create new device1 and attach to this reader */ } break;
case Device2: { /* create new device2 and attach to this reader */ } break;
}
// show goes on and on...
}
}
The reason I use this pattern is: I'm writing for a system that can have multiple of these "readers" attached at the same time and I must use them all at the same time.
And these "Devices": I can make theirs constructor public too, and everyone would be happy; but I want to make sure that they are not created by the code writers themselves (to make sure other coders of it)
Now the questions:
I'm sorry that the question is a very long one, but I just want to make it clear.
Thanks in advance...
Why bother about constructability of pure abstract base classes like DeviceBase
? It can't be constructed anyway if it is a properly designed contract or abstract base class. Unless you have to fit into some kind of framework which you didn't mention, just do the opposite of hiding, e.g.:
struct DeviceBase {
virtual void Foo() = 0;
virtual void Bar() = 0;
virtual ~DeviceBase() = default;
};
By the way, declaring the constructors or destructors private
will very effectively make your class "sealed". If for some reason DeviceBase
is not abstract (which were a serious design flaw in my eyes) make constructors protected
not private
. Where you need to bother, is the constructor accessibility of the concrete Device
classes. Assuming that you are going to "publish" these implementation classes (i.e. their definitions are accessible to users of your library) and you wish to stress that direct construction is prohibited, use the "access idiom" (my invented name for this):
namespace impl_detail {
class DeviceAccess;
}
class ConcreteDevice1 : public DeviceBase {
friend class impl_detail::DeviceAccess;
// implementation of DeviceBase and all other stuff go
// into the "private" section
};
namespace impl_detail {
class DeviceAccess {
template< class TDevice >
static DeviceBase* Create()
{
return new TDevice;
}
};
};
In your Reader
classes use impl_detail::DeviceAccess::Create
to construct Device
instances, e.g.:
// Your ExternalReader::PollForDevice...
switch (dt) {
case Device1:
return impl_detail::DeviceAccess::Create<ConcreteDevice1>();
case Device2:
// etc...
}
Long story short, best solution is to not publish concrete implementation classes at all, second best some kind of "psychological barrier" which restricts construction, e.g. of the above kind...