/** * The best little pizza house in Texas. *
Pizza Mania is having a special on the same kind of pizza (i.e. same thickness and same * ingredients). The special comes in two shapes: rectangular (2" by 4") for $4.49 * and circular (5" in diameter) for $4.69. Which one is the better deal? Write a * program to solve this problem. Why do we want to write a program to solve something as * simple as this one anyway?
*I model the "better deal" concept by comparing the ratio price/area.
*OOP Principle No. 0: Objects are the only things that can perform * computations.
*I design a Pizza
object that can tell me its price and its area. The
* algorithm to compute an area depends on the shape of the Pizza
. As such, the Pizza
's
* shape is a "variant".
OOP Principle No. 1: Encapsulate all related variants into an "abstract * class".
*I create AShape, an abstract class, to represent the
* union of all possible shapes, each with its own way of computing its area. Classes Circle and Rectangle, for
* examples, are concrete variants of AShape. This is an
* example of what we call the union pattern. How does a Pizza
object
* computes its area?
OOP Principle No. 2: Program to the (abstract) interface.
*A Pizza
object maintains a reference to an abstract AShape object, which, at run time, should be an instance of a
* specific concrete subclasses of AShape. For this reason, AShape is said to be polymorphic. At
* construction time, we hand a Pizza
object its price and a concrete AShape instance. The Pizza
object stores
* its price and maintains a reference to the given AShape
* instance. The Pizza
object will forward all requests to compute its
* area to its AShape reference. It is important to
* realize that the Pizza
object does not know (and does not care
* about) what kind of concrete shape its AShape reference
* is. This has the effect of reducing the "coupling" between the Pizza
* class and the concrete subclasses of AShape. There
* is no conditional statement to check for the specific type of shape for the Pizza
* object to compute its area. This has the effect of reducing code complexity.
* This a design pattern called the strategy pattern.
In general, the strategy pattern consists of a union pattern of strategies, and
* a client class, called the context, that contains a reference to the abstract
* strategy in the union. In our Pizza example, the context is the Pizza
class,
* and the abstract AShape plays the role of the (abstract)
* strategy. See the GoF's book for more details.
*
Copyright 1999 by Dung X. Nguyen - All rights reserved.
*/ public class Pizza { private double _dPrice; /** * Knows how to compute its area. * @SBGen Variable (,,,64) */ private AShape _shape; /** * Initializes thisPizza
to a given price and a given concrete shape.
* @param dPrice selling price, >= 0.
* @param shape a concrete shape, != null.
* @exception IllegalArgumentException, if params do not satisfy preconditions.
*/
public Pizza(double dPrice, AShape shape)
{
if (dPrice < 0 || null == shape)
{
throw new IllegalArgumentException ("Pizza.Pizza (price, shape): price < 0) or shape == null");
}
_dPrice = dPrice;
_shape = shape;
}
/**
* @return this Pizza's price in US$.
*/
public double dPrice ()
{
return _dPrice;
}
/**
* Delegates call to the strategy to compute the area.
* @return this Pizza's area.
*/
public double dArea ()
{
return _shape.dArea ();
}
/**
* Overrides method inherited from Object, and uses the strategy to get part of the string.
* @return a String representation of this Pizza.
*/
public String toString()
{
return ("Pizza Special: " + _shape.toString () + " All for $" + _dPrice);
}
}