【问题标题】:Best design for lookup-and-possibly-change method查找和可能更改方法的最佳设计
【发布时间】:2010-09-12 17:10:45
【问题描述】:

我正在设计一个存储(缓存)一组数据的类。我想查找一个值,如果该类包含该值,则使用它并修改该类的属性。我很关心公共界面的设计。
以下是该类的使用方式:

ClassItem *pClassItem = myClass.Lookup(value); 如果(pClassItem) { // 项目在类中找到,所以修改并使用它 pClassItem->SetAttribute(something); ... // 使用 myClass } 别的 { // 值在类中不存在,所以添加它 myClass.Add(value, something); }

但是我不想将 ClassItem 暴露给这个客户端(ClassItem 是 MyClass 的一个实现细节)。 为了解决这个问题,可以考虑以下几点:

bool found = myClass.Lookup(value); 如果(找到) { // 项目在类中找到,所以修改并使用它 myClass.ModifyAttribute(value, something); ... // 使用 myClass } 别的 { // 值在类中不存在,所以添加它 myClass.Add(value, something); }

但是,这是低效的,因为 Modify 必须再次进行查找。这将建议使用 lookupAndModify 类型的方法:

bool found = myClass.LookupAndModify(value, something); 如果(找到) { // 项目在类中找到 ... // 使用 myClass } 别的 { // 值在类中不存在,所以添加它 myClass.Add(value, something); }

但是将 LookupAndModify 整合到一种方法中似乎是非常糟糕的设计。它也只在找到值时进行修改,因此名称不仅麻烦而且容易误导。

还有其他更好的设计可以解决这个问题吗?任何设计模式(我无法通过谷歌找到任何东西)?

【问题讨论】:

    标签: oop


    【解决方案1】:

    实际上std::set<>::insert() 正是这样做的。如果值存在,则返回指向现有项的迭代器。否则,返回插入的迭代器。

    您很可能正在使用类似的数据结构进行快速查找,因此干净的公共接口(调用站点)将是:

    myClass.SetAttribute(value, something)
    

    它总是做正确的事。 MyClass 处理内部管道,客户不用担心值是否存在。

    【讨论】:

    • 如果您查看提供的用例,它们都会得到相同的结果——对象被修改和存储。那么,为什么(在这个级别)通过让客户端每次都进行两项检查来暴露和复杂化接口。
    • 我假设 // 使用 myClass 是一个线索,如果值已经存在,就会发生不同
    【解决方案2】:

    两件事。

    第一个解决方案很接近。

    但不要返回ClassItem *。返回一个“不透明对象”。对客户端不透明(无意义)但可由 myClass 实例使用的整数索引或其他哈希码。

    然后查找返回一个索引,修改可以随后使用。

    void *index = myClass.lookup( value );
    if( index ) {
        myClass.modify( index, value );
    }
    else {
        myClass.add( value );
    }
    

    编写“原始”查找、修改和添加后,然后编写围绕这些原始构建的您自己的复合操作。

    编写一个 LookupAndModify、TryModify、AddIfNotExists 和其他从您的低级部分构建的方法。

    【讨论】:

    • 这是我最初考虑的,但在发布我的问题时忘记了。我不太喜欢使用不透明对象,因为类型安全会成为问题,但我想只要仔细构造类就可以了。
    • 不透明的项目可以轻松输入安全。您不必使用 void*,您可以改用 MySecretThing*。 MySecretThing 可以包含大量私人内容或 void*。
    【解决方案3】:

    这假设您在 Modify 和 Add 情况下都将 value 设置为相同的“某物”:

    if (!myClass.AddIfNotExists(value, something)) {
       // use myClass
    }
    

    否则:

    if (myClass.TryModify(value, something)) {
       // use myClass
    } else {
       myClass.Add(value, otherSomething);
    }
    

    【讨论】:

    • 感谢您的回答。尽管您的名字更好,但我认为 TryModify 和 AddIfNotExists 都遭受与 LookupAndModify 相同的弱点 - 它们都在做 3 件事(查找、可能修改、返回找到),这对我来说似乎太多了。
    • 这取决于类的语义——我无法从通用代码示例中辨别出来。设计一个针对客户端使用优化的粗略界面很好(在很多情况下甚至更可取)。你的类是如何工作的(也许它有 3 个内部方法)是一个实现细节。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2017-12-05
    • 2019-06-17
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多