The Manager/Worker Idiom Again

Why do I say “the interface” rather than “the interfaces”? Because we're going to implement these classes to give the appearance of a single type of object that can change its behavior; in other words, we're going to use the manager/worker idiom again to implement another type of polymorphic object. This will enable us to write a main program that allows access to an object of any of these types in a uniform manner. Of course, the implementation of the member functions will be somewhat different in each class, to take account of the peculiarities of that class, but the structure of the program will be essentially the same for any number of types once we've made provisions to handle more than one. For this reason, we'll use just the “Basic” and “Music” types in the text; handling other types will be left as an exercise. Figure 11.1 shows the initial HomeItem interface.

Figure 11.1. The initial interface for the HomeItem manager class (code/hmit1.h)
// hmit1.h

class HomeItem
{
friend std::ostream& operator << (std::ostream& os,
  const HomeItem& Item);

friend std::istream& operator >> (std::istream& is, HomeItem& Item);

public:
 HomeItem();
 HomeItem(const HomeItem& Item);
 HomeItem& operator = (const HomeItem& Item);
virtual ~HomeItem();

// Basic: Includes art objects, furniture, jewelry, etc.
  HomeItem(std::string Name, double PurchasePrice,
  long PurchaseDate, std::string Description, std::string Category);
// Music: CDs, LPs, cassettes, etc.
  HomeItem(std::string Name, double PurchasePrice,
  long PurchaseDate, std::string Description, std::string Category,
  std::string Artist, Vec<std::string> Track);

virtual void Write(std::ostream& os);

protected:
 HomeItem(int);

protected:
 HomeItem* m_Worker;
 short m_Count;
};

If you think this looks familiar, you're right. It's almost exactly the same as the polymorphic object version of the StockItem interface we saw in Chapter 10. This is not a coincidence; every polymorphic object interface is going to look very similar to every other one. Why is this?

Similarities and Differences between Polymorphic Objects

They all look alike because the objects of every polymorphic object manager class do very similar things: managing the “real” objects of classes derived from the manager class. The only differences between the interfaces of two polymorphic object types are in the member functions that the user of the polymorphic objects sees. In this case, we don't have a Reorder function as we did in the StockItem class, for the very simple reason that we don't have to figure out how many HomeItem objects to reorder from our distributors.

Before we get into the worker classes for the HomeItem polymorphic object, let's go over the similarities and differences between the StockItem and HomeItem interfaces.

  1. The operators << and >>, as well as the default constructors, copy constructors, assignment operators, and destructors, have the same interfaces in the StockItem class and the HomeItem class except, of course, for their names and the types of their arguments (if applicable). This also applies to the “special” constructor used to prevent an infinite loop during construction of a worker object and to the Write function used to create a displayable and storable version of the data for an object.

  2. The “normal” constructors that create objects for which the initial state is known are the same in these two classes except, of course, for the exact arguments, which depend on the data needed by each object. One point we'll cover later is the use of a Vec as an argument to the second “normal” constructor.

  3. The GetName, GetPrice, and other class-specific member functions of StockItem don't exist in HomeItem because it is a different class with different requirements from those of StockItem.[3]

    [3] As we'll see, HomeItem will eventually have its own version of GetName. Many classes need the ability to retrieve the name of an item; using a function called something like GetName is a fairly common way to handle this requirement.

  4. The member data items for the two classes are the same except, again, for the type of m_Worker, which is a pointer to a HomeItem rather than to a StockItem.

Of course, this class doesn't really do anything by itself; as with all polymorphic objects, we need the worker classes to get the job done. Figure 11.2 shows the interfaces for HomeItemBasic and HomeItemMusic.

Figure 11.2. The initial interface for the HomeItemBasic and HomeItemMusic worker classes (codehmiti1.h)
// hmiti1.h

class HomeItemBasic : public HomeItem
{
public:
 HomeItemBasic();

 HomeItemBasic(std::string Name, double PurchasePrice,
 long PurchaseDate, std::string Description, std::string Category);

virtual void Write(std::ostream& os);

virtual std::string GetType();

protected:
 std::string m_Name;
 double m_PurchasePrice;
 long m_PurchaseDate;
 std::string m_Description;
 std::string m_Category;
};

class HomeItemMusic : public HomeItemBasic
{
public:

 HomeItemMusic(std::string Name, double PurchasePrice,
 long PurchaseDate, std::string Description, std::string Category,
 std::string Artist, Vec<std::string> Track);

virtual void Write(std::ostream& os);

virtual std::string GetType();

protected:
 std::string m_Artist;
 Vec<std::string> m_Track;
};

Susan had a question about having two interface files.

Susan: Why do we need two different interface files again?

Steve: The first one (hmit1.h) is for the user of these classes; the second one (hmiti1.h) is only for our use as class implementers. The user never sees this second interface file, which means that we can change it if we need to without forcing the user to recompile everything.

As we did with the manager classes, let's take a look at the similarities and differences between the HomeItem and StockItem worker classes.

  1. The default constructors, copy constructors, assignment operators, and destructors have the same interfaces in the StockItem worker classes and the HomeItem worker classes except, of course, for their names and the types of their arguments (if applicable). This also applies to the Write function used to create a displayable and storable version of the data for an object. By the way, the destructors are guaranteed to be virtual because the base class destructor is virtual. I've added the virtual keyword to the declaration of the derived class destructors solely for clarity.

  2. The “normal” constructors that create objects for which the initial state is known are the same in all of these classes except, of course, for the exact arguments, which depend on the data needed by each object. Again, we'll go into what it means to have a Vec argument when we cover the implementation of the “normal” constructor for the HomeItemMusic class.

  3. The HomeItem worker classes have a GetType member function that the StockItem classes don't have. The purpose of this function is to allow the proper storage and display of objects of various types. In the StockItem class, we depended on the value of the expiration date (“0” or a real date) to give us this information.

  4. The GetName, GetPrice, and other class-specific member functions of the StockItem worker classes don't exist in the HomeItem worker classes, as explained above.

  5. The member data items for the HomeItem worker classes are as needed for these classes, as with the HomeItem worker classes.

  6. We are using the long data type for the m_PurchaseDate member variable rather than the string data type that we used for a similar field in DatedStockItem.[4]

    [4] See the Glossary for details on the long and double data types.

  7. We are using the double data type for the m_PurchasePrice member variable rather than the short data type that we used for price information in the StockItem classes.

The first of the differences between the StockItem worker classes and the HomeItem worker classes that needs additional explanation is the GetType virtual function first declared in HomeItemBasic. Since I have claimed that all the classes that participate in a polymorphic object implementation must have the same interface (so the user can treat them all in the same way), why am I declaring a new function in one of the worker classes that wasn't present in the base class?

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset