C++ 朋友、抽象类和工厂模式
祝你们大家好 我正在我公司的一个复杂项目中工作,我在项目中使用了一些扭曲的工厂设计模式。省略细节;我有一些只能由“阅读器”创建的类(我称之为“设备”): 现在是“阅读器”,它恰好是设备的工厂:C++ 朋友、抽象类和工厂模式,c++,inheritance,factory-pattern,friend,C++,Inheritance,Factory Pattern,Friend,祝你们大家好 我正在我公司的一个复杂项目中工作,我在项目中使用了一些扭曲的工厂设计模式。省略细节;我有一些只能由“阅读器”创建的类(我称之为“设备”): 现在是“阅读器”,它恰好是设备的工厂: class ReaderBase { private: DeviceBase[] _devices; // to keep track of devices currently "latched" public: // some other methods, getters-set
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;
}
现在,这是我的工厂班;但它(正如你所看到的)纯粹是虚拟的。我从这本书中继承了一些特殊的读者:
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...
}
}
我使用这种模式的原因是:我为一个可以同时连接多个“读卡器”的系统而写,我必须同时使用它们
还有这些“装置”:我也可以公开它们的构造器,每个人都会很高兴;但我想确保它们不是由代码编写者自己创建的(以确保其他代码编写者不会这样做)
现在问题是:
ReaderX::PollforDevice
成为朋友,而不是整个ReaderX
类,但这对您帮助不大,只会为难以解决的循环依赖打开大门
实际上,如果不在两个层次结构中的类之间创建紧密耦合,就很难创建这样一种设计:层次结构X的类只能由层次结构Y的类创建,而不能由其他人创建。 我的方法是
DeviceX
,那么他们可以从读卡器
获得它,而不是以其他方式。确保在代码审查中强制执行此操作。
所有其他步骤都只是控制损坏BaseDevice
类暴露于读取器实现之外的代码ReaderBase
成为DeviceBase
的朋友,并为ReaderBase
提供一个函数来实际清理设备。这是必要的,以确保设备可以清理为什么要担心像
DeviceBase
这样的纯抽象基类的可构造性呢?如果它是正确设计的契约或抽象基类,则无论如何都不能构造它。除非你必须适应某种你没有提到的框架,否则只需做与隐藏相反的事情,例如:
struct DeviceBase {
virtual void Foo() = 0;
virtual void Bar() = 0;
virtual ~DeviceBase() = default;
};
顺便说一下,声明构造函数或析构函数private
将非常有效地使类“密封”。如果由于某种原因,DeviceBase
不是抽象的(在我看来这是一个严重的设计缺陷),那么就让构造函数受到保护
而不是私有
。需要麻烦的是具体设备
类的构造函数可访问性。假设您要“发布”这些实现类(即它们的定义可供库的用户访问),并且您希望强调禁止直接构造,请使用“访问习惯用法”(我为此发明的名称):
长话短说,最好的解决办法是根本不发布具体的实现类,其次是限制建设的某种“心理障碍”,例如上述类型的 别以为你能像朋友一样找到方法。是的,我知道,但在这些模式中,我所需要的只是“创建实例”——而不是接触他们的“私有成员”,我认为当我将基类构造函数设置为私有时,除了朋友之外,我不允许任何人创建实例;由于它是基类的私有构造函数,派生类也不能实例化。。。还是我对这个假设不正确?你可以试试,我其实不太确定。非常感谢!我想这一次我会偏离形式化表示,让一些东西起作用:)现在想想,你实际上暗示,如果我让ReaderBase成为朋友,并保护析构函数(为什么不保护构造函数),我就可以实现我想要的!因此,只要PollforDevice是ReaderBase中的一个虚拟声明函数,它可以进行清理和实例化,我就可以这样做,对吗?@AhmetIpkin:使构造函数受到保护不会增加任何内容,因为这样您就需要再次声明工厂类是它们可以创建的所有内容的朋友。对于析构函数,你没有这个问题,
struct DeviceBase {
virtual void Foo() = 0;
virtual void Bar() = 0;
virtual ~DeviceBase() = default;
};
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;
}
};
};
// Your ExternalReader::PollForDevice...
switch (dt) {
case Device1:
return impl_detail::DeviceAccess::Create<ConcreteDevice1>();
case Device2:
// etc...
}