用C ++中的对象存储库构建工厂?

时间:2009-11-26 11:20:12

标签: c++ design-patterns oop factory-pattern

我想创建一个工厂来创建实现抽象接口的对象,该工具将返回对内部保留的对象的引用,并且不复制对象。这个想法与log4cxx / log4j Logger类设计中的想法非常相似。我还想尽可能多地隐藏客户端的详细信息,即查看暴露的.h文件不会泄露私有成员等实现细节。 例如:

EncryptorRef = Encryptor::getEncryptor("AES");

我想知道是否接受了此类设计的已发布指南/示例代码,因为我不想重新发明轮子,这项任务非常普遍。我想过使用静态工厂方法,里面的Singleton存储库,以及作为返回类型的具体对象的智能指针/引用。问题:

  • 这样的设计有一个简单的示例代码吗? (log4cxx的代码太复杂,无法用作骨架)
  • 我如何完全隐藏存储库,假设他只看到纯抽象的Encryptor类定义了encryptor.h?
  • 你会建议使用智能引用或指针作为返回类型吗?是否有智能参考的标准实现?
  • 任何其他建议将不胜感激

非常感谢!

3 个答案:

答案 0 :(得分:3)

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

答案 1 :(得分:0)

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

答案 2 :(得分:0)

隐藏实现细节使加密类纯虚拟,没有数据。这使主标头文件保持简单,没有实现细节。如果要使用继承进行代码重用,那么使用像BaseEncryptionImpl这样的中间类(这将在私有/实现头文件中)。

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

此工厂方法应返回std::auto_ptr而不是原始指针,以确保异常安全。备受诟病的auto_ptr用于从函数返回指针。此外,它还减少了标头库与标准库的外部依赖关系,而不是提升。您班级的用户可以根据自己的需要使用boost::smart_prtboost::scoped_ptr,两者都有auto_ptr个构建器。

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

Encryptor.h

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

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

Encryptor.cpp

#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;
  }
}

Client.cpp

void foo()
{
  boost::scoped_ptr enc(Encryption::getEncryption("FOO"));

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

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