2010-03-31 4 views
4

Pour une affectation, j'ai créé un programme C++ simple qui utilise une superclasse (Student) et deux sous-classes (CourseStudent et ResearchStudent) pour stocker une liste d'étudiants et imprimer leurs détails, avec différents détails montrés pour les deux différents types d'étudiants (en utilisant l'annulation de la méthode display() de Student).Encapsulation d'une entrée utilisateur de données pour une classe

Ma question est de savoir comment le programme recueille l'entrée de l'utilisateur des choses comme le nom de l'étudiant, numéro d'identification, l'unité et l'information des frais (pour un étudiant en cours) et l'information de recherche (pour les étudiants de recherche):

Mon la mise en œuvre a pour but de solliciter l'entrée de l'utilisateur et la collecte de cette entrée est gérée dans les classes elles-mêmes. Le raisonnement derrière cela était que chaque classe sait de quel type d'entrée il a besoin, donc il est logique pour moi de savoir comment le demander (donné un ostream à travers lequel demander et un istream pour recueillir l'entrée de). Mon conférencier dit que les suggestions et les commentaires devraient tous être traités dans le programme principal, ce qui me semble un peu plus compliqué, et il serait plus difficile d'étendre le programme pour gérer différents types d'étudiants. Je considère, en guise de compromis, de créer une classe d'assistance qui gère l'invite et la collecte de l'entrée utilisateur pour chaque type de Student, qui pourrait ensuite être appelée par le programme principal. L'avantage de ceci serait que les classes d'étudiants n'en ont pas autant (elles sont donc plus propres), mais elles peuvent aussi être groupées avec les classes auxiliaires si la fonctionnalité d'entrée est requise. Cela signifie également que plus de classes de Student pourraient être ajoutées sans avoir à apporter de changements majeurs au programme principal, tant que des classes auxiliaires sont fournies pour ces nouvelles classes. De plus, la classe d'assistance pourrait être permutée pour une version en langue alternative sans avoir à apporter de modifications à la classe elle-même.

Quels sont les principaux avantages et inconvénients des trois différentes options d'entrée utilisateur (entièrement encapsulé, classe d'assistance ou dans le programme principal)?

+0

Lit un peu la séparation MVC (Model-View-Controller). Dans votre cas, les classes sont les modèles et la méthode principale (ou la classe d'aide) lisant l'entrée serait le contrôleur. – vladr

+0

J'ai entendu parler de l'architecture MVC, je suppose que c'est le moment de prendre le temps d'apprendre et de l'appliquer. Dans ce cas, la partie 'View' est gérée par la méthode display() de la classe Student (et des sous-classes), ainsi que par la méthode principale qui gère les options de menu et autres. Serait-il plus approprié d'avoir une classe de spectateur qui invite l'étudiant pour ses détails et les affiche, ou est-ce une séparation trop artificielle (ou tout simplement pas nécessaire pour un si petit projet)? –

Répondre

1

Comme mentionné par scv, il est normalement préférable de découpler la présentation (vue) de la structure interne (modèle).

Ici vous avez un cas typique:

  • la classe Student, racine d'une hiérarchie de modèle
  • la classe Displayer, racine d'une autre hiérarchie indépendante

Le problème avec l'affichage est qu'il varie en fonction de deux éléments, ce qui nécessite un système de double dispatch (en utilisant le virtuel).

Ceci est traditionnellement résolu en utilisant le Visitor Pattern.

Vérifions les classes de base d'abord:

// 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; 
}; 

Et maintenant, nous allons mettre en œuvre quelques-uns:

// 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) { } 

Comme vous pouvez le voir, le plus dur est que si je veux ajouter un nouveau dérivé classe de Student, alors je dois ajouter une nouvelle méthode virtual dans Displayer et le remplacer dans chaque classe dérivée de Displayer ... mais sinon, cela fonctionne très bien. L'avantage est que la logique d'affichage est maintenant découplée du modèle, ainsi nous pouvons ajouter une nouvelle logique d'affichage sans jamais toucher notre modèle.

1

Je pense que ce que votre enseignant voulait dire était "ne le mettez pas dans les classes d'étudiants". Comme Vlad l'a mentionné, les modèles seraient les classes d'étudiants. La vue ne devrait pas être dans les classes d'étudiants. L'idée est que les classes d'étudiants doivent stocker des informations structurelles sur ces objets. La façon dont ces données sont présentées dépend des choses qui utilisent la classe. Si vous deviez, par exemple, utiliser ces classes ultérieurement pour une application console et une application graphique, vous ne voudriez pas avoir le code d'affichage dans ces classes. Cela devrait vraiment être à l'application en utilisant les classes.

La vue/contrôleur serait dans la classe auxiliaire ou dans le programme principal. Être dans le programme principal ne signifie pas qu'il doit être désordonné. Vous pourriez avoir beaucoup de fonctions pour rendre le main() beau et propre, mais la même chose serait vraie si vous l'écrivez dans une classe d'aide. Vous aurez toutes ces fonctions et peut-être un peu plus. Ce que je suggérerais, c'est que si c'est un petit exercice, n'ajoutez pas la classe d'aide à moins que vous n'ayez déjà une idée claire de ce que serait cette classe, ou si vous avez le temps de réfléchir .

+0

Ajout de la classe d'assistance est assez simple - j'ai déjà toutes les fonctions pour cela, donc il s'agit principalement de changer les références afin qu'ils pointent vers la classe d'aide au lieu de la classe des étudiants, et peaufiner. L'affectation spécifie que l'étudiant doit avoir une fonction display() qui est remplacée dans les sous-classes, donc je vais garder display() dans la classe Student, mais je reconnais que ce n'est pas idéal. Pour le faire plus correctement, devrais-je créer une classe d'aide pour l'étudiant qui gère l'affichage, et étendre cette classe d'assistance pour chaque sous-classe afin que je puisse toujours passer outre? –

1

Bien que je sois génétiquement sceptique envers mes conseillers, je pense que votre conseiller a un argument valable ici.

Il est peut-être trop simpliste de réaliser à quel point l'insertion de cin/scanf dans les classes est importante. Mais imaginez cela, votre classe d'étudiants forme le back-end d'un code avec une interface graphique et les données proviennent de toutes sortes de choses - des boutons radio pour le genre, des listes déroulantes pour le groupe d'âge et ainsi de suite. Vous ne devriez vraiment pas mettre tout cela dans votre classe d'étudiants. Avoir un «visualiseur» ou une classe d'aide qui remplit les aides aux étudiants. Je suggère d'avoir une classe chacun en fonction du type de vue. Vous pouvez le faire dans Main, mais avoir des classes de visionneuses séparées vous aidera à réutiliser le code.

Arpan

+0

J'ai depuis longtemps soumis ce projet, et comme il s'est avéré que j'ai fait exactement ce que vous avez suggéré ici. +1 parce que je pensais que c'était une bonne idée et que j'avais le même genre de raisonnement. –

Questions connexes