我有一个设计繁琐的物体组合。 类X和Y是此设计的示意图,其中Y是X的组件。
class Y {
public:
std::string _name;
Y(std::string name) : _name(name) {}
};
class X {
Y _y;
public:
X(std::string name) : _y(name) {}
Y getY() { return _y; }
Y* getYPtr() { return &_y; }
};
请注意std::string _name
中的Y
是公开的。
我想要做的是通过Y::_name
的实例访问X
,为其编写新值,并有可能在程序的其他部分轻松撤消写操作
我的尝试如下:我使用包含三个信息的Undo
对象:
class Undo {
std::string _oldName;
std::string _newName;
std::string *_internalName;
public:
Undo(std::string *name) : _internalName(name) {}
void setOldName(std::string oldName) {
_oldName = oldName;
}
void setNewName(std::string newName) {
_newName = newName;
}
void undoToOldName() {
*_internalName = _oldName;
}
};
如果我想撤消写操作,我只需要在undoToOldName()
对象上调用Undo
方法。
示例:
X x("firstName");
Y *y = x.getYPtr();
// Prepare the undo object
Undo undo(&(y->_name));
undo.setOldName(y->_name);
undo.setNewName("secondName");
// Set new name
y->_name = "secondName";
// Output: secondName
std::cout << x.getY()._name << std::endl;
// Undo
undo.undoToOldName();
// Output: firstName
std::cout << x.getY()._name << std::endl;
我不喜欢这种设计需要Y *
吸气剂。
作为约束,我无法改变构图的设计。
您能为此建议替代设计吗?
感谢。
答案 0 :(得分:1)
一些评论:Undo
对象不需要setOldName
方法。它可以解决它,因为它有字符串指针。其次,它也不需要setNewName
;它只需要一种方法来告诉它何时设置新值。 (假设你需要它,我怀疑)
一个不错的设置是让getYPtr()
返回undo_ptr<Y>
。这是一个瘦的垫片,它知道相关的Undo
对象。调用undo_ptr<Y>::~undo_ptr
时,即客户端完成时,将调用关联的Undo::newNameSet
方法。如上所述,这只是通过提供的指针提取新值。
示例:
X x("firstName");
{
Undo undo(x, &X::name); // Slightly cleaner interface. Saves "firstName".
Y* y = x.getYPtr();
y->_name = "secondName";
// Output: secondName
std::cout << x.getY()._name << std::endl;
// Undo (calls Undo::operator(), the convention for functors).
undo();
// Output: firstName
std::cout << x.getY()._name << std::endl;
}
如您所见,在这种情况下无需捕获新名称,因此您不需要undo_ptr<Y>
的框架。
答案 1 :(得分:1)
使用对象修饰符保护修订版的不变性非常棘手。如果您需要一次回滚多个字段而一个失败,您会怎么做?您的修订控件实际上可能会影响对象的正常操作。
版本对象的一种简单方法是保留对象的所有版本。当您需要回滚时,只需将其替换为旧版本的副本即可。
答案 2 :(得分:0)
为什么要上新课?您可以使用X
,beginTransaction
和commitTransaction
方法扩展类rollbackTransaction
,以及update
方法,如果在事务之外调用它,则可以选择断言。