首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >接触管理系统

接触管理系统
EN

Code Review用户
提问于 2022-02-19 08:05:02
回答 1查看 918关注 0票数 4

我已经创建了一个接触管理课程来练习,我想知道你对此的看法。我知道有很多联系人管理类的例子,但是我尝试通过添加一些功能来使这个类有点不同,以避免使用错误的数据初始化联系人。例如,如果您尝试初始化与"asdf“的联系人的电话号码,则会出现警告或错误。你认为我用来验证输入数据的方法好吗?如果没有,你会怎么做。

我给出了一个使用类(演示)以及类数据成员和成员函数的头和定义的示例。

我非常愿意接受任何关于我的执行的建议,并预先感谢。

下面是我们班的一个例子或演示:

代码语言:javascript
复制
///IMANIPOUR Meysam
/// comment lines start with 3 forward slash.(///).
/// if the line contian 2 forward slash it could be run.

#include <iostream>
#include "Contacts_Manager.h"

int main(int argc, char* argv[])
{

    if(argc < 2)
    {
        std::cerr << "phonebook path has not specified. please specify it as second argument. " << "\n";
        return EXIT_FAILURE;
    }
    if(argc > 2)
    {
        std::cerr << "extra command argument is provided\n";
        return EXIT_FAILURE;
    }
    ///creating the object of the class.
    //Contacts_Manager cm(argv[1]);
   
    ///4 different ways of initializing new contact.
    //cm.newcontact("ali","12345","ali@mail.com");
    //cm.newcontact(NPE("hassan","23456","hassan@hotmail.com"));
    //cm.newcontact("hossein","34567");
    //cm.newcontact(NPE("sadjad","45678"));
    
    ///wrong data input and warning handling.
    //cm.newcontact("@name","09876");// wrong name warning will arise.
    //cm.newcontact("name","j9382");// wrong phone number warning will arise.
    //cm.newcontact("name","84989","test"); // wrong email warning will arise.
    //cm.newcontact("ali","28913","anemail@gmail.com");// duplicated contact info warning will arise.

    ///removeing an existing member of phone book.
    //cm.removecontact("sadjad"); // it could be by phone number like -> cm.removecontact("45678") 
    
    ///warning for non existing data.
    //cm.removecontact("notexistdata"); // warning will arise saying this info doesn't exist to be removed.
   
    /// edit contacts of the phone book. 
    //cm.edit("ali","Ali");//will edit contact with name ali to be Ali.
    //cm.edit("Ali","11111");//will edit will name Ali to have a new phone number like"11111".
    //cm.edit("sadjad","NewSadjad","99999");//editing contact named sadjad to a new neme and new phone number
    //cm.edit("23456","newemail@hotmail.com");//editing a contact with the given phone numbe to have the new email(2nd arugment).
    //cm.edit("hossein","newname","98989","Newemail@server.com");
    
    ///if the given new data for editing are not correct(for example phone without digits) then there will be warning.
    
    ///print the info of a contact with giving one data of that contact. 
    //cm.printinfo("NewSadjad");
   
    ///remove all the contact 
    //cm.removeall();
    return 0;
}   

下面是声明(*.h文件):

代码语言:javascript
复制
#ifndef CONTACTS_MANAGER_H
#define CONTACTS_MANAGER_H

#include <iostream>
#include <string>
#include <set>
#include <fstream>
#include <sstream>
#include <locale>

struct NPE{ // stand for Name Phone Email
    NPE(std::string _Name, std::string _Phone, std::string _Email = "not defined");
    std::string Name, Phone, Email;
};

class Contacts_Manager
{
public:
    typedef const std::string& strp;
    Contacts_Manager(strp _Dir);
    void newcontact(const NPE& _NPE);
    void newcontact(strp _Name, strp _Phone, strp _Email = "not defined");
    void removecontact(strp _CurrentData);//remove the contact which include _CurrentData
    void edit(strp _CurrentData, strp _NewData);//edit info of a contact which include _CurrentData with replacing _NewData(s).
    void edit(strp _CurrentData, strp _NewData1, strp _NewData2);
    void edit(strp _CurrentData, strp _NewData1, strp _NewData2, strp _NewData3);
    void printinfo(strp _SearchData);//it fill find a contact based _SearchData and print its info.
    void removeall();
private:
    std::string Dir;// path to phonebook, where we store contacts info.
    std::fstream Fio;
    std::set<std::string> tempo_phonebook;
    char whatdata(strp _Data);//return 'n' if _Data is name, return 'p' if _Data is Phone and 'e' if _Data is email. 
    int find(strp _Dataitem);//return the number of the line containing _Dataitem.(_Dataitem could be name, phone or email).
    
};

#endif

以下是函数的定义(*.cpp文件)

代码语言:javascript
复制
#include "Contacts_Manager.h"

NPE::NPE(std::string _Name, std::string _Phone, std::string _Email)
{
    Name  = _Name;
    Phone = _Phone;
    Email = _Email;
};

Contacts_Manager::Contacts_Manager(strp _Dir)
{
    Dir = _Dir;
}

char Contacts_Manager::whatdata(strp _Data)
{
    
    if(_Data.find('@')!= std::string::npos||_Data == "not defined")
    {
        return 'e';
    }
    else if (std::isdigit(_Data[0]) == 1)
    {
        return 'p';
    }
    else
    {
         return 'n'; 
    }
}

int Contacts_Manager::find(strp _Dataitem)
{
    char datatype = this->whatdata(_Dataitem);
    int fline = 0;
    Fio.close();
    Fio.open(Dir,std::ios::in);
    std::string line;
    while(std::getline(Fio,line))
    {
        size_t firstcomma = line.find(',',0);
        size_t secondcomma= line.find(',',firstcomma+1);
        size_t res = line.find(_Dataitem);
        if(res != std::string::npos)
        {
            switch(datatype)
            {
                case 'n':
                    {
                        if(!line.compare(0,firstcomma,_Dataitem))
                        {
                             Fio.close();
                             return fline;
                        }
                    }break;
                case 'p':
                    {
                        if(!line.compare(firstcomma+1,secondcomma-firstcomma-1,_Dataitem))
                        {
                             Fio.close();
                             return fline; 
                        }

                    }break;
                case 'e':
                    {
                        if(!line.compare(secondcomma+1,line.length()-secondcomma-1,_Dataitem))
                        {
                             Fio.close();
                             return fline;                            
                        }
                    }break;
            }

        }
        fline++;
    }
    fline = -1;
    Fio.close();
    return fline;
}

void Contacts_Manager::newcontact(const NPE& _NPE)
{
    Fio.close();
    if (this->find(_NPE.Name) != -1)
    {
        std::cout << "this name is already exist." << "\n";
        return;
    }
    else if (this->whatdata(_NPE.Email) != 'e')
    {
        std::cout << "wrong email, basically email contiain '@' character." << "\n";
        return;
    }
    else if(this->whatdata(_NPE.Phone) != 'p')
    {
        std::cout << "wrong number, basically phone number should contain digits not letter" << "\n"; 
        return;
    }
    else if(this->whatdata(_NPE.Name) == 'e')
    {
        std::cout << "wrong name, basically name shouldn't contain '@' character." << "\n";
        return;
    }
    else
    {
        Fio.open(Dir, std::ios::app);
        Fio << _NPE.Name << "," << _NPE.Phone << "," << _NPE.Email << "\n";
    }
    return;
}

void Contacts_Manager::newcontact(strp _Name, strp _Phone, strp _Email)
{
    Fio.close();
    if(this->find(_Name) != -1)
    {
        std::cout << "this name is already exist." << "\n";
        return;
    }
    else if (this->whatdata(_Email) != 'e')
    {
        std::cout << "wrong email, basically email contiain '@' character." << "\n";
        return;
    }
    else if(this->whatdata(_Phone) != 'p')
    {
        std::cout << "wrong number, basically phone number should contain digits not letter" << "\n"; 
        return;
    }
    else if(this->whatdata(_Name) == 'e')
    {
        std::cout << "wrong name, basically name shouldn't contain '@' character." << "\n";
        return;
    }
    else
    {
        Fio.open(Dir,std::ios::app);
        Fio << _Name << "," << _Phone << "," << _Email << "\n";
    }
    return; 
}

void Contacts_Manager::removecontact(strp _CurrentData)
{
    int fline = this->find(_CurrentData);
    if(fline == -1)
    {
        std::cout << "can't find a contact with given info.\n";
        return;
    }
    Fio.close();
    Fio.open(Dir,std::ios::in);
    tempo_phonebook.clear();
    bool condition = true;
    std::string line;
    int cnt = 0;
    while(std::getline(Fio,line))
    {
        if(line == "")
           condition = false; 
        if(cnt != fline && condition)
        {
            tempo_phonebook.insert(line);
        }
        cnt++;
        condition = true;
    }
    Fio.close();
    Fio.open(Dir,std::ios::out|std::ios::trunc);
    for(auto i : tempo_phonebook)
    {
        Fio << i << "\n";
    }
    Fio.close();
}

void Contacts_Manager::edit(strp _CurrentName, strp _NewData)
{
    int fline = this->find(_CurrentName);
    if(fline == -1)
    {
        std::cout << "can't find a contact with given info." << "\n";
        return;
    }
    tempo_phonebook.clear();
    Fio.open(Dir,std::ios::in);
    std::string line;
    int cnt = 0;
    while(std::getline(Fio,line))
    {
        if(cnt == fline)
        {
            size_t firstcomma = line.find(',',0);
            size_t secondcomma= line.find(',',firstcomma+1);
            char datatype = this->whatdata(_NewData);
            switch(datatype)
            {
                case 'n':
                    {
                        line.replace(0,firstcomma,_NewData);
                    }break;

                case 'p':
                    {
                        line.replace(firstcomma+1,secondcomma-firstcomma-1,_NewData);
                    }break;
                case 'e':
                    {
                        line.replace(secondcomma+1,line.length()-secondcomma-1,_NewData);
                    }      
            }
            tempo_phonebook.insert(line);
        }
        else
        {
            tempo_phonebook.insert(line);
        }
        cnt++;
    }
    Fio.close();
    Fio.open(Dir,std::ios::out|std::ios::trunc);
    for(auto i : tempo_phonebook)
    {
        Fio << i << "\n";
    }
    Fio.close();
    return;
}
//I was thinking if I could use multiprocessing then I would invok two times edit function with _NewData 1 and 2.
void Contacts_Manager::edit(strp _CurrentData, strp _NewData1, strp _NewData2)
{
    if(this->whatdata(_NewData1) == this->whatdata(_NewData2))
    {
       std::cout << "Please enter two different types of data.\n";
       std::cout << "More detial -> " << _NewData1 << " and " << _NewData2 << "are both the same type.\n";
       return;
    }
    if(this->whatdata(_NewData1) != this->whatdata(_CurrentData))
    {
        this->edit(_CurrentData,_NewData1);
        this->edit(_CurrentData,_NewData2);
        return;
    }
    else if(this->whatdata(_NewData2) != this->whatdata(_CurrentData))
    {
        this->edit(_CurrentData,_NewData2);
        this->edit(_CurrentData,_NewData1);
        return;
    }
    else 
    {
        this->edit(_CurrentData,_NewData2);
        this->edit(_CurrentData,_NewData1);
        return;
    }
}

void Contacts_Manager::edit(strp _CurrentData, strp _NewData1, strp _NewData2, strp _NewData3)
{
    char input_types[3] = {this->whatdata(_NewData1),this->whatdata(_NewData2),this->whatdata(_NewData3)};
    if(input_types[0] == input_types[1] || input_types[0] == input_types[2] || input_types[1] == input_types[2])
    {
       std::cout << "Please enter different types of new data.\n";
       return;
    }

    if(input_types[0] != this->whatdata(_CurrentData))
    {
        this->edit(_CurrentData,_NewData1);
        if(input_types[1] != this->whatdata(_CurrentData))
        {
            this->edit(_CurrentData,_NewData2);
            this->edit(_CurrentData,_NewData3);
            return;
        }
        else if(input_types[2] != this->whatdata(_CurrentData))
        {
            this->edit(_CurrentData,_NewData3);
            this->edit(_CurrentData,_NewData2);
            return;
        }
    }

    if(input_types[1] != this->whatdata(_CurrentData))
    {
        this->edit(_CurrentData,_NewData2);
        if(input_types[0] != this->whatdata(_CurrentData))
        {
            this->edit(_CurrentData,_NewData1);
            this->edit(_CurrentData,_NewData3);
            return;
        }
        else if(input_types[2] != this->whatdata(_CurrentData))
        {
            this->edit(_CurrentData,_NewData3);
            this->edit(_CurrentData,_NewData1);
            return;
        }
    }
    
    if(input_types[2] != this->whatdata(_CurrentData))
    {
        this->edit(_CurrentData,_NewData3);
        if(input_types[0] != this->whatdata(_CurrentData))
        {
            this->edit(_CurrentData,_NewData1);
            this->edit(_CurrentData,_NewData2);
            return;
        }
        else if(input_types[1] != this->whatdata(_CurrentData))
        {
            this->edit(_CurrentData,_NewData2);
            this->edit(_CurrentData,_NewData1);
            return;
        }
    }

}


void Contacts_Manager::printinfo(strp _SearchData)
{
    int fline = this->find(_SearchData);
    if(fline == -1)
    {
        std::cout << "No contact has been found" << "\n";
        return;
    }
    Fio.close();
    Fio.open(Dir,std::ios::in);
    int cnt = 0;
    std::string line;
    while(std::getline(Fio,line))
    {
        if(cnt == fline)
        {
            size_t firstcomma = line.find(',',0);
            size_t secondcomma= line.find(',',firstcomma+1);
            std::cout << "Name  : " << line.substr(0,firstcomma) << "\n";
            std::cout << "Phone : " << line.substr(firstcomma+1,secondcomma-firstcomma-1) << "\n";
            std::cout << "Email : " << line.substr(secondcomma+1,line.length()-secondcomma-1) << "\n";
            return;
        }
        cnt++;
    }
}

void Contacts_Manager::removeall()
{
    Fio.close();
    Fio.open(Dir,std::ios::out|std::ios::trunc);
    Fio.close();
    return;
}
EN

回答 1

Code Review用户

发布于 2022-02-19 16:02:46

接口审查

我要说的是,从长远来看,重新编译每个用例的程序都是不可用的。一次或两次可能很有趣,但很快就会变得烦人。通常的建议是创建一个基于命令行的菜单,但我有不同的想法。接受环境变量的联系人文件路径,这样只要路径有效,人们就可以在其终端的配置文件中设置它,而不会再次键入它。然后接受遵循非常严格格式的命令,稍后可以使用正则表达式传递这些命令。如果没有匹配,就错误退出。

用户体验(UX)是工程中一个非常重要的组成部分。大多数性能来自从上到下对应用程序的优化(使通用操作变得简单明了,允许在容易出错的操作之前设置一个保存点,将复杂的操作一步步地划分为一个进程)。这也适用于代码--我们可以使正确的用法比容易出错的使用更容易、更直观,对解决了哪些问题有具体的想法并对其进行优化,提供错误报告机制以方便错误搜索。

代码评审

代码语言:javascript
复制
struct NPE{ // stand for Name Phone Email
    NPE(std::string _Name, std::string _Phone, std::string _Email = "not defined");
    std::string Name, Phone, Email;
};

这可能在Contacts_Manager类中。尽管NPE是独立的,但如果不考虑manager类,它的功能就会受到严重限制。另外,我认为ContactContactsEntryNPE的一个更好的名字。

为了使条目可扩展,代码可以使用std::map<std::string, std::string>而不是固定字段。在构造函数和修改函数中,联系人条目对象可以在保存前验证正确性和完整性。更重要的是,您可以将联系人文件保存为json或yaml格式,这样您就不再需要手动解析它了。有许多库为解析和格式化json和yaml提供了支持。

whatdata有点奇怪。它只有三个可能的返回值,但是返回类型表示有更多的可能返回值。最好只是有一个枚举:

代码语言:javascript
复制
enum class FieldType {
    Email,
    Phone,
    Name
};

这样,很明显只有三个可能的值,没有人需要知道它们的常量('n', 'p', 'e')。

也有一些小的东西一起产生严重的后果。其中之一是手动打开和关闭文件。最好每次创建一个新对象,并通过移动保存所需的对象。

另一件小事情还不清楚超载。edit重载的参数名称也不能使其更清楚。最好提供一个已重载operator=operator std::string()的代理对象,以便该字段能够验证正确性。

可能还有更多的小事。

票数 5
EN
页面原文内容由Code Review提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://codereview.stackexchange.com/questions/274255

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档