我已经创建了一个接触管理课程来练习,我想知道你对此的看法。我知道有很多联系人管理类的例子,但是我尝试通过添加一些功能来使这个类有点不同,以避免使用错误的数据初始化联系人。例如,如果您尝试初始化与"asdf“的联系人的电话号码,则会出现警告或错误。你认为我用来验证输入数据的方法好吗?如果没有,你会怎么做。
我给出了一个使用类(演示)以及类数据成员和成员函数的头和定义的示例。
我非常愿意接受任何关于我的执行的建议,并预先感谢。
下面是我们班的一个例子或演示:
///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文件):
#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文件)
#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;
}发布于 2022-02-19 16:02:46
我要说的是,从长远来看,重新编译每个用例的程序都是不可用的。一次或两次可能很有趣,但很快就会变得烦人。通常的建议是创建一个基于命令行的菜单,但我有不同的想法。接受环境变量的联系人文件路径,这样只要路径有效,人们就可以在其终端的配置文件中设置它,而不会再次键入它。然后接受遵循非常严格格式的命令,稍后可以使用正则表达式传递这些命令。如果没有匹配,就错误退出。
用户体验(UX)是工程中一个非常重要的组成部分。大多数性能来自从上到下对应用程序的优化(使通用操作变得简单明了,允许在容易出错的操作之前设置一个保存点,将复杂的操作一步步地划分为一个进程)。这也适用于代码--我们可以使正确的用法比容易出错的使用更容易、更直观,对解决了哪些问题有具体的想法并对其进行优化,提供错误报告机制以方便错误搜索。
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类,它的功能就会受到严重限制。另外,我认为Contact或ContactsEntry是NPE的一个更好的名字。
为了使条目可扩展,代码可以使用std::map<std::string, std::string>而不是固定字段。在构造函数和修改函数中,联系人条目对象可以在保存前验证正确性和完整性。更重要的是,您可以将联系人文件保存为json或yaml格式,这样您就不再需要手动解析它了。有许多库为解析和格式化json和yaml提供了支持。
whatdata有点奇怪。它只有三个可能的返回值,但是返回类型表示有更多的可能返回值。最好只是有一个枚举:
enum class FieldType {
Email,
Phone,
Name
};这样,很明显只有三个可能的值,没有人需要知道它们的常量('n', 'p', 'e')。
也有一些小的东西一起产生严重的后果。其中之一是手动打开和关闭文件。最好每次创建一个新对象,并通过移动保存所需的对象。
另一件小事情还不清楚超载。edit重载的参数名称也不能使其更清楚。最好提供一个已重载operator=和operator std::string()的代理对象,以便该字段能够验证正确性。
可能还有更多的小事。
https://codereview.stackexchange.com/questions/274255
复制相似问题