CSE2305 - Object-Oriented Software Engineering
Assessment

 

Assignment 3: solutions


This assignment was due Friday, 22 September 2006.
Total marks: 50.
Contribution to final mark: 5%.

Synopsis


Question 1

[50 marks]

Develop a design for Pirate Pete's Ship Shop.

NOTE: There is no "right" answer... but some answers will be better than others! Here are some thoughts to inform your own thinking.

* Greg Paperin has kindly provided detail of his possible solution to this assignment.

* Ben Porter has also kindly provided detail of his possible solution to this assignment.

The first part of developing a design is to look for possible classifications from which classes and objects can be discovered. Most of the items stocked by the shop have a lot in common, so we can devise a base level abstraction that represents items that it rents. We'll call this class StockItem. More specialised classes will inherit from this base class, such as ships, parrots, cannons and sails. (The diagram below has been coloured for clarity. You don't have to colour code your own diagrams.)

Class diagram showing key classes of PublishedItem, Book, Serial and Newspaper

StockItem represents the base level abstraction. Notice how only the required methods are exposed in its public interface. We assume that classes like string, Percent and Price are value objects (see Lecture Topic 17 for details). We can use the standard library string class. Percentage and Price could be typedef'd to floats as a first step.

Whilst Cannons and Sails are both associated with all Ships (in my interpretation of the situation), each Ship type was associated independently with its fittings to show clearly the different numbers of Sails and Cannons a particular Ship type can mount. This independent association with different Ship types (cf. Parrot class below) makes the diagram slightly misleading in that it may appear that a particular cannon or sail may be on board 1 Galleon, 1 Schooner AND 1 Canoe simultaneously. To indicate that this is not the case, the relationship "mounts" is noted to be "mutually exclusive" on the diagram.

A Parrot may be associated directly with a ship since the way I interpretted Pirate Pete's specification any ship (regardless of type) may have only single parrot (or not - it might fly away in the heat of battle or it may be fed to the sharks for entertainment).

The Print function of StockItem and its sub-classes is a good example of a polymorphic function – what it does depends on type. For example, if we are printing a Ship object (or something derived from it) the code would be something like this:

ostream& GalleonShip::Print(ostream& s) const
{
	s << getItemType() << ": " << shipName << endl;
	s << "Guns mounted: " << numberOfCannons<< endl;
	s << "Sails on board:" << numberOfSails<< endl;
	s << "Is a Parrot fluttering around?" << HasParrot() << endl;
	s << "Weekly rental price: " << WeeklyRentalPrice() << endl;
    s << "Deposit required: " << DepositPrice() << endl;
	return s;
}

Sail and Cannon would define a Print function with slightly different behaviour. The specific Print functions for the different types of ship could be redefined to print something specific for each ship class. In this instance, such a refinement might not be necessary.

Looking more closley at the Price type, it may become important to make Price a class in its own right (to aid with expanded options such as rounding, change, pretty printing, currency conversion, etc.). Price has been expanded in the diagram below for this reason (it is still a value object however).

Class diagram showing the Price class

A number of classes so far need to define methods to read from a stream, write to a stream and print to a stream. The read/write methods are for saving and loading objects to a stream (a serialisation mechanim) – something that forms part of a persistence mechanism. The Print method is used to print the object in a human readable format (which can be used when printing search matches for example). Because this appears in many classes it makes sense to factorise these methods into a separate class and get all the necessary classes to inherit from this class. As we'll need to input object information from the user, we could also define a get method, that reads object state in from the user (i.e. prompts to enter values like a ship's name). The base class, Streamable, contains only pure virtual functions (defining an interface but no implementation – that is left to subclasses). From Streamable's point of view all we know is that the object can be read, written and printed to a supplied stream. The getObject method is used to return an object read from a stream - this will be required to stream StockItem and its subclasses from files. Please see Stroustrup section 25.4.1 for more details.

Class diagram showing Streamable mixin class and subclasses

This type of class is known as a mixin (or property) class. It represents a "uses a" rather than an "is a" relationship, even though it uses inheritance (usually multiple inheritance).

The next stage is the database component of the system. We need a database of StockItems. We need to add and delete, search and rent StockItems. We also need to be able to move them between a "wharf" and the "sea". There are many possible solutions. We could use the List class from assignment 1 or the associative Array class from assignment 2, with the key type a string or UniqueID and the data a pointer to a StockItem. We can also use the idea of genericity and develop a generic "database" class. This will effectively be a wrapper class that can wrap around an STL container class.

Whether or not a specific item is "at sea" or "at wharf" could be represented by an enumerated type stored within each StockItem that is toggled when a ship is rented out from AtWharf to AtSea (and vice versa when the ship is returned). Alternatively, there could be separate containers within the Shop: one storing items at the wharf, the other storing items at sea. I prefer this second approach as I do not wish to add any value to a StockItem that should really be independent of StockItems. Its location is (I think) such a value. The enumerated type would also need to be updated if Pete bought a new wharf to accomodate a new position for his goods... something that would be cumbersome and error-prone. So here is one possible solution...

 

Above we have a Shop that has independent container classes Sea and Wharf Stock that store objects (one object for each instance of a StockItem) according to their position. These containers are created and destroyed with the Shop, hence the specification of a composition relationship. Now there is one catch here... when a StockItem is rented out it will move from WharfStock, to SeaStock.

Where does the return date for the item get stored? It could be stored in each StockItem. Alternatively, since the return date is only an attribute of SeaStock-contained StockItems, SeaStock could actually be a container for pairs of Date and StockItem objects. A Date object is therefore associated with each StockItem in the SeaStock container. it would also be possible to order the SeaStock list according to return date of the objects it stores. This would ensure that checking the list for overdue items would be faster than if the list was unordered.

How do we know how many of a particular type of StockItem are stored (for example) at the Wharf? In the above solution no value is maintained that keeps track of the number of StockItems or their type at each location. Such a variable could be added at various places: A counter could be kept in the WharfStock and SeaStock objects for each object type stored. A static counter could be kept in each StockItem sub-class keeping track of instances of that class (this could keep track of whether the instances were at Sea or at the Wharf only if each object also stored this information (see above). Alternatively, I take the less rapid but simpler approach of scanning each list and counting up the instances of an object (checked by asking them to return their ItemType string). This would be tedious if Pete had a lot of stock and a running total would need to be implemented that was maintained when stock moved between locations or was added and deleted from the Shop.

...further diagrams and information will be added here shortly...

 


This material is part of the CSE2305 - Object-Oriented Software Engineering course.
Copyright © Alan Dorin & Jon McCormack, 2004-2006. All rights reserved.

Last Modified: October 10, 2006