程序最美(寻路)

你还在坚持练习你的技术吗?运动员天天训练,音乐家也会演练更难的曲章。你呢?

雇员记录系统

雇员记录系统

         由于内容来自于《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

posted on 2013-08-18 00:37  unixfy  阅读(613)  评论(0编辑  收藏  举报

导航