实现存储类以存储某个类的多个实例

时间:2013-10-22 10:36:22

标签: c++ class

我们有一个存储类,类Person,其定义如下:

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

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

课程要求:

  1. 应包含所有Person的实例。
  2. 应该提供将Person添加到池中的方法。
  3. 应提供快速访问方法,以便按地址移除某人
  4. 应为按地址提供快速非常规获取者
  5. 我们建议以下课程:

    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
    };
    

    用例

    说我有这段代码:

    1. PersonPool p_pool;
    2. 人p1;
    3. p1.m_address =“x”;
    4. p_pool.add_person(P1);
    5. 人&安培; p2 = p_pool.get_person(“x”);
    6. p2.m_address =“y”;
    7. p_pool.get_person( “Y”);
    8. 问题

      示例中的第6行修改了Person的地址 当我想根据新地址(“y”)获得Person时,PersonPool将无法返回此Person
      它“不知道”地址已被修改,并且仍将旧地址“x”保留为该Person实例的键。

      PersonPool增强的建议:

      1. 地图的关键不应该是地址 的问题:
        • 什么是正确的钥匙?请记住,我们需要快速按地址访问。
        • 如果我们选择的新密钥也被Person的用户修改(即使m_name可能被修改),该怎么办
      2. 将功能添加到PersonPool
        void update_person(string old_address,string new_address)
        问题:
        • 难看。用户应该对我糟糕的设计感到困扰。
        • 如果用户不使用此方法,该怎么办
      3. 仅提供const getter。存储在PersonPool中的 Person 的任何修改都必须使用PersonPool提供的 new 功能完成 的问题:
        • 打破了班级要求。我们需要非const getter
        • 即使我们放弃了该要求,也就是说我们必须在Person中复制PersonPool接口。我们当然不想这样做。
      4. 问题:

        您能想到更好的PersonPool实施。是否有可能调整我的建议并摆脱问题。

        感谢您的时间!

2 个答案:

答案 0 :(得分:1)

我无法确定这是否是学术活动。无论如何,很难确定具体的存储实现将为您提供最佳性能。这取决于许多因素,包括(但不限于):

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

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

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

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

关于类接口的一些建议:

// 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";
}

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

答案 1 :(得分:0)

使用带地址的std :: map作为关键不是一个好主意。如何使用矢量:

class Person
{
public:
    string m_name;
    string m_address;
    string m_phone_number;
    bool operator == (const Person& other)
    {
        return m_address == other.m_address;
    }
};

class PersonPool
{
public:
    void add_person(const Person& p)   { m_persons.push_back(p); }
    bool person_exists(string address) { return (getPerson(address) != m_persons.end());     }
    Person& get_person(string address) { return (*getPerson(address)); }
    void remove_person(string address) { m_persons.erase(getPerson(address)); }

private:
    vector<Person> m_persons; 
    vector<Person>::iterator getPerson(string address)
    {
        return find(m_persons.begin(), m_persons.end(), address);
    }
};
相关问题