我正在设计一个存储(缓存)一组数据的类。我想查找一个值,如果该类包含该值,则使用它并修改该类的属性。我关心公共界面的设计 以下是该课程的使用方法:
ClassItem *pClassItem = myClass.Lookup(value); if (pClassItem) { // item is found in class so modify and use it pClassItem->SetAttribute(something); ... // use myClass } else { // value doesn't exist in the class so add it myClass.Add(value, something); }
但是我不想将ClassItem暴露给这个客户端(ClassItem是MyClass的一个实现细节)。 为了解决这个问题,可以考虑以下几点:
bool found = myClass.Lookup(value); if (found) { // item is found in class so modify and use it myClass.ModifyAttribute(value, something); ... // use myClass } else { // value doesn't exist in the class so add it myClass.Add(value, something); }
然而,这是低效的,因为Modify必须再次进行查找。这将建议使用lookupAndModify类型的方法:
bool found = myClass.LookupAndModify(value, something); if (found) { // item is found in class ... // use myClass } else { // value doesn't exist in the class so add it myClass.Add(value, something); }
但将LookupAndModify滚动到一个方法似乎非常糟糕的设计。它也只会修改是否找到值,因此名称不仅繁琐,而且具有误导性。
还有另一个更好的设计可以解决这个问题吗?任何设计模式(我通过谷歌找不到任何东西)?
答案 0 :(得分:2)
实际上std::set<>::insert()
正是这样做的。如果值存在,则返回指向现有项的迭代器。否则,返回插入的迭代器。
无论如何,您可能正在使用类似的数据结构进行快速查找,因此一个干净的公共接口(调用站点)将是:
myClass.SetAttribute(value, something)
总是做正确的事。 MyClass处理内部管道,客户端不担心值是否存在。
答案 1 :(得分:1)
这假设您在“修改”和“添加”案例中将值设置为相同的“某事”:
if (!myClass.AddIfNotExists(value, something)) {
// use myClass
}
否则:
if (myClass.TryModify(value, something)) {
// use myClass
} else {
myClass.Add(value, otherSomething);
}
答案 2 :(得分:1)
两件事。
第一个解决方案已经结束。
但是,请不要返回ClassItem *
。返回“不透明对象”。对客户端不透明(无意义)但可由myClass实例使用的整数索引或其他哈希代码。
然后查找返回一个索引,修改后可以使用该索引。
void *index = myClass.lookup( value );
if( index ) {
myClass.modify( index, value );
}
else {
myClass.add( value );
}
在编写“原始”查找,修改和添加之后,编写围绕这些原语构建的自己的复合操作。
编写LookupAndModify,TryModify,AddIfNotExists以及从较低级别构建的其他方法。