Чтобы скрыть детали реализации, сделайте класс Encryption чисто виртуальным, без данных. Это делает основной файл заголовка простым и без подробностей реализации. Если вы хотите использовать наследование для повторного использования кода, тогда используйте промежуточный класс, такой как BaseEncryptionImpl (это будет в файле заголовка private / реализация).
Только исходный файл, который реализует статический фабричный метод getEncryptor
, должен включать реализации шифрования.
Этот фабричный метод должен возвращать std::auto_ptr
в отличие от необработанного указателя, чтобы быть безопасным для исключения. Клеветнический auto_ptr
предназначен для возврата указателя из функций. Кроме того, он уменьшает внешние зависимости вашего заголовка до стандартной библиотеки, в отличие от boost. Пользователи вашего класса могут использовать boost::smart_prt
или boost::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);
}