2010-03-31 19 views
4

對於一個作業,我做了一個簡單的C++程序,它使用超類(Student)和兩個子類(CourseStudentResearchStudent)來存儲學生列表並打印出詳細信息,針對兩種不同類型的學生所示的不同細節(使用從Student覆蓋display()方法)。封裝一個類的用戶輸入數據

我的問題是關於如何計劃從東西,如學生姓名,身份證號碼,單位和費用信息(爲一個療程學生)收集用戶輸入和研究信息(研究生):

我實現具有對用戶輸入的提示以及收集在類自身內處理的輸入。這背後的原因是每個班級都知道它需要什麼類型的輸入,所以讓我知道如何請求它是有意義的(給定一個ostream通過它詢問並從中收集輸入)。

我的講師說,提示和輸入都應該在主程序中處理,這在我看來似乎有點混亂,並且會使擴展程序來處理不同類型的學生更加棘手。

我正在考慮作爲一種折衷辦法,爲每個類型的Student提供一個輔助類,以處理用戶輸入的提示和收集,然後可以由主程序調用該類。這樣做的好處是學生類沒有那麼多(因此他們更乾淨),但是如果需要輸入功能,他們也可以與幫助類捆綁在一起。這也意味着可以添加更多的Student類,而不必對主程序進行重大更改,只要爲這些新類提供了輔助類。此外,輔助類可以替換爲另一種語言版本,而無需對類本身進行任何更改。

什麼是用戶輸入(全封閉,輔助類或者在主程序)的三個不同的選項的主要優點和缺點?

+0

閱讀MVC(模型 - 視圖 - 控制器)分離的一點。在你的情況下,類是模型,讀取輸入的主要方法(或助手類)將是控制器。 – vladr 2010-04-01 00:02:10

+0

我聽說過MVC架構,我想現在是騰出時間學習和應用它的時候了。 在這種情況下,'View'部分由Student類(和子類)的display()方法處理,以及處理菜單選項等的main方法。有一個提示學生提供詳細信息並顯示它們的觀察器類,或者這是人爲的分離(或者對於這樣一個小型項目不是必需的),會更合適嗎? – 2010-04-01 00:14:39

回答

1

正如scv提到的,它通常是更好的去耦內部結構(模型)呈現(視圖)。

這裏有一個典型案例:

  • Student類,模型層次
  • Displayer類的根,另一個獨立層次的根

與顯示器的問題是它根據兩個要素而變化,這要求雙重調度系統(使用虛擬)。

這是傳統上使用Visitor Pattern解決。

讓我們來看看基類第一:

// student.h 
class Displayer; 

class Student 
{ 
public: 
    virtual ~Student(); 
    virtual void display(Displayer& d) const = 0; // display should not modify the model 
}; 

// displayer.h 
class Student; 
class CourseStudent; 
class ResearchStudent; 

class Displayer 
{ 
public: 
    virtual ~Displayer(); 

    virtual void display(const Student& s) = 0; // default method for students 
               // not strictly necessary 
    virtual void display(const CourseStudent& s) = 0; 
    virtual void display(const ResearchStudent& s) = 0; 
}; 

現在,讓我們來實現一些:

// courseStudent.h 
#include "student.h" 

class CourseStudent: public Student 
{ 
public: 
    virtual void display(Displayer& d) const; 

}; 

// courseStudent.cpp 
#include "courseStudent.h" 
#include "displayer.h" 

// *this has static type CourseStudent 
// so Displayer::display(const CourseStudent&) is invoked 
void CourseStudent::display(Displayer& d) const 
{ 
    d.display(*this); 
} 


// consoleDisplayer.h 
#include "displayer.h" 

class ConsoleDisplayer: public Displayer 
{ 
public: 
    virtual void display(const Student& s) = 0; // default method for students 
               // not strictly necessary 
    virtual void display(const CourseStudent& s) = 0; 
    virtual void display(const ResearchStudent& s) = 0; 
}; 

// consoleDisplayer.cpp 
#include "consoleDisplayer.h" 

#include "student.h" 
#include "courseStudent.h" 
#include "researchStudent.h" 

void ConsoleDisplayer::display(const Student& s) { } 

void ConsoleDisplayer::display(const CourseStudent& s) { } 

void ConsoleDisplayer::display(const ResearchStudent& s) { } 

正如你所看到的,最困難的部分是,如果我想添加一個新的派生那麼我需要在Displayer中添加一個新的virtual方法,並在每個派生類Displayer中重寫它,但除此之外它效果很好。

優點是顯示的邏輯現在與模型分離,因此我們可以添加新的顯示邏輯,而無需觸摸我們的模型。

1

我想你的老師的意思是說「不要把它放在學生班」中。

弗拉德提到模型將是學生課程。這個觀點不應該在學生課堂上。這個想法是,學生課程應該存儲關於這些對象的結構信息。數據如何呈現取決於使用該類的東西。例如,如果您以後將這些類用於控制檯應用程序和GUI應用程序,則不希望在這些類中包含顯示代碼。這應該真的取決於使用這些類的應用程序。

視圖/控制器將在助手類或主程序中。在主程序中並不意味着它必須是混亂的。你可能有很多函數讓main()看起來很乾淨,但如果你把它寫在一個輔助類中,情況也是如此。你將擁有所有這些功能,也許還有更多功能。

我會建議的是,如果這是一個小練習,除非您已經清楚瞭解該課程的具體情況,或者如果您有時間花時間去計算,那麼不要添加輔助類。

+0

添加helper類非常簡單 - 我已經擁有了所有的函數,所以它主要是改變引用,以便它們指向助手類而不是Student類,然後調整。 該賦值指定學生應該有一個在子類中被覆蓋的display()函數,所以我將在Student類中保留display(),但是認識到這不是理想的。爲了以後更好地做到這一點,我是否會爲處理顯示的學生製作助手類,併爲每個子類擴展此助手類,以便我仍然可以覆蓋? – 2010-04-01 01:31:14

1

雖然我對我的顧問基因持懷疑態度,但我認爲你的顧問在這裏有一個有效的觀點。

將cin/scanf放在類中很重要,可能太簡單了。但想象一下,您的學生課程使用GUI形成一些代碼的後端,數據來自各種各樣的事物 - 性別的單選按鈕,年齡組的組合框等等。你真的不應該把這一切都放在你的學生課堂中。

有一個'查看器'或助手類填充學生的幫助。我建議有一個類每個取決於視圖的種類。你可以在main內部完成,但是單獨的查看器類將幫助你重新使用代碼。

Arpan

+0

我早就提交了這個項目,事實證明我確實在你這裏提出了什麼建議。 +1,因爲我認爲這是一個好主意,並且有相同的推理。 – 2010-06-06 02:45:54