Listing 2: Implements design 3

// design3.cpp: Implements Alistair's 3rd CoffeeMachine Design

// NOTE: This version doesn't use std::string because of
//       a problem with the <sstream> header in today's
//       compilers (it doesn't eat the newline).
//       Member functions are defined in situ to save
//       space.

//       For simplicity, this implementation zeroes-out the
//       credit after each drink is dispensed (see returnCoins()).

#include <stdio.h>
#include <string.h>
#include <assert.h>

// We make Selection a class:
// Provides conversions to and from ints and strings.
class Selection
{
public:
    enum {BLACK, WHITE, SWEET, BOTH, BOUILLION, NUM_SELECT};
    Selection(int c)
    {
        assert(0 <= c && c < NUM_SELECT);
        choice = c;
    }
    Selection(const char* s)
    {
        for (int i = 0; i < NUM_SELECT; ++i)
            if (strcmp(text[i], s) == 0)
            {
                choice = i;
                return;
            }
        throw "Selection: bad action";
    }
    const char* toString() const {return text[choice];}
    int priceOf() const {return price[choice];}
    operator int() const {return choice;}

private:
    int choice;
    static int price[NUM_SELECT];
    static const char* text[NUM_SELECT];
};

// Static data for Selection class:
int Selection::price[Selection::NUM_SELECT] = {35,35,35,35,25};
const char* Selection::text[Selection::NUM_SELECT] =
{
    "black", "white", "sweet", "both", "boullion"
};

// CashBox class:
// Tracks the amount of credit.
class CashBox
{
public:
    CashBox() {credit = 0;}
    void deposit(int amount)
    {
        credit += amount;
        printf("\tCashBox: Depositing %d cents.",amount);
        printf("\tYou now have %d cents credit.\n",credit);
    }
    void returnCoins()
    {
        printf("\tCashBox: Returning %d cents\n",credit);
        credit = 0;
    }
    bool haveYou(int amount) const {return credit >= amount;}
    void deduct(int amount)
    {
        credit -= amount;
        returnCoins();
    }

private:
    int credit;
};

// Mixer class:
// Doesn't do much!
class Mixer
{
public:
    void make(const Selection& s)
    {
        printf("\tMixer: Making %s\n", s.toString());
    }
};

// Selector class:
// Checks credit; Dispenses product.
class Selector
{
public:
    Selector(CashBox* pC, Mixer* pM)
    {
        pCashBox = pC;
        pMixer = pM;
    }
    void select(const Selection& s)
    {
        int amount = s.priceOf();
        if (pCashBox->haveYou(amount))
        {
            pMixer->make(s);
            pCashBox->deduct(amount);
        }
        else
            puts("\tSelector: Insufficient funds");
    }

private:
    CashBox* pCashBox;
    Mixer* pMixer;
};

// CoffeeMachine class:
// Owns CashBox, Mixer, and Selector.
class CoffeeMachine
{
public:
    CoffeeMachine()
    {
        pCashBox = new CashBox;
        pMixer = new Mixer;
        pSelector = new Selector(pCashBox, pMixer);
    }
    bool doOneAction()
    {
        // Reads commands and executes them.
        char line[16];
        if (gets(line))
        {
            char action[7];
            sscanf(line, "%s", action);
            if (strcmp(action, "insert") == 0)
            {
                int value;
                sscanf(line, "%*s %d", &value);
                pCashBox->deposit(value);
            }
            else if (strcmp(action,"select") == 0)
            {
                char choice[9];
                sscanf(line, "%*s %s", choice);
                pSelector->select(choice);
            }
            else if (strcmp(action,"quit") == 0)
                return false;
            return true;
        }
        else
            return false;
    }

private:
    CashBox* pCashBox;
    Mixer* pMixer;
    Selector* pSelector;
};

// Test program
main()
{
    try
    {
        CoffeeMachine cm;
        while (cm.doOneAction())
            ;
    }
    catch (const char* s)
    {
        puts(s);
    }
    return 0;
}

/* Input:
insert 25
insert 25
select white
insert 50
select boullion
quit
*/

/* Output:
    CashBox: Depositing 25 cents.    You now have 25 cents credit.
    CashBox: Depositing 25 cents.    You now have 50 cents credit.
    Mixer: Making white
    CashBox: Returning 15 cents
    CashBox: Depositing 50 cents.    You now have 50 cents credit.
    Mixer: Making boullion
    CashBox: Returning 25 cents
*/
//End of File