/** * 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. *

*
Author:
*
Dung X. Nguyen
*
 
*
Last Revised:
*
Sept. 08, 1999
*
*

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 this Pizza 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); } }