Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/design-patterns/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ 在C+中使用对象存储库构建工厂+;?_C++_Design Patterns_Oop_Factory Pattern - Fatal编程技术网

C++ 在C+中使用对象存储库构建工厂+;?

C++ 在C+中使用对象存储库构建工厂+;?,c++,design-patterns,oop,factory-pattern,C++,Design Patterns,Oop,Factory Pattern,我想创建一个工厂,用于创建实现抽象接口的对象,该接口将返回对内部保存的对象的引用,而对象不会被复制。这个想法与log4cxx/log4j记录器类设计中的想法几乎相同。我还希望尽可能多地隐藏客户机的详细信息,即查看暴露的.h文件不会显示私有成员等实现细节。 例如: 我想知道是否有为此类设计发布的指南/示例代码,因为我不想重新发明轮子,而且这项任务非常常见。我考虑使用静态工厂方法、内部的单例存储库,以及对具体对象的智能指针/引用作为返回类型。问题: 这种设计有简单的代码示例吗?(log4cxx的代

我想创建一个工厂,用于创建实现抽象接口的对象,该接口将返回对内部保存的对象的引用,而对象不会被复制。这个想法与log4cxx/log4j记录器类设计中的想法几乎相同。我还希望尽可能多地隐藏客户机的详细信息,即查看暴露的.h文件不会显示私有成员等实现细节。 例如:

我想知道是否有为此类设计发布的指南/示例代码,因为我不想重新发明轮子,而且这项任务非常常见。我考虑使用静态工厂方法、内部的单例存储库,以及对具体对象的智能指针/引用作为返回类型。问题:

  • 这种设计有简单的代码示例吗?(log4cxx的代码太复杂,无法用作骨架)
  • 假设客户机只看到纯抽象的
    Encryptor
    class-defined Encryptor.h,我如何对客户机完全隐藏存储库
  • 您是否建议使用智能引用或指针作为返回类型?是否有智能参考的标准实施
  • 如有其他建议,将不胜感激

非常感谢

为了隐藏实现细节,我建议使用pImpl习惯用法。

只有当客户端不再需要对对象的引用时(例如,释放一些锁或其他资源,或减少一些引用计数),需要进行任何清理时,才使用智能指针作为返回值。如果没有必要这样做,我建议返回一个简单的参考。这样,客户机就知道他不必管理对象的生命周期或类似的事情。智能引用的标准实现是Boost.SmartPtr。
至于隐藏实现,只需将要公开的接口放入纯抽象基类中,并让客户机通过工厂获取实例。然后,他只需要带有抽象基类的头、带有工厂声明的头和要链接到的二进制文件。

要隐藏实现细节,请将加密类设置为纯虚拟的,没有数据。这使得主头文件保持简单,并且没有实现细节。如果您想使用继承来重用代码,那么可以使用像BaseEncryptionImpl这样的中间类(这将在私有/实现头文件中)

只有实现静态工厂方法的源文件
getEncryptor
必须包含加密实现

此工厂方法应返回一个
std::auto_ptr
,而不是一个原始指针,以确保异常安全。备受诟病的
auto_ptr
是为从函数返回指针而设计的。此外,它还将标头的外部依赖项减少到标准库,而不是boost。您的类的用户可以根据自己的需要使用
boost::smart_prt
boost::scoped_ptr
,两者都有
auto_ptr
构造函数

起初,我会尽可能简单地使用
getEncryptor
,可能使用
if-else-if
等来决定应该创建哪个。这比在单例中实现AbstractFactory注册表要简单得多。大多数时候,注册中心只是在转移问题。如何初始化注册表?您可以使用每个
EncryptionImpl
类定义的静态对象,其构造函数注册,析构函数注销,但如果链接器确定您不需要这些对象,因此不将它们包含在可执行文件或库中,则这可能会导致问题

加密机

class Encryptor {
public:
  virtual void encrypt(const Data & in, Data * out) = 0;
  virtual ~Encryptor();

  static std::auto_ptr<Encryptor> getEncryptor(const char * name);
};

隐藏的第一步是提供一个函数,并在内部保留完整的工厂类。没错,因此我猜它应该是工厂方法实现中使用的一个单例?不一定:您也可以使用
pimpl
习惯用法让一个类实例化工厂,这允许有多个工厂。。。如果你觉得有道理的话。然而,在大多数情况下,这些工厂确实是独一无二的,因此实现为
Singleton
。非常感谢您的详细回答!不过,我有以下顾虑:我希望(需要调查)每种类型都有一个具体的对象,并与所有客户共享。这是因为某些对象将具有相当大的缓存,构建它们需要读取配置。如果我为客户端克隆对象,我需要实现一些缓存共享机制。一种选择是按名称(某处)保存对象的静态映射,或者在启动时构造所有对象,或者在请求时检查是否已构造对象?要共享具体对象,您可能应该返回一个共享\u ptr。预创建对象和按需创建对象都有好处。预创建可能会减慢启动速度并使用比所需更多的内存,但会有助于解决getEcryption()中的线程问题。Ondemand具有更快的启动速度,但对getEcryption的调用可能具有不可预测的时间,而且实现起来也更复杂。如果您不介意复杂的实现并希望提高内存效率,那么可以将弱ptr存储在缓存中。
class Encryptor {
public:
  virtual void encrypt(const Data & in, Data * out) = 0;
  virtual ~Encryptor();

  static std::auto_ptr<Encryptor> getEncryptor(const char * name);
};
#include "Encryptor.h"
#include "EncryptorA.h"
#include "EncryptorB.h"

std::auto_ptr<Encryptor> Encryptor::getEncryptor(const char * name)
{
  // EncryptorA::NAME is a std::string
  if (EncryptorA::NAME == name) {
    return std::auto_ptr<Encryptor>(new EncryptorA);
  }
  else if (EncryptorB::NAME == name) {
    return std::auto_ptr<Encryptor>(new EncryptorB);
  }
  else {
    throw EncryptionNotDefined;
  }
}
void foo()
{
  boost::scoped_ptr enc(Encryption::getEncryption("FOO"));

  Data in = ...;
  Data out = ...;

  enc->encrypt(in, &out);
}