/* Finding a Common Abstraction Motto: Concentrate common abstractions in a base class. The class interfaces of Card and Monitor are similar: Both have price() and name() as pure virtual functions. The difference is that class Card has an additional virtual function: rebate(). Studying the similarities and differences between these classes will clarify their relationships and lead to a better program. Card and Monitor are similar, but they are not formally related in the inheritance hierarchy. Both Card and Monitor have price() and name() memberfunctions. They are both computer components. It makes mor esense to formalize that common abstraction in a further base class called: Component. This makes the semantic of a computer explicitelly defined with the help of C++ language tools. */ #include <iostream> using namespace std; enum CARD {CDROM, TAPE, NETWORK }; enum MONITOR { MONO, COLOR }; class Component { public: virtual int price() = 0; virtual char *name() = 0; virtual int rebate(); int netPrice(); }; /* Although Component adds another class to the program, it unifies Card and Monitor by identifying a common base abstraction. With the addition of Component, the program better models the program domain. As you can read from the first implementation a card may have a rebate but a Monitor object may not. Is the distintion intentional, or merely accidental? It is better to chose a general approximation here, therefore we suppose that a Component may have a rebate. We express this to declare rebate() as a member of Component. */ int Component::rebate() { return 0; } /* Although price() and name() in Component are pure virtual functions, Component::rebate() is not. There is no meaningful default default implementation of price() and name() that the base class might use - that information must be specified by a derived class before an object may be instatiated. In contrast, a rebate of zero is a sound default implementation to use in a base class. */ class Card : public Component { public: virtual int price() = 0; virtual char *name() = 0; virtual int rebate(); }; class Monitor : public Component { public: virtual int price() = 0; virtual char *name() = 0; }; class Network : public Card { public: int price(); char *name(); }; class Tape : public Card { public: int price(); char *name(); }; class CDRom : public Card { public: int price(); char *name(); int rebate(); }; class Color : public Monitor { public: int price(); char *name(); }; class Monochrome : public Monitor { public: int price(); char *name(); }; int Card::rebate() { return 45; } int Network::price() { return 600; } char *Network::name() { return "Network"; } int CDRom::price() { return 1500; } char *CDRom::name() { return "CDRom"; } int CDRom::rebate() { return 135; } int Tape::price() { return 1000; } char *Tape::name() { return "Tape"; } int Color::price() { return 1500; } char *Color::name() { return "Color"; } int Monochrome::price() { return 500; } char *Monochrome::name() { return "Mono"; } class Computer { public: Computer( CARD, MONITOR ); ~Computer(); int netPrice(); void print(); private: Card *card; Monitor *mon; }; Computer::Computer( CARD c, MONITOR m ) { switch( c ) { case NETWORK: card = new Network; break; case CDROM: card = new CDRom; break; case TAPE: card = new Tape; break; } switch( m ) { case MONO: mon = new Monochrome; break; case COLOR: mon = new Color; break; } } Computer::~Computer() { delete card; delete mon; } /* Unification of the base abstractions (creating the common base class Component permits a simplification of the pricing. Both Card and Monitor have a rebate, so we can implement netPrice() in Component: */ int Component::netPrice() { return price() - rebate(); } /* As a consequece we can drastically simplify the netPrice() of Computer. It is the sum of netPrice()-es of the Components. */ int Computer::netPrice() { // was: return mon->price() + card->price() - card->rebate(); return mon->netPrice() + card->netPrice(); } void Computer::print() { cout << "Configuration = " << card->name() << ", " << mon->name() << ", net price = " << netPrice() << endl; } int main() { Computer nm( NETWORK, MONO ); Computer cm( CDROM, MONO ); Computer tm( TAPE, MONO ); Computer nc( NETWORK, COLOR ); Computer cc( CDROM, COLOR ); Computer tc( TAPE, COLOR ); nm.print(); cm.print(); tm.print(); nc.print(); cc.print(); tc.print(); return 0; }