Re: Model View Controller basics.

From: Kurt (kurbylogic_at_hotmail.com)
Date: 09/12/04


Date: 12 Sep 2004 07:05:44 -0700

I don't think you need all components in MVC, your model doesn't have
anythigng to observe anyway. We can apply a few other basic patterns
that will help alot to remove the concerns you mentioned. Forgive my
C++ as it has been a few years... I'm only suggesting a few ideas,
I'll leave it up to you to fix the syntax and fill in the blanks.

> Quests and Questions:
> - Remove the menu from the engine.
Why not rename Engine to Menu, a good noun from your domain ;)

Menu menu;
menu.display();
while(!menu.IsDone())
{
   menu.awaitCommand();
}

> - Remove the double code in the ugly switch or try to replace the switch completly (in the engine).

Check into the command pattern:

class Command
{
public:
  virtual void Execute(Menu* pMenu) = 0;
}
class FindByFirstName : Command
{
  virtual void Execute(Menu* pMenu) { pMenu->FindByFirstName() }
}
ExitCommand tells menu to set the isDone flag remember
while(!menu->IsDone()) ...
class ExitCommand
{
  public:
    virtual void Execute(Menu* pMenu) { pMenu->Exit(); }
}
Menu
public:
  void Exit() { isDone = TRUE; }

Add each command to an array in your Menu class
Command[] menuitems
awaitCommand()
{
   int menuindex = 0;
   cin >> menuindex;
   if(menuindex > 0 && menuindex < sizeof(menuitems))
      menuitems[menuindex].Execute();
   else cout << "invalid choice";
}

display might even be simplified to
{
  for(int index = 1; index <= sizeof(menuitems); ++index)
    cout << i << ") " << menuitems[index]->getName();
}

> - The class PhoneBook should only be a simple phone book definition. Hence, the (console) view methods don't belong
> there. Furthermore, there might be more views coming up.
> Once again, typically me. The solution seems to be the MVC patter.
> And exactly this the reason for my presence here.

The presentation can display the entry, in could employ a helper or
translater to format the properties as desired, entry shouldn't know
anything about its presentation, however that doesn't mean it can't
help somewhat, perhaps it could implement a toString method such as
java does, or return a map with name, value properties to display on a
generic output that is too lazy to want or need to care about all the
getters and setters different class types (I've used this trick to
DataBind a DataGrid in ASP.NET to a hashtable for displaying a
business object properties for viewing)

Menu
public:
 void FindByLastName(pMenu)
 {
      cout << "Last name? ";
      cin >> lastName;
      PhoneBookEntry entry = PhnBook.FindByLastName(lastName);
      WriteEntry(entry);
   ( or as I was saying above maybe even a useful generic write of a
map
     you can use to write phonebook entries, address cards, etc.. )
     WriteObjectDescription(entry.getDescription())
 }
  void WriteObjectDescription( map m)
{
   it i = m->getIterator();
   while(it->moveNext()) { cout << i->key; cout << i->value; }
}
Your phone book now contains no presentation logic what so ever it
still performs the data retrevial but no input or output. The
commands still have a dependancy on the menu object, however, these
commands do console specific stuff and also belong as part of the
presentation, notice they delegate the actual finding algo to the
phonebook.

Hope this helps somewhat.

- Kurt

> Thinking in terms of "engines" is typically me. Therefore these two types of problems happens over and over again to me.
> Is there a pattern for these two problems?
> - The class PhoneBook should only be a simple phone book definition. Hence, the (console) view methods don't belong
> there. Furthermore, there might be more views coming up.
> Once again, typically me. The solution seems to be the MVC patter.
> And exactly this the reason for my presence here.

"Val" <valmont_programming@hotmail.com> wrote in message news:<41438d9c$0$62368$5fc3050@dreader2.news.tiscali.nl>...
> What my toy code does is just fetching the first name, last name and the phone number from a file and then stores it in
> a Vector.
> The "engine" (class PhoneBookEng) is responisble for sorting and a toy-like binary search. Currently it is also
> responsible for a console based menu
> so the user can enter who or wich phone number he is looking for. Later more on that.
> The class PhoneBook is just a wrapper for a vector holding the records. BUT, it is also responsible for the console
> view. Bad bad bad.
> The main() function is super simple. I love that.
>
> Okidoky. The fact that the engine also provides a menu ( a console based menu in this case) is also bad. But I am way
> too demotivated to move on with that for now. The reason follows below:
> The fact that class PhoneBook defines the console output is bad. But I can't solve this issue, hence my presence here.
> For now only a console output is relevant. But soon more views will be important.
> Furthermore, the case is jolly ugly. But once again, I am too demotivated to move on with that right now.
>
> In my fantasy, the PhoneBookEng class is the controller. It provides the algorithms. That is the responsibility of that
> class.
> The class Person *might* easely serve as the model for now.
> The class PhoneBook should be just a simple wrapper.
>
> Quests and Questions:
> - Remove the double code in the ugly switch or try to replace the switch completly (in the engine).
> - Remove the menu from the engine.
> Thinking in terms of "engines" is typically me. Therefore these two types of problems happens over and over again to me.
> Is there a pattern for these two problems?
> - The class PhoneBook should only be a simple phone book definition. Hence, the (console) view methods don't belong
> there. Furthermore, there might be more views coming up.
> Once again, typically me. The solution seems to be the MVC patter.
> And exactly this the reason for my presence here.
>
> Code below is complete and working. Notice how I made it only to demonstrate the typical design problems (and therefore
> code uglyness most likely!). Demonstrational purposes is the one and only correct scope. So please do bare with me :)
> The source files can be downloaded from my webspace: http://home.tiscali.nl/~valmont/cpp/downloads/seperateview.zip for
> anyone's conveniance. It also contains the file with names and numbers.
>
> #include "PhoneBookEngine.h"
>
> int main()
> {
> PhoneBkEng PBE;
> return 0;
> }
>
> #ifndef PERSON_H
> #define PERSON_H
>
> #include <iostream>
> #include <string>
> using namespace std;
>
> struct Person
> {
> string fname;
> string lname;
> string tele;
> };
>
> ostream& operator<<(ostream& os, const Person& p)
> {
> os <<p.fname <<" " <<p.lname <<" " <<p.tele;
> return os;
> }
>
> istream& operator>>(istream& is, Person& p)
> {
> is >>p.fname >>p.lname >>p.tele;
> return is;
> }
> #endif //PERSON_H
>
> #ifndef PHONEBKCOMPARATOR_H
> #define PHONEBKCOMPARATOR_H
>
> //Comparators and co. : used by class PhoneBookEng in PhoneBookEngine.h
> #include "Person.h"
> #include <functional>
> #include <string>
> using namespace std;
>
> //Compare functions for std::sort() (passed to 3rd argument).
> bool LessFirstName( const Person& a, const Person& b)
> { return a.fname < b.fname; }
> //The one below works, but I have no clue about its workings :)
> class LessLastname : binary_function<Person, Person, bool>
> {
> public:
> bool operator()(const Person& E1, const Person& E2)
> { return E1.lname<E2.lname; }
> };
>
> bool LessTelephone(const Person& E1, const Person& E2)
> { return E1.tele<E2.tele; }
>
> //Functions for binarySearch() (passed to a function pointer).
> string FirstName(const Person& p)
> { return p.fname; }
> string LastName(const Person& p)
> { return p.lname; }
> string Telephone(const Person& p)
> { return p.tele; }
>
> #endif //PHONEBKCOMPARATOR_H
>
> #ifndef PHONEBOOKENGINE_H
> #define PHONEBOOKENGINE_H
>
> #include "PhoneBook.h"
> #include "PhoneBkComparator.h"
> #include "Person.h"
> #include <algorithm>
> #include <string>
> #include <iterator>
> using namespace std;
>
> //PhoneBkEng: Phonebook engine. Does the sorting, searching and provides a menu
> //to choose what to search for and by which key of person data to sort.
>
> typedef const vector<Person>& VPerson;
> typedef string (*compare)(const Person& p);
>
> class PhoneBkEng
> {
> public: //Typical members
> int showMenu()
> {
> cout << "\nEnter a Selection:\n";
> cout << "0) Exit\n";
> cout << "1) Find Phone number by First Name\n";
> cout << "2) Find Phone number by Last Name\n";
> cout << "3) Find Person by Phone Number\n";
> cout << "4) Show All Records\n";
> cin >> menuchoice;
> return menuchoice;
> }
>
> int binarySearch( VPerson a, const string& x, const compare comp ) const
> {
> int low = 0, high = a.size( ) - 1;
> while( low <= high )
> {
> int mid = ( low + high ) / 2;
> if( comp(a[ mid ]) < x )
> low = mid + 1;
> else if( comp(a[ mid ]) > x )
> high = mid - 1;
> else
> return mid; //Found.
> }
> return -1; //Not found.
> }
>
> void Execute(const int input)
> {
> //Lets quickly test unrelated names and phone numbers.
> //Notice that names are to be entered in UPPERcase only.
> string firstname, lastname, phone;
> firstname = "AMY";
> lastname = "JONES";
> phone = "130-229-3425";
>
> enum {Exit, FindByFirstName, FindByLastName, FindByPhone, ShowAll};
> //Remember, binarySearch returns the index of the item.
> //It is passed straight into showTheRecord(const int Idx ).
> switch(input)
> {
> case Exit: cout << "Exited.\n"; break;
> case FindByFirstName:
> sort(PBook.getPbook().begin(), PBook.getPbook().end(), LessFirstName );
> PBook.showTheRecord(binarySearch(PBook.getPbook(), firstname, FirstName ));
> break;
> case FindByLastName:
> sort(PBook.getPbook().begin(), PBook.getPbook().end(), LessLastname() );
> PBook.showTheRecord(binarySearch(PBook.getPbook(), lastname, LastName));
> break;
> case FindByPhone:
> sort(PBook.getPbook().begin(), PBook.getPbook().end(), LessTelephone);
> PBook.showTheRecord(binarySearch(PBook.getPbook(), phone, Telephone));
> break;
> case ShowAll:
> PBook.displayAll(cout); break;
> default:
> cout << "ERROR, reason: Incorrect Choice\n";
> }
> }
>
> public: //c'tors, d'tors cpy'ctors etc.
> PhoneBkEng() : menuchoice(1)
> {
> while (menuchoice != 0)
> {
> showMenu();
> Execute(menuchoice);
> }
> }
> private:
> int menuchoice;
> PhoneBook PBook;
> };
>
> #endif //PHONEBOOKENGINE_H



Relevant Pages

  • Re: Predicting the Future and Kolmogorov Complexity
    ... Predictability is based on the pattern itself. ... addition to the string. ... For any prediction scheme, there are computable strings that show no ... Out of this hole comes a ~2 cm blue marble followed by a red ...
    (talk.origins)
  • Re: macro for parsing text
    ... SUB will remove from any cell selected the pattern as you described (i.e. ... Dim c As Range ... Dim Temp As String ... Dim colMatches As MatchCollection ...
    (microsoft.public.excel.programming)
  • Re: macro for parsing text
    ... SUB will remove from any cell selected the pattern as you described (i.e. ... Dim c As Range ... Dim Temp As String ... Dim colMatches As MatchCollection ...
    (microsoft.public.excel.programming)
  • Re: Entropy in crystalization: up or down?
    ... such a pattern as "artifact" has exactly the same fundamental basis ... for accepting a certain type of narrow band radiosignal as artifact. ... and *that* is the reason that induction on a data string alone is worthless. ... over and over again, in radiosignals. ...
    (talk.origins)
  • Re: Model View Controller basics.
    ... looking for a pattern asap:) ... The solution seems to be the MVC patter. ... | you can use to write phonebook entries, address cards, etc.. ...
    (comp.object)

Loading