Lab 7-2: Coding the UML spcification
   ctor and dtor practicing II

 
實習目標 練習依照 UML 的類別圖實作類別, 製作類別間靜態的連結, 練習使用建構元, 解構元與檔案串流
 
步驟一 這次實習接續實習 6-2, 繼續完成還沒有完成的類別, 並且探討一些比較複雜的參考關係

請參考下面 UML 的類別圖, 製作所需要的類別

這是一個描述類似海洋大學這樣子的組織的系統, 主要針對所有開設的課程來描述, 首先學校裡面有好幾個學院, 每一個學院裡面又有不同的系所, 每一個系所每個學期都會開設許多的課程, 系所也有許多的老師, 每個課程應該都有一個老師在負責授課。

步驟二 請繼續定義其它相關類別包括 Institute, Course, 以及 Teacher, 其中的資料部份先用最直覺的定義 (這些定義因為是類別內的實作部份, 將來如果需要更改是很容易更動的), 例如 m_name, m_ID 可以用 string, year 和 semester, 都可以先用 int 來定義, 所有的資料基本上都是 private 的
步驟三 接下來要繼續建構類別間的關係, 每一個學院裡包括多個獨立研究所, 所以在 College 類別內需要增加 vector<Institute *> m_institutes; 在這裡我還是使用 vector 樣版, 雖然會使得程式碼 (exe 檔案) 比較大, 但是有關這一類效率的問題是可以留到最後再處理的。

各個研究所和學系裡有多個老師, 也開設多個課程, 所以在 Department 和 Institute 裡加上 vector<Teacher *> m_teachers; 和 vector<Course *> m_courses; 兩個資料成員, 來實作 Department (Institute) 和 Teacher 的關係以及 Department (Institute) 和 Course 的關係,

請注意目前所實作的關係都是單向的, 比方說由一個 Department 類別的物件可以循著 m_teachers 到達任何一個系上的老師物件, 但是倒過來並無法到達, 也就是由一個老師物件無法找到他隸屬於哪一個系所, 這需要依照不同應用程式的需求來設計, 作雙向的連結常常可以增加應用程式的反應速度, 把運算時間分散到每一次維護雙向連結的程式碼上面, 但是缺點也就在於雙向連結程式碼維護的複雜度, 如果要作雙向的連結的話, 在 C++ 中可以用一個指標來實作。

在 Course 類別中會有一個任課老師的欄位, 請先用 string 類別的資料成員來實作, 這樣子實作可能會遇見姓名重複, 以及效率不彰的問題, 不過我們等到比較後面一點再來討論這個問題

在 Teacher 類別裡會有連接到多個課程的連結, 可以用 vector<Course *> m_courses; 來實作, 不過請注意在下一個步驟中課程的資料是依照系所來排列的, 並不是依照任課教師來排列的, 同時課程是組合成系所物件的重要物件, 也是由系所物件來產生的, 並不是由任課教師來產生的。

步驟四 現在資料比上一個實習要複雜一點, 我們把資料放在 ntou2.txt 檔案內, 部份資料節錄如下:
    海洋大學             // 學校名稱
    2                    // 學院個數
    生命與資源科學院     // 第一個學院名稱
    2                    // 此學院內學系個數
    食品科學系           // 第一個學系名稱
    2                    // 此學系內教師人數
    王大明               // 第一個教師姓名
    張三                 // 第二個教師姓名
    3                    // 此學系開設課程總數
    食品科學導論         // 第一門課程名稱
    92001                //   課程代號
    92                   //   學年度
    1                    //   學期
    王大明               //   開課教師
    食品營養             // 第二門課程名稱
    92002                // ...
    92
    1
    王大明
    水產食品
    91001
    91
    2
    張三
    ...
    1                    // 此學院內獨立研究所數目
    生物科技研究所       // 第一個研究所名稱
    ...
此檔案內每一筆資料所代表意義以及基本的讀取方法請參考 testRead2.cpp, 以及 testRead2.exe (請下載後執行)

請設計各個建構元函式, 依據此資料檔案內容建構各個物件, 例如: College 類別的建構元如下:

    College::College(ifstream &infile)
    {
        char buf[50];
        getline(infile, m_name, '\n'); // string m_name; 學院名稱

        int numberOfDepartments;
        infile >> numberOfDepartments;
        infile.getline(buf, 50, '\n');

        int iDept;
        for (iDept=0; iDept<numberOfDepartments; iDept++)
            m_departments.push_back(new Department(infile)); 

        int numberOfInstitutes;
        infile >> numberOfInstitutes;
        infile.getline(buf, 50, '\n');

        int iInst;
        for (iInst=0; iInst<numberOfInstitutes; iInst++)
            m_institutes.push_back(new Institute(infile)); 
    }
請注意, 由於在建構元中產生了這些 Department 物件和 Institute 物件, 所以在解構元中需要把它們釋放掉, 才不會有記憶體的遺失
步驟五 我們也在新的類別裡加上 print(ostream &os) 來列印各個類別內的資料內容, 如此可以在 University 類別中寫一個 static 的成員函式來測試結果:
    static void University::unitTest()
    {
        ifstream infile("ntou2.txt");
        if (!infile)
            std::cout << "Cannot open ntou2.txt!!\n";
        else
        {
            University ntou(infile);
            ntou.print(std::cout);
        }
    }
範例執行程式 campusCourse2.exe (請下載後執行)
步驟六 接下來可以製作簡單的 UI 來查詢教師授課清單, 我們可以在 University 類別中製作一個 query() 的成員函式來負責使用者界面, 例如:
    bool University::query()
    {
        using namespace std;
        int option;
        char buf[50];
    
        cout << "   1. 結束本程式\n";
        cout << "   2. 查詢教師基本資料\n";
        cout << "   3. 查詢課程基本資料\n";
        cout << "   4. 查詢教師開授課程\n";
        cout << "   5. 查詢系所課程\n";
        cout << "   6. 查詢系所教師\n";
        cout << "   7. 新增課程\n";
        cout << "   8. 新增教師\n";
        cout << "請選擇功能 : ";
        cin >> option;
        cin.getline(buf, 50, '\n');
    
        switch (option)
        {
        case 1:
            return false;
        case 2:
            cout << "請輸入教師姓名: ";
            cin.getline(buf, 50, '\n');
            queryTeacherBasicsByName(string(buf), cout);
            break;
        ...
        };
    }
其中 queryTeacherBasics() 為一個 private 的成員函式, 主要負責轉介這一個查詢教師基本資料的請求到各個 College 物件成員, 這個機制我們在物件導向程式裡稱為委託 (delegation), 其內容如下:
    void University::queryTeacherBasicsByName(string name, ostream &os)
    {
        std::vector<College *>::iterator iter;
        for (iter=m_colleges.begin();
             iter<m_colleges.end();
             iter++)
            (*iter)->queryTeacherBasicsByName(name, os);
    }
大家可以發現這是一個很制式化的函式, 這個函式也使得 College 類別必須提供一個 queryTeacherBasicsByName(string name, ostream &os) 的界面, 依照這樣的程序, 你會發現依序下去 Department, Institute, 以及 Teacher 類別都需要提供類似功能的界面來支援這一項查詢的功能, 最後實體的功能交由 Teacher 類別來完成

在上面的設計裡你會發現我盡量將輸出的串流以參數的方式傳遞, 而不用全域的方式, 這樣子有助於控管程式輸出的管道

建議你在定義各個類別界面的過程中時常地編譯你的程式, 一步一步地完成程式的需求, 有的時候欲速則不達

在各個物件導向的方法論中, 其實各個類別的界面應該要藉由一些圖形輔助在紙上或是透過輔助工具 (CASE tool, 例如 IBM Rose) 來設計, 這個初步練習裡, 我們先用巡迴漸進式 (iterative) 的方式來製作一次, 對於類別界面的定義能夠有更深刻的印象

範例執行程式 campusCourse3.exe (請下載後執行)

步驟七 程式其它相關功能

  1. 各項查詢功能: 教師基本資料, 課程基本資料, 教師開課資料, 學期課程列表

  2. 新增, 修改, 刪除資料功能

  3. 存檔

  4. 學生資料

  5. 學生選課資料
步驟八 請將所完成的 project (去掉 debug/ 資料匣下的所有內容) 壓縮起來儲存在 cyber 上你的帳號內, 後面的實習課程可能需要使用這裡所完成的程式

C++ 物件導向程式設計課程 首頁

製作日期: 03/22/2004 by 丁培毅 (Pei-yih Ting)
E-mail: [email protected] TEL: 02 24622192x6615
海洋大學 電機資訊學院 資訊工程系 Lagoon