我们有一个存储类Person,具有以下定义:

class Person
{
public:
    string m_name;
    string m_address;
    string m_phone_number;
};

我们希望有一个存储类PersonPool,它存储所有Person的实例。

类(class)要求:
  • 应该包含所有Person的实例。
  • 应该提供将Person添加到池中的方法。
  • 应该提供快速访问方法,以通过地址
  • 删除一个人
  • 应该通过地址
  • 为人提供快速非常量 getter

    我们建议以下类(class):
    class PersonPool
    {
    public:
        void add_person(const Person& p)   { m_persons.insert(p.m_address, p); }
        bool person_exists(string address) { return m_persons.has_key(address);     }
        Person& get_person(string address) { return m_persons[address];             }
        void remove_person(string address) { m_persons.erase(address);              }
    
    private:
        map<String,Person> m_persons;  ///> key: person address; value: Person's instance
    };
    

    使用范例

    说我有这段代码:
  • PersonPool p_pool;
  • 人p1;
  • p1.m_address =“x”;
  • p_pool.add_person(p1);
  • Person&p2 = p_pool.get_person(“x”);
  • p2.m_address =“y”;
  • p_pool.get_person(“y”);

  • 问题

    示例中的第6行修改了Person的地址。
    当我想基于新地址(“y”)获取Person时,PersonPool将无法返回此Person。它不“知道”地址已被修改,仍然将旧地址“x”作为该Person实例的密钥。

    有关PersonPool增强的建议:
  • map 的键不应是地址。
    问题:
  • 什么是正确的密钥?请记住,我们需要按地址进行快速访问。
  • 如果我们选择的新密钥也被Person的用户修改(即使m_name可能被修改)怎么办
  • PersonPool添加函数:
    void update_person(字符串old_address,字符串new_address)
    问题:
  • 丑陋。用户应该用我的不良设计来而不是
  • 如果用户不使用此方法怎么办
  • 仅提供const getter。存储在PersonPool中的对Person的任何修改都必须使用PersonPool提供的新功能来完成
    问题:
  • 违反了类(class)要求。我们需要非常量getter
  • 即使我们放弃了该要求,这也意味着我们必须在Person中复制PersonPool接口(interface)。我们当然不想这样做。

  • 题:

    您能想到一个更好的PersonPool实现。是否可以调整我的建议并摆脱此问题。

    谢谢您的宝贵时间!

    最佳答案

    我真的不能说这是否是学术 Activity 。无论如何,很难确定哪种特定的存储实现将为您带来最佳性能。这将取决于许多因素,包括(但不限于):

  • 数据集的大小(多少人)
  • 数据集的内容(字符串的格式和大小)
  • 您正在使用的特定库的效率
  • 典型用法(针对查找和更新进行优化)

  • 我将采用的方法是设计类接口(interface)以满足所有使用需求,构建一些简单的性能测试,并开始比较不同存储实现的相对性能。从最简单的实现开始,如有需要,继续进行更复杂的优化(避免过早的优化!)。

    这是封装的好处:您可以自由更改内部实现细节,而不会影响界面的用户。

    另外,使用地址作为唯一键似乎行不通。如果您实际上是在对现实世界的数据进行建模,那么不止一个人可以使用相同的地址(或姓名或电话号码)吗?我可能还会使用内部函数来封装唯一键的细节。

    有关类接口(interface)的一些建议:
    // use typedefs to make changes easier
    typedef string KEY_TYPE;
    typedef map<KEY_TYPE, Person> PERSON_POOL;
    typedef vector<Person> PERSONS;
    
    class PersonPool
    {
    public:
        void add_person(const Person& p);
        void update_person(const Person& p);
        Person get_person(string name, string address);
        void remove_person(string name, string address);
        bool person_exists(string name, string address);
    
        // find zero or more persons
        PERSONS get_persons_by_name(string name);
        PERSONS get_persons_by_address(string address);
        PERSONS get_persons_by_number(string number);
    
    private:
        KEY_TYPE get_key(string name, string address);
        KEY_TYPE get_key(const Person &p);
        PERSON_POOL m_persons;
    };
    

    示例实现:
    void Person::add_person(const Person& p)
    {
        m_persons.insert(get_key(p), p);
    }
    
    Person Person::get_person(const Person& p)
    {
        PERSON_POOL::iterator i = find(m_persons.begin(), m_persons.end(), get_key(p));
        if (i != m_persons.end())
            return i->second;
        throw "person not found";
    }
    

    无论如何,祝您的项目好运。

    09-16 06:48