雇员记录系统
雇员记录系统
由于内容来自于《Professional C++》,所以书中相关说明不再赘述。
一、Employee类
我们先实现一个Employee类:
// Employee类声明 // Employee.h #pragma once #include <string> namespace EmployeeRecorder { const int kDefaultStartingSalary = 30000; class Employee { public: Employee(void); ~Employee(void); void promote(int inRaiseAmount = 1000); // 升职 void demote(int inDemeriteAmount = 1000); // 降职 void hire(); // 雇用 void fire(); // 解雇 void display() const; // 显示 // 检测器、修改器 void setFirstName(const std::string& inFirstName); std::string getFirstName() const; void setLastName(const std::string& inLastName); std::string getLastName() const; void setEmployeeNumber(int inEmployeeNumber); int getEmployeeNumber() const; void setSalary(int inNewSalary); int getSalary() const; void setIsHired(bool inIsHired); bool getIsHired() const; protected: std::string mFirstName; std::string mLastName; int mEmployeeNumber; int mSalary; bool bHired; }; }
// Employee类实现 // Employee.cpp #include "Employee.h" #include <iostream> namespace EmployeeRecorder { Employee::Employee(void) : mFirstName("") , mLastName("") , mEmployeeNumber(-1) , mSalary(kDefaultStartingSalary) , bHired(false) { } Employee::~Employee(void) { } void Employee::promote(int inRaiseAmount) { setSalary(getSalary() + inRaiseAmount); } void Employee::demote(int inDemeritAmount) { setSalary(getSalary() - inDemeritAmount); } void Employee::hire() { bHired = true; } void Employee::fire() { bHired = false; } void Employee::display() const { std::cout << "Employee: " << getLastName() << ", " << getFirstName() << std::endl; std::cout << "--------------------------------" << std::endl; std::cout << (bHired ? "Current Employee" : "Former Employee") << std::endl; std::cout << "Employee Number: " << getEmployeeNumber() << std::endl; std::cout << "Salary: $" << getSalary() << std::endl; std::cout << std::endl; } void Employee::setFirstName(const std::string& inFirstName) { mFirstName = inFirstName; } std::string Employee::getFirstName() const { return mFirstName; } void Employee::setLastName(const std::string& inLastName) { mLastName = inLastName; } std::string Employee::getLastName() const { return mLastName; } void Employee::setEmployeeNumber(int inEmployeeNumber) { mEmployeeNumber = inEmployeeNumber; } int Employee::getEmployeeNumber() const { return mEmployeeNumber; } void Employee::setSalary(int inNewSalary) { mSalary = inNewSalary; } int Employee::getSalary() const { return mSalary; } void Employee::setIsHired(bool inIsHired) { bHired = inIsHired; } bool Employee::getIsHired() const { return bHired; } }
// Employee类测试 // EmployeeTest.cpp #include "Employee.h" #include <iostream> using namespace std; using namespace EmployeeRecorder; int main() { // 测试Employee类 cout << "Testing the Employee class." << endl; Employee emp; emp.setFirstName("Marni"); emp.setLastName("Kleper"); emp.setEmployeeNumber(71); emp.setSalary(50000); emp.promote(); emp.promote(50); emp.hire(); emp.display(); return 0; }
二、Database类
下面设计Database类来存储Employee类对象。
// Database类定义 // Database.h #pragma once #include "Employee.h" #include <iostream> #include <vector> namespace EmployeeRecorder { const int kFirstEmployeeNumber = 1000; class Database { public: Database(void); ~Database(void); Employee& addEmployee(const std::string& inFirstName, const std::string& inLastName); Employee& getEmployee(int inEmployeeNumber) /*const*/; Employee& getEmployee(const std::string& inFirstName, const std::string& inLastName) /*const*/; void displayAll() const; void displayCurrent() const; void displayFormer() const; protected: std::vector<Employee> mEmployees; int mNextEmployeeNumber; }; }
// Database类实现 // Database.cpp #include "Database.h" #include <iostream> #include <stdexcept> namespace EmployeeRecorder { Database::Database(void) { mNextEmployeeNumber = kFirstEmployeeNumber; } Database::~Database(void) { } Employee& Database::addEmployee(const std::string& inFirstName, const std::string& inLastName) { Employee theEmployee; theEmployee.setFirstName(inFirstName); theEmployee.setLastName(inLastName); theEmployee.setEmployeeNumber(++mNextEmployeeNumber); theEmployee.hire(); mEmployees.push_back(theEmployee); return mEmployees[mEmployees.size() - 1]; } Employee& Database::getEmployee(int inEmployeeNumber) /*const*/ { for (auto iter = mEmployees.begin(); iter != mEmployees.end(); ++iter) { if (iter->getEmployeeNumber() == inEmployeeNumber) { return *iter; } } std::cerr << "No employee with number " << inEmployeeNumber << std::endl; throw std::exception(); } Employee& Database::getEmployee(const std::string& inFirstName, const std::string& inLastName) /*const*/ { for (auto iter = mEmployees.begin(); iter != mEmployees.end(); ++iter) { if (iter->getFirstName() == inFirstName && iter->getLastName() == inLastName) { return *iter; } } std::cerr << "No employee with number " << inFirstName << ' ' << inLastName << std::endl; throw std::exception(); } void Database::displayAll() const { for (auto iter = mEmployees.begin(); iter != mEmployees.end(); ++iter) { iter->display(); } } void Database::displayCurrent() const { for (auto iter = mEmployees.begin(); iter != mEmployees.end(); ++iter) { if (iter->getIsHired()) { iter->display(); } } } void Database::displayFormer() const { for (auto iter = mEmployees.begin(); iter != mEmployees.end(); ++iter) { if (!iter->getIsHired()) { iter->display(); } } } }
// Database类测试 // DatabaseTest.cpp #include "Database.h" #include <iostream> using namespace std; using namespace EmployeeRecorder; int main() { Database myDB; Employee& emp1 = myDB.addEmployee("Greg", "Wallis"); emp1.fire(); Employee& emp2 = myDB.addEmployee("Scott", "Kleper"); emp2.setSalary(100000); Employee& emp3 = myDB.addEmployee("Nick", "Solter"); emp3.setSalary(10000); emp3.promote(); cout << "All employees: " << endl; cout << endl; myDB.displayAll(); cout << endl; cout << "Current employees: " << endl; cout << endl; myDB.displayCurrent(); cout << endl; cout << "Former employees: " << endl; cout << endl; myDB.displayFormer(); cout << endl; return 0; }
三、用户界面
// UserInterface.cpp #include "Database.h" #include <iostream> #include <stdexcept> using namespace std; using namespace EmployeeRecorder; int displayMenu(); void doHire(Database& inDB); void doFire(Database& inDB); void doPromote(Database& inDB); void doDemote(Database& inDB); int main() { Database employeeDB; bool done = false; while (!done) { int selection = displayMenu(); switch (selection) { case 1: doHire(employeeDB); break; case 2: doFire(employeeDB); break; case 3: doPromote(employeeDB); break; case 4: doDemote(employeeDB); break; case 5: employeeDB.displayAll(); break; case 6: employeeDB.displayCurrent(); break; case 7: employeeDB.displayFormer(); break; case 0: done = true; break; default: cerr << "Unknown command." << endl; break; } } return 0; } int displayMenu() { int selection; cout << endl; cout << "Employee Database" << endl; cout << "-----------------" << endl; cout << "1) Hire a new employee" << endl; cout << "2) Fire an employee" << endl; cout << "3) Promote an employee" << endl; cout << "4) Demote an employee" << endl; cout << "5) List all employees" << endl; cout << "6) List all current employees" << endl; cout << "7) List all previous employees" << endl; cout << "0) Quit" <<endl; cout << endl; cout << "---> "; cin >> selection; return selection; } void doHire(Database& inDB) { string firstName; string lastName; cout << "First name? "; cin >> firstName; cout << "Last name? "; cin >> lastName; try { inDB.addEmployee(firstName, lastName); } catch (const exception&) { cerr << "Unable to add new employee!" << endl; } } void doFire(Database& inDB) { int employeeNumber; cout << "Employee number? "; cin >> employeeNumber; try { Employee& emp = inDB.getEmployee(employeeNumber); emp.fire(); cout << "Employee " << employeeNumber << " terminated." << endl; } catch (const exception&) { cerr << "Unable to terminate employee!" << endl; } } void doPromote(Database& inDB) { int employeeNumber; int raiseAmount; cout << "Employee number? "; cin >> employeeNumber; cout << "How much of a raise? "; cin >> raiseAmount; try { Employee& emp = inDB.getEmployee(employeeNumber); emp.promote(raiseAmount); } catch (const exception&) { cerr << "Unable to promote employee " << employeeNumber << '!' << endl; } } void doDemote(Database& inDB) { int employeeNumber; int lowerAmount; cout << "Employee number? "; cin >> employeeNumber; cout << "How much of a lower? "; cin >> lowerAmount; try { Employee& emp = inDB.getEmployee(employeeNumber); emp.demote(lowerAmount); } catch (const exception&) { cerr << "Unable to demote employee " << employeeNumber << '!' << endl; } }
四、对雇员记录系统的分析和讨论
以上雇员记录系统一共涉及了两个类:
Employee
Database
其中,Employee用于代表具体的一个雇员,Database是存放所有的雇员,即Database有Employee聚合而成。
Employee的成员函数有:
void promote(int inRaiseAmount = 1000); // 升职
void demote(int inDemeriteAmount = 1000); // 降职
void hire(); // 雇用
void fire(); // 解雇
void display() const; // 显示
// 检测器、修改器
void setFirstName(const std::string& inFirstName);
std::string getFirstName() const;
void setLastName(const std::string& inLastName);
std::string getLastName() const;
void setEmployeeNumber(int inEmployeeNumber);
int getEmployeeNumber() const;
void setSalary(int inNewSalary);
int getSalary() const;
void setIsHired(bool inIsHired);
bool getIsHired() const;
Database的成员函数有:
Employee& addEmployee(const std::string& inFirstName,
const std::string& inLastName);
Employee& getEmployee(int inEmployeeNumber) /*const*/;
Employee& getEmployee(const std::string& inFirstName,
const std::string& inLastName) /*const*/;
void displayAll() const;
void displayCurrent() const;
void displayFormer() const;
在具体的UserInterface.cpp中关于雇员的promote、demote操作是作用于Database上的,在具体的promote、demote操作是先通过Database的getEmployee获取具体的雇员,然后针对具体的雇员通过Employee中的promote、demote进行相应的操作。
这里就有个问题,为什么是要获取了具体的雇员,然后通过Employee里的promote、demote进行操作,而不再Database中设置相应的promote、demote操作对具体的雇员进行操作呢?这里我的理解是Database是Employee的聚合,promote、demote是针对某个具体的Employee进行的,虽然也可以通过EmployeeNumber在Database中对具体的雇员进行操作,但是这种操作不应该属于Database的,因为针对某个具体雇员的操作不应该放在全局的Database中,而应该放在单个的Employee中。这也就是类与类之间尽可能的耦合松些。
既然是通过Employee中的成员函数进行的操作,那么是如何实现的呢?
程序中,Database的成员函数getEmployee的返回类型为Employee&,在具体的doPromote、doDemote实现中具体变量为Employee&引用类型,所以,赋值之后操作的是Database中的某个Employee。
有关函数返回值类型、被赋值变量类型有以下几种情况:
函数返回值类型 |
被赋值变量类型 |
效果 |
数据份数 |
引用 |
引用 |
通过变量操作的是原数据 |
1份:原数据 |
引用 |
非引用 |
通过变量操作的是被赋值的变量 |
2份:原数据、被赋值变量 |
非引用 |
引用 |
通过变量操作的事返回的值,但是返回的值是一个局部临时值,执行完赋值语句后函数返回对象会析构,所以后续执行会报错 |
2份:原数据、函数返回值 |
非引用 |
非引用 |
通过变量操作的是被赋值的变量 |
3份:原数据、函数返回值、被赋值变量 |
上面我们说到Employee和Database之间是聚合关系,下面我们给出他们的类图:
// by StarUML
(完)
文档信息
·版权声明:自由转载-非商用-非衍生-保持署名 | Creative Commons BY-NC-ND 3.0
·博客地址:http://www.cnblogs.com/unixfy
·博客作者:unixfy
·作者邮箱:goonyangxiaofang(AT)163.com
·如果你觉得本博文的内容对你有价值,欢迎对博主 小额赞助支持