next up previous
Next: Final version (Value versus Up: Vehicles and Garages Previous: 2nd version (Consistency)

3rd version (Coupling)

The inheritance hierarcy in this program is sound. Both Car and Truck are specialization of the base class Vehicle. Class Garage manages cars and truck uniformly with respect to the base class interface.

The public inheritance establishes valid "is a kind of" relationships between the base class and the derived classes. Other part of the program can deal with Car and Truck objects knowing only that they are at least Vehicle objects and they react to the interface established by the public members of Vehicle.

Although the inheritance is valid, the detailed distribution of code between the base and derived classes can be improved. To make a better version from the example, try to answer the following questions:

The common properties of all vehicles are a license plate number and the ability to identify themselves. These properties are captured in the plate base class data member, and virtual member fuction identify().

Vhat is the difference between a Car and a Truck? The only difference is the string "car" or "truck" printed by identify(). In other words, truck and car differ only in value not in their behaviour.

The similarity between Car::identify() and Truck::identify() is telling. In the following, we migrate common behaviour - represented by the identify() function - to the base class.

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

class Vehicle
{
public:
    Vehicle() { plate = 0; }
    Vehicle(char *p)
    {
        plate = new char[strlen(p)+1];
        strcpy(plate, p);
    }
    virtual ~Vehicle() { delete [] plate; }
    void identify()	
    { 
	char *p = plate ? plate : "none";
	printf( "%s with plate %s\n", group(), p);
    }
protected:
	virtual char *group() = 0;

private:
    char   *plate;
};

The virtual behaviour identify() has been replaced by the virtual behaviour of group(). In fact, group() itselfmay be replaced with a data member. Plate member has been moved from the protected area to private.

Car and Vehicle has been also modified accordingly to the changes at Vehicle.

class Car : public Vehicle
{
public:
    Car() : Vehicle() { }
    Car(char *p) : Vehicle(p) { };

private:
	char *group()  { return "car"; }
};

class Truck : public Vehicle
{
public:
    Truck() : Vehicle() { }
    Truck(char *p) : Vehicle(p) { };

private:
	char *group()  { return "truck"; }
};

class Garage
{
public:
    Garage(int max);
   ~Garage();

    int       accept(Vehicle*);
    Vehicle  *release(int bay);
    void      listVehicles();
private:
    int	      maxVehicles;
    Vehicle **parked;
};

Garage::Garage(int max)
{
    maxVehicles = max;
    parked = new Vehicle*[maxVehicles];
    for( int bay = 0; bay < maxVehicles; ++bay ) 
    {
        parked[bay] = 0;
    }
}

Garage::~Garage()
{
    delete [] parked;
}

int Garage::accept(Vehicle *veh)
{
    for( int bay = 0; bay < maxVehicles; ++bay )
	if( !parked[bay] )
	{
	    parked[bay] = veh;
	    return( bay );
	}
    return( -1 );	// No free bay
}

Vehicle	*Garage::release(int bay)
{
    if( bay < 0 || bay > maxVehicles )
        return 0;
    Vehicle *veh = parked[bay];
    parked[bay] = 0;
    return( veh );
}

void	Garage::listVehicles()
{
    for( int bay = 0; bay < maxVehicles; ++bay )
	if( parked[bay] )
	{
	    printf("Vehicle in bay %d is: ", bay);
	    parked[bay]->identify();
	}
}

Car c1("AAA100");
Car c2("BBB200");
Car c3("CCC300");

Truck t1("TTT999");
Truck t2("SSS888");
Truck t3("UUU777");


int main( )
{
    Garage Park(14);

    Park.accept(&c1);
    int t2bay = Park.accept(&t2);
    Park.accept(&c3);
    Park.accept(&t2);

    Park.release(t2bay);

    Park.listVehicles();

    return 0;
}


next up previous
Next: Final version (Value versus Up: Vehicles and Garages Previous: 2nd version (Consistency)
Porkoláb Zoltán 2001-09-03