Originality is nothing but judicious imitation. The most original writers borrowed one from another.
We forfeit three-quarters of ourselves in order to be like other people.
Act that your principle of action might safely be made a law for the whole world.
The Prototype design pattern is interesting in its use of a cloning technique to replicate instantiated objects. New objects are created by copying prototypical instances. In this context, instances refer to instantiated concrete classes. The purpose is to reduce the cost of instantiating objects by using cloning. Rather than instantiating new objects from a class, a clone of an existing instance can be used instead. Figure 6-1 shows the Prototype class diagram.
Note that the Client
class
is an integral part of the Prototype design pattern. The
client creates an instance of a concrete prototype through the Prototype
interface that includes a clone method of some sort. Fortunately, PHP has
a built-in clone()
method that can be
used within the design pattern. As you will see, the basics of the design
are quite simple.
The Prototype pattern should be used in any application where your project requires that you create several instances of a prototypical object. For example, in research on evolutionary development, scientists often use fruit flies. They reproduce quickly and have a greater probability of generating a mutation, the fundamental evolutionary change event. For example, a typical study may use 15 million fruit flies, and because females may be laying eggs almost as soon as they emerge (within hours), the chance of finding and recording mutations is much greater than with other creatures, such as elephants, which have a 22-month gestation period. In recording mutations, the male and female prototypes serve as a base, and mutations are a clone of any male or female instance. Thus, from two instantiations (one male and one female), you can clone as many mutations as required with no further need to create another instance from the concrete classes.
The Prototype pattern has also been used to create an organizational structure where a finite number of positions can be created and filled based on the actual organization. Prototypes have been used where a drawing object has been created using composition and then cloned for different versions. A final example could be in game development where a prototype warrior could be cloned to add numbers and types to an army.
The key to working with the Prototype design pattern in PHP
is understanding how to use the built-in function, __clone()
. While somewhat odd in relation to
what you’ve probably done in PHP programming, it’s very easy. In order to
see how to use the method, look at the following little program. (You
really don’t need to extend an abstract class that contains an abstract
__clone()
method, but the examples all
show an abstract class including a __clone()
method, and so this might prove useful
in the further Prototype examples in this book.)
<?php //CloneMe.php abstract class CloneMe { public $name; public $picture; abstract function __clone(); } class Person extends CloneMe { public function __construct() { $this->picture="cloneMan.png"; $this->name ="Original"; } public function display() { echo "<img src='$this->picture'>"; echo "<br />$this->name <p />"; } function __clone() {} } $worker=new Person(); $worker->display(); $slacker = clone $worker; $slacker->name="Cloned"; $slacker->display(); ?>
The concrete class Person
is an
extension of the CloneMe
abstract
class. In the example, an instance of Person
is instantiated by $worker
. So now, $worker
is a Person
object. Next, a second instance variable,
$slacker
, clones the $worker
instance of Person
. It has access to the same properties as
$worker
and can change them just as a
direct instance of the Person
class
would be able to do. Figure 6-2 shows the
results.
The __clone()
method cannot be
accessed directly. Rather, if a __clone()
method has been included in a class
definition, using the following format:
$anotherInstance = clone $someInstance;
the clone
keyword instantiates
another instance of the same class as that of the cloned instance. The PHP
documentation notes:
An object copy is created by using the
clone
keyword (which calls the object’s__clone()
method if possible). An object’s__clone()
method cannot be called directly.
There’s one catch to the cloning process: the clone does not launch the action in the constructor function. Clones can use default assigned values generated by the constructor, but if a constructor generates an action such as printing a message as soon as it is instantiated, the clone will not display that message (“Hello, clone!”). The following example shows how a constructor sends out a message upon instantiation but not on a clone operation:
<?php class HelloClone { private $builtInConstructor; public function __construct() { echo "Hello, clone!<br />"; $this->builtInConstructor="Constructor creation<br />"; } public function doWork() { echo $this->builtInConstructor; echo "I'm doing the work!<p />"; } } //Launch constructor $original=new HelloClone(); $original->doWork(); //Clone does not launch constructor $cloneIt = clone $original; $cloneIt->doWork(); ?>
The original instantiation displayed the message “Hello, clone!” but the clone operation did not. The following output shows the results:
Hello, clone! Constructor creation I'm doing the work! Constructor creation I'm doing the work!
What this means for the Prototype design pattern (and any other use of cloning) is that you should not depend on your constructor function for any significant output or return. However, that may not be a bad thing. In fact, it may be a good programming practice.
In discussing unit testing, Miško Hevery, who develops coding guidelines for Google, points out that a constructor should do no real work (http://bit.ly/1a9MWr). The comment was made in the context of unit testing (testing parts of a program), but it certainly may apply to design patterns. Hevery’s main point is that when a class instantiates and initializes its collaborators, the result tends to be an inflexible and prematurely coupled design. In the same vein, when a constructor function outputs anything, it provides no options for the client other than to shoot out what the constructor sends, even if it does not want it—or at least does not want it at a given time.
Hevery’s point does not mean that a constructor function cannot assign values to properties when needed. Likewise, the client’s constructor can be a good deal different from the other participants of a pattern because it is making requests of the participants.
One way to deal with the concept that constructors should do no
real work is to omit constructor functions in pattern classes unless you
have a good reason to include them. Otherwise, allow operations to be
called when needed and let the client take care of instantiation and
cloning chores. So, while we can find limitations in using the __clone()
function, those limitations may aid
in better OOP programs.
In this first example, consider an experiment using fruit flies. The goal of the research is to set up a prototype fruit fly and then, whenever a mutation occurs, build the mutation. With 50 million flies, you’ll get a lot of mutations, but you’re interested only in the fly’s eye color, the number of wing beats per second, and the number of unit eyes since the fruit fly eye contains hundreds of light-sensing units, each with its own lens and set of light receptor cells, and they may vary based on gender and reproduction. Other mutations are possible, but this study examines only those three variables.
The reason for selecting the Prototype for a fruit fly study is that it provides a starting point from which to measure mutation. The concrete classes set up a baseline for standard values for fruit flies, and mutations can be measured as deviations from the baseline. An abstract class provides the baseline variables (all of them are public for ease of the example use).
The two concrete class implementations of the prototype
(IPrototype
) represent the fly
genders, the variable (gender), and gender behaviors (mating and
producing eggs). The abstract class also includes an abstract method
based on the __clone()
method.
<?php //IPrototype.php abstract class IPrototype { public $eyeColor; public $wingBeat; public $unitEyes; abstract function __clone(); } ?>
The two implementations of IPrototype
differentiate between gender
using constants labeling one MALE
and the other FEMALE
. The male has
a $mated
Boolean variable set to
true
after the male has mated and
the female has a $fecundity
variable containing a numeric value representing how capable the fly
is at reproducing (its number of remaining eggs):
<?php //MaleProto.php include_once('IPrototype.php'); class MaleProto extends IPrototype { const gender="MALE"; public $mated; public function __construct() { $this->eyeColor="red"; $this->wingBeat="220"; $this->unitEyes="760 "; } function __clone(){} } ?>
Importantly, both concrete implementations of IPrototype
have an implemented __clone()
method even though the
implementation is nothing more than adding two curly braces to the
statement. The __clone()
method is
built into PHP with encapsulated code that will do the required work
for this particular design pattern; so an “implementation” can be
nothing more than adding the signature of a function:
<?php //FemaleProto.php include_once('IPrototype.php'); class FemaleProto extends IPrototype { const gender="FEMALE"; public $fecundity; public function __construct() { $this->eyeColor="red"; $this->wingBeat="220"; $this->unitEyes="760 "; } function __clone(){} } ?>
Both implementations include literals (actual numbers, strings, or Booleans) for the assigned values. In this way, the mutations can be measured as a deviation from these values.
While not rare in design patterns, the Client
class is included as an
integral participant in the Prototype design
pattern. The reason for this is that while the concrete
implementations of the child classes serve as templates for the
instances, the work of actually cloning the instances using the same
template is carried out by the Client
class.
The two concrete implementations of the prototype are very
simple and use direct value assignments to the shared variables of
eyeColor
, wingBeat
, and unitEyes
; they don’t even have getter/setter
methods. For now, that’s fine because the focus is on seeing how those
properties are used by the cloned implementations of the classes’
instances; $fly1
and $fly2
are instantiated from the concrete
classes and $c1Fly
, $c2Fly
, and $updatedCloneFly
are all clones of one or
the other of the two class instances.
<?php //Client.php function __autoload($class_name) { include $class_name . '.php'; } class Client { //For direct instantiation private $fly1; private $fly2; //For cloning private $c1Fly; private $c2Fly; private $updatedCloneFly; public function __construct() { //Instantiate $this->fly1=new MaleProto(); $this->fly2=new FemaleProto(); //Clone $this->c1Fly = clone $this->fly1; $this->c2Fly = clone $this->fly2; $this->updatedCloneFly = clone $this->fly2; //update clones $this->c1Fly->mated="true"; $this->c2Fly->fecundity="186"; $this->updatedCloneFly->eyeColor="purple"; $this->updatedCloneFly->wingBeat="220"; $this->updatedCloneFly->unitEyes="750"; $this->updatedCloneFly->fecundity="92"; //Send through type hinting method $this->showFly($this->c1Fly); $this->showFly($this->c2Fly); $this->showFly($this->updatedCloneFly); } private function showFly(IPrototype $fly) { echo "Eye color: " . $fly->eyeColor . "<br/>"; echo "Wing Beats/second: " . $fly->wingBeat . "<br/>"; echo "Eye units: " . $fly->unitEyes . "<br/>"; $genderNow=$fly::gender; echo "Gender: " . $genderNow . "<br/>"; if($genderNow=="FEMALE") { echo "Number of eggs: " . $fly->fecundity . "<p/>"; } else { echo "Mated: " . $fly->mated . "<p/>"; } } } $worker=new Client(); ?>
With multiple class references, it’s easier to use the PHP
__autoload()
method than the
include_once
method. In this way,
no matter how many participants or helper classes the Client
class references, all classes are
automatically included. The downside of using __autoload()
while learning design patterns
is that the include_once
method
shows all of the classes in use. Throughout the rest of the book, one
or the other of the techniques for including classes in external files
is employed depending on how useful a specific class referenced class
name is to understanding the program. (Filenames are based on class
names.)
The following output shows two unchanged clones of the male and female concrete classes (the “template” classes) and the third is the output of a “mutated” clone indicated by purple eyes and a different number of eye units. The number of eggs is within a standard deviation and is not considered a mutation.
Eye color: red Wing Beats/second: 220 Eye units: 760 Gender: MALE Mated: true Eye color: red Wing Beats/second: 220 Eye units: 760 Gender: FEMALE Number of eggs: 186 Eye color: purple Wing Beats/second: 220 Eye units: 750 Gender: FEMALE Number of eggs: 92
The Prototype depends on the Client to use the concrete prototypes through a cloning process. The Client is the participant in the design that performs the cloning, and because cloning is the key element in the Prototype design, that makes the Client a fundamental participant and not simply a requesting class.
The minimalist example focuses on the relationships between the participants and the outcome. To keep the amount of code to the minimum to “see” the structure, the classes were not built with the kind of encapsulation we expect from an OOP application. In other words, the participants in the pattern implementation are fairly skeletal so that the relationship between the classes is easier to see. For instance, in the minimal implementation of the Prototype, the Client is able to change prototype property values directly—that is, by simple assignment. For example, the client changed the mutant eye color using the following code:
$this->updatedCloneFly->eyeColor="purple";
No method in the abstract or concrete prototype classes included getter/setter methods or some other structure to better encapsulate the properties.
On the creational side of design patterns, modern business organizations may be good candidates for the Prototype implementation. As bureaucratic hierarchies, they model many of the same characteristics that object-oriented programming does. This next Prototype example is still relatively simple, with the focus on understanding class relationships, but it is better encapsulated along the lines expected by OOP. The class diagram in Figure 6-3 shows its participants and general structure.
The software engineering corporation depicted is typical of modern organizations. The Engineering Department is responsible for creating the product, Management handles coordinating and organizing resources, and Marketing is in charge of sales, promotion, and overall marketing of the product.
The first thing that this Prototype implementation does is add OOP to the program’s interface—an abstract class. Like all Prototype interfaces, this one includes an abstract cloning operation. However, it also includes both abstract and concrete getters and setters. The abstract getter/setter pair leaves the specific implementation up to the three concrete prototype implementations. The other getter/setter methods are more generally applicable to such things as employee names, ID codes, and photos. Not that all of the properties are protected, so even though the concrete getters and setters have public visibility, the protected visibility of the properties used in the operations affords a degree of encapsulation:
<?php //IAcmePrototype.php abstract class IAcmePrototype { protected $name; protected $id; protected $employeePic; protected $dept; //Dept abstract function setDept($orgCode); abstract function getDept(); //Name public function setName($emName) { $this->name=$emName; } public function getName() { return $this->name; } //ID public function setId($emId) { $this->id=$emId; } public function getId() { return $this->id; } //Employee Picture public function setPic($ePic) { $this->employeePic=$ePic; } public function getPic() { return $this->employeePic; } abstract function __clone(); } ?>
With the getter/setter methods set, the values for any of the properties are through inherited protected variables. With this arrangement, the extended classes and their instances are better encapsulated.
Each of the three IAcmePrototype
child classes must implement
the “dept” (department) abstract methods along with the __clone()
method. Likewise, each concrete
prototype class includes a constant, UNIT
, with an assigned value that can be used
by instances, whether implemented directly or a clone, for
identification. Begin by looking at how the Marketing class has been
structured:
<?php //Marketing.php include_once('IAcmePrototype.php'); class Marketing extends IAcmePrototype { const UNIT="Marketing"; private $sales="sales"; private $promotion="promotion"; private $strategic="strategic planning"; public function setDept($orgCode) { switch($orgCode) { case 101: $this->dept=$this->sales; break; case 102: $this->dept=$this->promotion; break; case 103: $this->dept=$this->strategic; break; default: $this->dept="Unrecognized Marketing "; } } public function getDept() { return $this->dept; } function __clone(){} } ?>
The setDept()
method is
implemented using a single parameter. Instead of directly entering the
name of the department within the marketing unit, the method expects a
numeric code. If it were expecting an object derived from a class, the
method could be built using a type hint for an object/interface type,
but type hinting does not allow scalar types such as int
. Using a switch/case
statement with the argument as a
comparative variable, the class enforces one of three acceptable cases
or defaults to “Unrecognized Marketing.” Once a match is made, the
operation uses a private variable that has an assigned value. Again,
this helps to encapsulate both the class and setter method. The getter
method (getDept()
) uses the same
private variables.
The other two prototype implementations are similar, but note that
each has different departments stored in private variables. Likewise,
each has a different value for the constant, UNIT
:
<?php //Management.php include_once('IAcmePrototype.php'); class Management extends IAcmePrototype { const UNIT="Management"; private $research="research"; private $plan="planning"; private $operations="operations"; public function setDept($orgCode) { switch($orgCode) { case 201: $this->dept=$this->research; break; case 202: $this->dept=$this->plan; break; case 203: $this->dept=$this->operations; break; default: $this->dept="Unrecognized Management"; } } public function getDept() { return $this->dept; } function __clone(){} } ?>
The values expected in the switch/case
statement are different in all
three concrete prototype implementations. Likewise, the name and values
of the private properties are different as well:
<?php //Engineering.php include_once('IAcmePrototype.php'); class Engineering extends IAcmePrototype { const UNIT="Engineering"; private $development="programming"; private $design="digital artwork"; private $sysAd="system administration"; public function setDept($orgCode) { switch($orgCode) { case 301: $this->dept=$this->development; break; case 302: $this->dept=$this->design; break; case 303: $this->dept=$this->sysAd; break; default: $this->dept="Unrecognized Engineering"; } } public function getDept() { return $this->dept; } function __clone(){} } ?>
With all three concrete prototype implementations, each unique for
its use but respecting the interface, a single instance of each can be
created and then cloned by as many instances as needed. The Client
class will fill this last
role.
The basic setup for the Client is very simple. The plan is to create a single instance of each concrete prototype and then clone each one as the following outline shows:
Marketing Instance
Marketing clone
Marketing clone
Management Instance
Management clone
Engineering Instance
Engineering clone
Engineering clone
Only the clones will be used. The information for each unique case is to be assigned to the clones using the getter/setter methods. The following code for the client shows this implementation:
<?php //Client.php function __autoload($class_name) { include $class_name . '.php'; } class Client { private $market; private $manage; private $engineer; public function __construct() { $this->makeConProto(); $Tess=clone $this->market; $this->setEmployee($Tess,"Tess Smith",101,"ts101-1234","tess.png"); $this->showEmployee($Tess); $Jacob=clone $this->market; $this->setEmployee($Jacob,"Jacob Jones",102,"jj101-2234","jacob.png"); $this->showEmployee($Jacob); $Ricky=clone $this->manage; $this->setEmployee($Ricky,"Ricky Rodriguez",203,"rr203-5634","ricky.png"); $this->showEmployee($Ricky); $Olivia=clone $this->engineer; $this->setEmployee($Olivia,"Olivia Perez",302,"op301-1278","olivia.png"); $this->showEmployee($Olivia); $John=clone $this->engineer; $this->setEmployee($John,"John Jackson",301,"jj302-1454","john.png"); $this->showEmployee($John); } private function makeConProto() { $this->market=new Marketing(); $this->manage=new Management(); $this->engineer=new Engineering(); } private function showEmployee(IAcmePrototype $employeeNow) { $px=$employeeNow->getPic(); echo "<img src=$px width='150' height='150'><br/>"; echo $employeeNow->getName() . "<br/>"; echo $employeeNow->getDept() . ": " . $employeeNow::UNIT . "<br/>"; echo $employeeNow->getID() . "<p/>"; } private function setEmployee(IAcmePrototype $employeeNow,$nm,$dp,$id,$px) { $employeeNow->setName($nm); $employeeNow->setDept($dp); $employeeNow->setID($id); $employeeNow->setPic("pix/$px"); } } $worker = new Client(); ?>
The client’s constructor class holds three private properties to
be used to instantiate one each of the three concrete prototype classes.
The makeConProto()
method generates
the necessary instances.
Next, an “employee” instance is created using the clone technique.
The cloned instance then sends unique instance information to a setter
method (setEmployee()
) that uses type
hinting for the IAcmePrototype
interface. However, note that it employs type hinting only for the first
parameter. None of the other parameters have type hinting, and they do
not have to be derived from the IAcmePrototype
interface. All of the setter
methods from the IAcmePrototype
abstract class as well as the implemented setDept()
methods from the concrete prototype
classes are used by the cloned “employee.”
In order to use the data for each employee, the Client
class uses the inherited getter
methods. Figure 6-4 shows a simple
output for each of the five employee clones.
You can add as many clones as required, and all you will ever need is a single instantiation of one of the concrete prototype classes. Instead of having several instances of the concrete classes, you have a single class instantiation and several clones.
The important point, perhaps the fundamental point, to
keep in mind is that design patterns allow the developer to add and
change a program without having to start all over. For example, suppose
that the president of the company decides that a new division should be
added to the company—Research, for instance. Would that be difficult to
do? Not at all. A Research
class
could extend the IAcmePrototype
abstract class and implement the abstract getter/setter methods to
reflect the division’s organization. Note that the getter/setter methods
in the Client
class use code hinting
to the interface and not a concrete implementation of the abstract
class. So, as long as the added unit implements the interface correctly,
it will slip into the application without making a wave or requiring
refactoring of the other participants in the program.
In addition to adding more concrete classes, making changes within
each class is just as easy and undisruptive. For example, suppose the
marketing division of the organization decides that they need a special
online marketing division apart from the current departments they have.
The switch/case
operation would need
a single new case and a new private property (variable) to describe the
added department. This change would not affect the other participants,
encapsulated in their classes. The bigger the application, the more
important it is that the change does not cause disruption, and as you
can see, the Prototype design pattern allows for both consistency and
change.
In looking at the Client
class, you may be thinking that with a
real organization, you’d have a lot more employees, and hardcoding them
in a client doesn’t seem to be a very smart way of dealing with the
problem. That’s absolutely true, and so we need to consider how to
dynamically create clones from data stored in a database, an XML file,
or somewhere other than a line of code in a client.
When you use a record from a database, you can pass that data to a
PHP program to handle it. However, the data are not stored as instances
of a concrete class but instead as numeric or string data of some kind.
Take, for example, the following bit of data from the Client
class:
$Tess=clone $this->mar; $this->setEmployee($Tess,"Tess Smith",101,"ts101-1234","tess.png"); $this->showEmployee($Tess);
The data in the setEmployee()
method arguments would normally come from a database and feed into the
Client. The first parameter expects an object with the IAcmePrototype
interface. So, the question is,
how do you dynamically create (clone) an object based on data coming
from a database?
PHP seems to be one of the most considerate languages around when it comes to dynamic creation. The process to take a variable and instantiate a class in PHP is quite simple. The following code creates an instance of a class from a value in a variable:
//Class name = MyClass $myVar = "MyClass"; $myObj =new $myVar;
That’s it. The variable $myObj
has just instantiated an instance of
MyClass
.
The code is equivalent to the following:
$myObj = new MyClass();
Using these techniques, you can dynamically create and clone objects from data coming from a database, array, or anywhere else you program gets it data.
In the following example, imagine that instead of an array, the data are coming from a database. The same principles apply. Note also that it employs an interface instead of an abstract class:
<?php interface IPrototype { const PROTO="IPrototype"; function __clone(); } class DynamicObjectNaming implements IPrototype { const CONCRETE=" [Concrete] DynamicObjectNaming"; public function __construct() { echo "This was dynamically created.<br/>"; } public function doWork() { echo "<br/>This is the assigned task.<br/>"; } function __clone() {} } $employeeData = array('DynamicObjectNaming','Tess','mar', 'John', 'eng', 'Olivia','man' ); $don=$employeeData[0]; $employeeData[6]=new $don; echo $employeeData[6]::CONCRETE; $employeeData[6]->doWork(); $employeeName=$employeeData[5]; $employeeName = clone $employeeData[6]; echo $employeeName->doWork(); echo "This is a clone of " . $employeeName::CONCRETE . "<br/>"; echo "Child of: " . $employeeName::PROTO; ?>
When you run the program, you will see the following output:
This was dynamically created. [Concrete] DynamicObjectNaming This is the assigned task. This is the assigned task. This is a clone of [Concrete] DynamicObjectNaming Child of: IPrototype
Notice that in the initial instantiation, the constructor printed, “This was dynamically created.” That’s because the instantiation launched the operations in the constructor. However, in the cloning process, the cloned object did not launch the constructor. Nevertheless, the clone could use any assigned values generated from the initial instantiation of the class that was passed to the cloned object.
Because PHP is a server-side language and is a key tool for interacting with a MySQL database, the Prototype design pattern is an especially good option. Instead of having to create new objects for every element in a database, PHP can use the Prototype to create single instances of a concrete class and then clone the rest of the cases (records) from the database.
After looking at the cloning process compared with direct
instantiation of an object from a class, you may well ask yourself,
“What’s the difference?” In other words: Why do clones use fewer resources
than objects instantiated directly from a class? The big difference is in
what you do not see. When an object creates an instance through cloning,
it does not fire the constructor. In the DynamicObjectNaming
class application, you saw
an example of where the direct instantiation fired off the constructor and
the clone did not. The clone had all of the properties of the original
class and even parent interface, but it also inherited any values that had
been passed to the instantiated object. Any values generated by the
constructor function and stored in the object properties become a part of
the object. So there is no need to rerun the constructor. If you find that
your clones do need access to values generated by the constructor function
but cannot access them, it’s time to refactor your class so that
instantiated instances have everything they need and can pass that on to
the clone.
Overall, the Prototype can be applied in several different kinds of PHP projects where a problem solution calls for a creational pattern. This chapter has provided a couple of different examples, but now that you have a better idea of what the Prototype pattern does and how to use it, keep an eye open for opportunities to employ it. If you do, you can expect to save development time and improve your design for changes that may occur.