我可以在不使用new()的情况下实现工厂模式构造吗?
Can I implement Factory-pattern construction without using new()?
目前,我正在处理一个通过切换大小写实现多态性的令人愉快的遗留代码类:
class LegacyClass {
public:
enum InitType {TYPE_A, TYPE_B};
void init(InitType type) {m_type=type;}
int foo() {
if (m_type==TYPE_A)
{
/* ...A-specific work... */
return 1;
}
// else, TYPE_B:
/* ...B-specific work... */
return 2;
}
/** Lots more functions like this **/
private:
InitType m_type;
};
我想将其重构为适当的多态性,例如:
class RefactoredClass {
public:
virtual ~RefactoredClass(){}
virtual int foo()=0;
};
class Class_ImplA : public RefactoredClass {
public:
virtual ~Class_ImplA(){}
int foo() {
/* ...A-specific work... */
return 1;
}
};
class Class_ImplB : public RefactoredClass {
public:
virtual ~Class_ImplB(){}
int foo() {
/* ...B-specific work... */
return 2;
}
};
不幸的是,我有一个关键的问题:由于优化和体系结构的考虑,在LegacyClass
的主要使用中,我不能使用动态分配;通过组合,实例是另一个类的成员:
class BigImportantClass{
/* ... */
private:
LegacyClass m_legacy;
}
(在本例中,BigImportantClass
可以动态分配,但分配需要在一个连续的虚拟段中,并且需要单个new()
调用;我不能在BigImportantClass
函数或随后的初始化方法中进一步调用new()
。
是否有一个好的方法来初始化一个具体的实现,多态的,不使用new()
?
到目前为止,我自己的进展是:我可以做的是提供一个
char[]
缓冲区作为BigImportantClass
的成员,并在该内存中初始化一个RefactoredClass
的具体成员。缓冲区足够大,可以容纳RefactoredClass
的所有实现。然而,我不知道如何安全地做到这一点。我知道place -new语法,但我是处理对齐的新手(因此,c++ -FAQ警告我…),并且对RefactoredClass
接口的所有具体实现进行通用对齐听起来令人望而生畏。是这条路吗?或者我还有其他选择吗? 下面是一些代码…只是做一些显而易见的事情。我没有使用c++ 11的新union
特性,这实际上可能是一种更结构化的方式,以确保适当的对齐和大小,并清理代码。
#include <iostream>
template <size_t A, size_t B>
struct max
{
static const size_t value = A > B ? A : B;
};
class X
{
public:
X(char x) { construct(x); }
X(const X& rhs)
{ rhs.interface().copy_construct_at_address(this); }
~X() { interface().~Interface(); }
X& operator=(const X& rhs)
{
// warning - not exception safe
interface().~Interface();
rhs.interface().copy_construct_at_address(this);
return *this;
}
struct Interface
{
virtual ~Interface() { }
virtual void f(int) = 0;
virtual void copy_construct_at_address(void*) const = 0;
};
Interface& interface()
{ return reinterpret_cast<Interface&>(data_); }
const Interface& interface() const
{ return reinterpret_cast<const Interface&>(data_); }
// for convenience use of virtual members...
void f(int x) { interface().f(x); }
private:
void construct(char x)
{
if (x == 'A') new (data_) Impl_A();
else if (x == 'B') new (data_) Impl_B();
}
struct Impl_A : Interface
{
Impl_A() : n_(10) { std::cout << "Impl_A(this " << this << ")n"; }
~Impl_A() { std::cout << "~Impl_A(this " << this << ")n"; }
void f(int x)
{ std::cout << "Impl_A::f(x " << x << ") n_ " << n_;
n_ += x / 3;
std::cout << " -> " << n_ << 'n'; }
void copy_construct_at_address(void* p) const { new (p) Impl_A(*this); }
int n_;
};
struct Impl_B : Interface
{
Impl_B() : n_(20) { std::cout << "Impl_B(this " << this << ")n"; }
~Impl_B() { std::cout << "~Impl_B(this " << this << ")n"; }
void f(int x)
{ std::cout << "Impl_B::f(x " << x << ") n_ " << n_;
n_ += x / 3.0;
std::cout << " -> " << n_ << 'n'; }
void copy_construct_at_address(void* p) const { new (p) Impl_B(*this); }
double n_;
};
union
{
double align_;
char data_[max<sizeof Impl_A, sizeof Impl_B>::value];
};
};
int main()
{
{
X a('A');
a.f(5);
X b('B');
b.f(5);
X x2(b);
x2.f(6);
x2 = a;
x2.f(7);
}
}
输出(带注释):
Impl_A(this 0018FF24)
Impl_A::f(x 5) n_ 10 -> 11
Impl_B(this 0018FF04)
Impl_B::f(x 5) n_ 20 -> 21.6667
Impl_B::f(x 6) n_ 21.6667 -> 23.6667
~Impl_B(this 0018FF14) // x2 = a morphs type
Impl_A::f(x 7) n_ 11 -> 13 // x2 value 11 copied per a's above
~Impl_A(this 0018FF14)
~Impl_B(this 0018FF04)
~Impl_A(this 0018FF24)
我使用c++ 11联合实现了这一点。这段代码似乎可以在g++ 4.8.2下工作,但它需要-std=gnu++11或-std=c++11标志。
#include <iostream>
class RefactoredClass {
public:
virtual ~RefactoredClass() { }; // Linking error if this is pure. Why?
virtual int foo() = 0;
};
class RefactorA : RefactoredClass {
double data1, data2, data3, data4;
public:
int foo() { return 1; }
~RefactorA() { std::cout << "Destroying RefactorA" << std::endl; }
};
class RefactorB : RefactoredClass {
int data;
public:
int foo () { return 2; }
~RefactorB() { std::cout << "Destroying RefactorB" << std::endl; }
};
// You may need to manually create copy, move, &ct operators for this.
// Requires C++11
union LegacyClass {
RefactorA refA;
RefactorB refB;
LegacyClass(char type) {
switch (type) {
case 'A':
new(this) RefactorA;
break;
case 'B':
new(this) RefactorB;
break;
default:
// Rut-row
break;
}
}
RefactoredClass * AsRefactoredClass() { return (RefactoredClass *)this; }
int foo() { return AsRefactoredClass()->foo(); }
~LegacyClass() { AsRefactoredClass()->~RefactoredClass(); }
};
int main (void) {
LegacyClass A('A');
LegacyClass B('B');
std::cout << A.foo() << std::endl;
std::cout << B.foo() << std::endl;
return 0;
}
现在应该有人回答了…这是我的
我建议使用字符数组和最大的整数类型之一的并集:
union {
char refactored_class_buffer[ sizeof RefactoredClass ];
long long refactored_class_buffer_aligner;
};
我还强烈建议使用assert甚至if(check)抛出;进入你的工厂,这样你就永远不会超过你的缓冲区的大小。
如果每种情况下的数据是相同的,并且您只是改变行为,则不需要在核心中分配-这基本上是使用单例策略的策略模式。您最终在逻辑中使用多态性,而不是在数据中使用多态性。
class FooStrategy() {
virtual int foo(RefactoredClass& v)=0;
}
class RefactoredClass {
int foo() {
return this.fooStrategy(*this);
}
FooStrategy * fooStrategy;
};
class FooStrategyA : public FooStrategy {
//Use whichever singleton pattern you're happy with.
static FooStrategyA* instance() {
static FooStrategyA fooStrategy;
return &fooStrategy;
}
int foo(RefactoredClass& v) {
//Do something with v's data
}
}
//Same for FooStrategyB
当你创建一个RefactoredClass
时,你将它的fooStrategy
设置为FooStrategyA::instance()
。
相关文章:
- 派生类是否可以在抽象工厂设计模式中具有数据成员
- 工厂设计模式优化
- 下面抽象工厂设计模式的实现是正确的吗
- 工厂方法模式使用继承而抽象工厂模式使用组合如何
- 使用宏替换工厂模式样式 API 中的"create()"函数
- 实现通用工厂设计模式
- 使用工厂模式实施单例
- 工厂模式与unique_ptr
- 设计模式的工厂替代方法:具有不同构造函数的类
- 具有多个继承的工厂模式
- 工厂模式和单例模式:未定义的引用
- 在任何编译语言中实现以下语法(用于工厂设计模式)? 最好是 Kotlin,C++
- 共享对象工厂的设计模式
- RAII和工厂设计模式
- 如何使工厂设计模式在C 中
- 对不同的参数使用工厂方法模式
- 实现工厂模式时虚拟功能的多重定义
- dlopen、工厂模式和虚拟方法表
- 工厂模式和std::绑定方法
- 这是哪种设计模式:工厂方法还是抽象工厂