CHAPTER 3 ■ OBJECT BASICS
How can I extend my example to accommodate these changes? Two options immediately present
themselves. First, I could throw all the data into the ShopProduct class. Second, I could split ShopProduct
into two separate classes.
Let’s examine the first approach. Here, I combine CD- and book-related data in a single class:
class ShopProduct {
public $numPages;
public $playLength;
public $title;
public $producerMainName;
public $producerFirstName;
public $price;
function __construct( $title, $firstName,
$mainName, $price,
$numPages=0, $playLength=0 ) {
$this->title = $title;
$this->producerFirstName = $firstName;
$this->producerMainName = $mainName;
$this->price = $price;
$this->numPages = $numPages;
$this->playLength = $playLength;
}
function getNumberOfPages() {
return $this->numPages;
}
function getPlayLength() {
return $this->playLength;
}
function getProducer() {
return "{$this->producerFirstName}".
" {$this->producerMainName}";
}
}
I have provided method access to the $numPages and $playLength properties to illustrate the
divergent forces at work here. An object instantiated from this class will include a redundant method
and, for a CD, must be instantiated using an unnecessary constructor argument: a CD will store
information and functionality relating to book pages, and a book will support play-length data. This is
probably something you could live with right now. But what would happen if I added more product
types, each with its own methods, and then added more methods for each type? Our class would become
increasingly complex and hard to manage.
So forcing fields that don’t belong together into a single class leads to bloated objects with
redundant properties and methods.
The problem doesn’t end with data, either. I run into difficulties with functionality as well. Consider
a method that summarizes a product. The sales department has requested a clear summary line for use
in invoices. They want me to include the playing time for CDs and a page count for books, so I will be
forced to provide different implementations for each type. I could try using a flag to keep track of the
object’s format. Here’s an example: