Women’s movements would form among the factory workers, a great mobilisation that destroyed the old models.
Design is the method of putting form and content together. Design, just as art, has multiple definitions; there is no single definition. Design can be art. Design can be aesthetics. Design is so simple, that’s why it is so complicated.
Create your own method. Don’t depend slavishly on mine. Make up something that will work for you! But keep breaking traditions, I beg you.
As part of the creational category of design patterns, the Factory Method pattern is involved with creating something. In the case of the Factory Method, the something created is a product that is not tied to the class that creates it. Instead, in order to maintain loose coupling, the client makes the request through a factory. The factory then makes the requested product. Another way of thinking about it is that the Factory Method frees the product from the requestor. Figure 5-1 shows a class diagram of the Factory Method.
The Client
class is implied. As you can see
in Figure 5-1, the
Client
holds a reference to the Creator (factory
interface) for requesting a graphic or text product. However, it does not
instantiate the product it requests. The concrete factories instantiate
the requested product. Imagine that you want to order chocolate cupcakes
with black and orange frosting for a Halloween party. You call the baker
(creator) who then makes the cupcakes (product) for you. You are not
involved with the creation of the object that you requested but you still
get the cupcakes requested.
In part, design patterns are selected based on what you want to be able to change. In Chapter 3, Table 3-1 shows that the Factory Method should be used when the subclass of an object instantiated can vary. In the examples in this chapter, all of the subclasses of the Project interface vary; they are different countries. As you will see, the projects developed are objects made up of text (write-ups) and graphics (maps). At the outset, we assume that the developer does not know how many countries there will be. In other words, the number and types of objects are unknown. A class cannot anticipate the number of objects it must create, and so you do not want the class tightly bound to the classes it may have to create.
If a class has a finite and known number of objects it must create, the class can be built so that the finite number of objects can be created in a predictable manner. For example, if you are making a world map application with separate objects for the seven continents, you can be fairly certain that they are not going to vary. On the other hand, if you are creating a site for different species of insects, you can be fairly certain that new ones will be discovered, change, and become extinct over a relatively short period of time. A programming product to deal with that kind of variation needs to have a good deal of flexibility built into it. This is the kind of project where you would want to consider using a Factory Method design.
To get started with the Factory Method design pattern, this first example returns only text. It is for a project where the developer knows that he will have to create different text and graphic items for a project that involves maps and text write-ups. He has no idea of exactly how many graphic-text pairs he has to create, and he’s not even sure what the client wants to add. He’s been told that a map graphic is required and that descriptive text needs to be added as well. So, to get started, he creates a small Factory Method design to output text information to the screen, one displaying “graphic” information and the other “text” information. If done correctly, it should not be difficult to make changes to accommodate any number of text and graphics.
The first step is to set up the factory: a Creator interface. For
the interface, this implementation uses an abstract class. In looking
carefully at the class diagram, one of the code annotations indicates a
concrete method, startFactory()
. From
the fact that a concrete method is used in the interface, we know that
the interface must be an abstract class instead of an interface.
Interfaces can have only abstract methods, so it must be an abstract
class. In addition, the design requires an abstract method, factoryMethod()
. In an abstract class, all
such methods need to be designated as abstract; otherwise, they are
treated as concrete methods. Creator.php shows the code for this first
pattern participant:
<?php //Creator.php abstract class Creator { protected abstract function factoryMethod(); public function startFactory() { $mfg= $this->factoryMethod(); return $mfg; } } ?>
Note that the pseudocode annotation indicates that the startFactory()
method needs to return a
product. In the implementation, startFactory()
expects that the factoryMethod()
will return a product object.
So, the concrete implementation of the factoryMethod()
needs to build and return a
product object implemented from a Product
interface.
The two concrete factory classes extend Creator
and implement the factoryMethod
. The factoryMethod()
implementation returns a text
or graphic product through a Product
method, getProperties()
. The TextFactory
and GraphicFactory
implementations incorporate
these elements:
<?php //TextFactory.php include_once('Creator.php'); include_once('TextProduct.php'); class TextFactory extends Creator { protected function factoryMethod() { $product=new TextProduct(); return($product->getProperties()); } } ?> <?php //GraphicFactory.php include_once('Creator.php'); include_once('GraphicProduct.php'); class GraphicFactory extends Creator { protected function factoryMethod() { $product=new GraphicProduct(); return($product->getProperties()); } } ?>
Both factory implementations are similar other than the fact that
one creates a TextProduct
and the
other a GraphicProduct
instance.
The second interface in the Factory Method design pattern is the
Product
. In this first minimalist
implementation, a single method, getProperties()
, is to be implemented by all
text and graphics properties:
<?php //Product.php interface Product { public function getProperties(); } ?>
Set up as a method with no properties, we can decide with the
implementation exactly what we want to do with the getProperties()
method. In PHP, given the
signature of a name and visibility, we can do anything we want with
this abstract method, including having a return value, and as long as
the name and visibility conform to the signature, we’re good to
go.
You can see where polymorphism comes in with this implementation of the Factory Method
in the getProperties()
method. It
is going to be used to return either “text” or “graphics,” but we know
that as long as it has the correct signature, it’s going to deliver
what we want. The exact same method, getProperties()
, has many (poly) different
forms (morphs). In this case, one of the forms returns text and the
other graphics:
<?php //TextProduct.php include_once('Product.php'); class TextProduct implements Product { private $mfgProduct; public function getProperties() { $this->mfgProduct="This is text."; return $this->mfgProduct; } } ?>
You may be thinking, “Big deal, all this does is return a string
variable.” At this point, that is true. However, you can put anything
you want in the implementation, and the Factory Method design will
create and return it to the Client
for use. So, where you see the output “This is text,” or “This is a
graphic,” imagine any object you may possibly want to create and use.
This next implementation returns an abstract graphic in a message with
a “text graphic”:
<?php //GraphicProduct.php include_once('Product.php'); class GraphicProduct implements Product { private $mfgProduct; public function getProperties() { $this->mfgProduct="This is a graphic.<3"; return $this->mfgProduct; } } ?>
Each of the two factory and product implementations override the abstract methods to create two different factories and products while conforming to the interfaces implemented.
The final participant in this pattern is implied: the
client. We do not want the Client
class to make a request directly to the product. Instead, we want the
request to go through the Creator interface. Later, if we add products
or factories, the client can make the same request to a much richer
variety of products without breaking the application:
<?php //Client.php include_once('GraphicFactory.php'); include_once('TextFactory.php'); class Client { private $someGraphicObject; private $someTextObject; public function __construct() { $this->someGraphicObject=new GraphicFactory(); echo $this->someGraphicObject->startFactory() . "<br />"; $this->someTextObject=new TextFactory(); echo $this->someTextObject->startFactory() . "<br />"; } } $worker=new Client(); ?>
If everything works as expected, the output is:
This is a graphic.<3 This is text.
Note that the Client
object
made no direct request to the product but instead made it through the
factory. Importantly, the client leaves the characteristics of the
product up to the product implementations.
The real value of a design pattern is not the speed of the operations but in the speed of development. In simple applications, like this current example of a Factory Method, it can be difficult to see. However, as we begin making changes, the value becomes more apparent.
The first step will be to change a product to include
loading a graphic image into an HTML document. In and of itself, adding
graphics to a web page is quite simple, but as your PHP program becomes
more complex, it can become trickier. The following shows the changed
GraphicProduct
class:
<?php //GraphicProduct.php include_once('Product.php'); class GraphicProduct implements Product { private $mfgProduct; public function getProperties() { $this->mfgProduct="<!doctype html><html><head><meta charset='UTF-8' />"; $this->mfgProduct.="<title>Map Factory</title>"; $this->mfgProduct.="</head><body>"; $this->mfgProduct.="<img src='Mali.png' width='500' height='500' />"; $this->mfgProduct.="</body></html>"; return $this->mfgProduct; } } ?>
Again you can see polymorphism at work. The same getProperties()
method now has an entirely
different implementation. Does this mean that the client will have to
change its request? No. In requesting a graphic, the Client
class just drops the text request as
the following shows:
<?php //Client.php include_once('GraphicFactory.php'); class Client { private $someGraphicObject; private $someTextObject; public function __construct() { $this->someGraphicObject=new GraphicFactory(); echo $this->someGraphicObject->startFactory() . "<br />"; } } $worker=new Client(); ?>
That simple request is the same as was made in the initial client.
However, because the GraphicProduct
object changed, so does the output, as shown in Figure 5-2.
In looking at Figure 5-2, you can see that the graphic includes text, but that text is part of the graphic image and not HTML text placed in the document.
Getting products in PHP is not that difficult, but as a site grows and becomes more complex, keeping the changes simple increases in importance. The next step is to work with the text and graphics so that they can be placed together in a document.
As you can see in Figure 5-2, the text has been
integrated into the image, so all that the change has accomplished is to
demonstrate that graphics can be loaded into a page without having to
change the client’s request from the GraphicFactory
class. Can the same be done
when more than two products have to be coordinated?
Taking materials from the CIA’s World Factbook, a map and write-up have been stitched together, as shown in Figure 5-3.
The Factory Method helps to simplify demands made by growing and increasingly complex sites where new products are introduced. To create the site shown in Figure 5-3 requires changes only in the text and graphic products. All of the other participants in the application stay the same, as requests depend on the interfaces and not the concrete products.
The changes to the text product are relatively simple. The
returned product will include some formatting and a header, but the same
variable is returned to the requesting client and displayed on the
screen. The following listing shows the changes in the TextProduct
class:
<?php //TextProduct.php include_once('Product.php'); class TextProduct implements Product { private $mfgProduct; public function getProperties() { //Begin heredoc formating $this->mfgProduct =<<<MALI <!doctype html> <html><head> <style type="text/css"> header { color: #900; font-weight: bold; font-size: 24px; font-family: Verdana, Geneva, sans-serif; } p { font-family: Verdana, Geneva, sans-serif; font-size: 12px; } </style> <meta charset="UTF-8"><title>Mali</title></head> <body> <header>Mali</header> <p>The Sudanese Republic and Senegal became independent of France in 1960 as the Mali Federation. When Senegal withdrew after only a few months, what formerly made up the Sudanese Republic was renamed Mali. Rule by dictatorship was brought to a close in 1991 by a military coup that ushered in a period of democratic rule. President Alpha KONARE won Mali's first two democratic presidential elections in 1992 and 1997. In keeping with Mali's two-term constitutional limit, he stepped down in 2002 and was succeeded by Amadou TOURE, who was elected to a second term in 2007 elections that were widely judged to be free and fair. A military coup overthrew the government in March 2012, claiming that the government had not adequately supported the Malian army's fight against an advancing Tuareg-led rebellion in the north. Heavy international pressure forced coup leaders to accelerate the transition back to democratic rule and, to that end, Dioncounda TRAORE was installed as interim president on 12 April 2012 </p> </body></html> MALI; return $this->mfgProduct; } } ?>
The changes in the text object appear to be substantial, but the
single Product
method, getProperties()
, still maintains the same
interface, returning a property object to a factory request. The
heredoc
format allows developers to
write HTML code without having to put every line in quotes, and within
the heredoc
variable PHP variables
and constants are accepted. (In the Helper Classes
section further on in this chapter, you will see how a “Helper” class
takes care of formatting.)
In looking at the graphic object class, we see the same method and interface as when it merely returned text with no HTML formatting:
<?php //GraphicProduct.php include_once('Product.php'); class GraphicProduct implements Product { private $mfgProduct; public function getProperties() { $this->mfgProduct="<img style='padding: 10px 10px 10px 0px'; src='Mali.png' align='left' width='256' height='274'>"; return $this->mfgProduct; } } ?>
Just like the text product and the magic of polymorphism, the
getProperties()
method is proving to
be as resilient as a cockroach. Nothing has been changed in the factory
objects, and the same request from the Client
has
been issued, changing the request from “text” to a “graphic”
product.
Thus far you’ve seen that changing the graphic and text will not tangle up a Factory Method design, but what happens when you start adding more maps and text write-ups? Will it be necessary to add a new concrete factory class every time a new country is added? That would mean a new factory and product would need to be added for each new country; it’s time to look at a parameterized Factory Method design. Figure 5-4 shows one such Factory Method implementation.
The class diagram in Figure 5-4 shows a number of differences from the initial class diagram. Both are accurate depictions of the Factory Method design pattern—they accomplish the same goals—but they are different in their implementation.
One of the key differences between the parameterized Factory
Method and the initial design shown in Figure 5-1 is that the client
holds references to the factory and the product. In the parameterized
request, the Client
class must name
the product, not just the product factory. The parameter in the factoryMethod()
operation is a product passed
by the client; so the client must reference the concrete product it
wants. However, that request is still through the Creator
interface. So, even though the client
has a reference to a product, it is still separated from the product
through the Creator
.
In most respects, the parameterized Factory Method is simpler because the client has to deal only with a single concrete factory. The factory method operation has a single parameter that directs the creation to the desired product. In the initial design, each product had its own factory and no parameter to pass; it relied on unique factories for each product.
As far as implementing more products from the parameterized
Factory Method, all that needs to be done is to implement more concrete
ones with the Product
interface.
Further, since the product should
contain both text and graphics, instead of having separate products for
the two, in this example, a single class can handle them both as a
unified entity without breaking the principle that each class should
have only a single responsibility. The single responsibility is to
display text and graphics depicting a country. Since the application is
a simple one, the responsibility of each Product
class is fairly simple as well.
The new factories—Creator
and CountryCreator
—are similar to the old, but
they include both a parameter and code hinting. The code hinting allows
development to proceed by programming to the interface (Product) and not
the concrete implementation of the Product interface:
<?php //Creator.php abstract class Creator { protected abstract function factoryMethod(Product $product); public function doFactory($productNow) { $countryProduct=$productNow; $mfg= $this->factoryMethod($countryProduct); return $mfg; } } ?>
As can be seen in the new Creator
abstract class, both the factoryMethod()
and the startFactory()
operations expect a parameter.
Further, because the code hinting requires a Product
object and not a specific
implementation of the Product
, it can
be used with any concrete instance of the Product
.
The concrete creator class, CountryCreator
, implements the factoryMethod()
with the necessary parameter
with code hinting. Of course, the class inherits
the startFactory()
method that will
be used by the Client
:
<?php //CountryFactory.php include_once('Creator.php'); include_once('Product.php'); class CountryFactory extends Creator { private $country; protected function factoryMethod(Product $product) { $this->country=$product; return($this->country->getProperties()); } } ?>
The concrete creator class includes a private variable, $country
, that holds the specific product
requested by the client. It then uses the Product method, getProperties()
, to return to the
client.
The changes in the concrete products do not change the original Product interface. It is exactly like it was originally:
<?php //Product.php interface Product { public function getProperties(); } ?>
That means the concrete products must also have the same
interface, and as you will see, they do. However, the new
implementations contain both graphics and text. The text is embedded in
the class itself (something you would probably get from a text file or a
database) and a graphic that is called up with a simple <img src...>
tag. The following class
represents an example with text and a graphic map culled from the CIA’s
World
Factbook:
<?php //TextProduct.php include_once('FormatHelper.php'); include_once('Product.php'); class KyrgyzstanProduct implements Product { private $mfgProduct; private $formatHelper; public function getProperties() { $this->formatHelper=new FormatHelper(); $this->mfgProduct=$this->formatHelper->addTop(); $this->mfgProduct.=<<<KYRGYZSTAN <img src='Countries/Kyrgyzstan.png' class='pixRight' width='600' height='304'> <header>Kyrgyzstan</header> <p>A Central Asian country of incredible natural beauty and proud nomadic traditions, most of Kyrgyzstan was formally annexed to Russia in 1876. The Kyrgyz staged a major revolt against the Tsarist Empire in 1916 in which almost one-sixth of the Kyrgyz population was killed. Kyrgyzstan became a Soviet republic in 1936 and achieved independence in 1991 when the USSR dissolved. Nationwide demonstrations in the spring of 2005 resulted in the ouster of President Askar AKAEV, who had run the country since 1990. Subsequent presidential elections in July 2005 were won overwhelmingly by former prime minister Kurmanbek BAKIEV. Over the next few years, the new president manipulated the parliament to accrue new powers for himself. In July 2009, after months of harassment against his opponents and media critics, BAKIEV won re-election in a presidential campaign that the international community deemed flawed. In April 2010, nationwide protests led to the resignation and expulsion of BAKIEV. His successor, Roza OTUNBAEVA, served as transitional president until Almazbek ATAMBAEV was inaugurated in December 2011. Continuing concerns include: the trajectory of democratization, endemic corruption, poor interethnic relations, and terrorism. </p> KYRGYZSTAN; $this->mfgProduct .=$this->formatHelper->closeUp(); return $this->mfgProduct; } } ?>
The output has not changed from the original Factory Method that had separate factories for graphics and text. Figure 5-5 shows what you can expect to see.
You may have noticed that the image is on the right instead of the
left, and it is larger compared to the map of Mali, but otherwise, it’s
almost the same. Something new is the addition of an instance of a class
named FormatHelper
. It is a “helper”
class that needs to be explained in the context of design patterns and
this particular implementation, but first, the Client
class needs to be re-examined because
it too has changed—it requires a parameter.
Initial examples in this chapter show how the client
simply made a request through the factory interface for the specific
product factory. With the changes made, the Client
class now has to include a parameter:
<?php //Client.php include_once('CountryFactory.php'); include_once('KyrgyzstanProduct.php'); class Client { private $countryFactory; public function __construct() { $this->countryFactory=new CountryFactory(); echo $this->countryFactory->doFactory(new KyrgyzstanProduct()); } } $worker=new Client(); ?>
A helper class in a design pattern is a class that has
some task that is better handled by a separate object instead of
incorporated into one of the participants. You might think of a helper
class in the same way you would an external CSS file. You could add the
same CSS to each and every class, but it is far more efficient to pack
it into a single file and reuse it by incorporating a <link>
tag that calls a stylesheet.
Likewise, if you have a certain set of HTML formatting tags that are
reused, they can be packaged into another object for reuse. The
following shows the helper class used with this application:
<?php class FormatHelper { private $topper; private $bottom; public function addTop() { $this->topper="<!doctype html><html><head> <link rel='stylesheet' type='text/css' href='products.css'/> <meta charset='UTF-8'> <title>Map Factory</title> </head> <body>"; return $this->topper; } public function closeUp() { $this->bottom="</body></html>"; return $this->bottom; } } ?>
Not only does it provide an HTML wrapper, it also calls the CSS
file, products.css. For
convenience, the helper class has HTML code that is added to the top and
bottom of a typical HTML page placed into two different public methods,
addTop()
and closeUp()
. In this way, the instantiated
concrete product can be placed between the correct HTML formatting
tags.
The CSS stylesheet also provides options for the developer and designer. Two CSS classes allow for left and right image alignment choices:
@charset "UTF-8"; /* CSS Document */ img { padding: 10px 10px 10px 0px; } .pixRight { float:right; margin: 0px 0px 5px 5px; } .pixLeft { float:left; margin: 0px 5px 5px 0px; } header { color:#900; font-size:24px; font-family:"Arial Black", Gadget, sans-serif; } body { font-family:Verdana, Geneva, sans-serif; font-size:12px; }
You can even think of a CSS file as a “helper” class. Likewise, you may wish to add some JavaScript or jQuery scripts as external helpers to the larger design.
An unofficial diagram that I’ve found helpful is a file diagram. Basically, it consists of a picture of the files and folders used in a design pattern with the relationship notations indicating links. It’s a lot like a Class diagram but provides a picture of the actual files in use. Figure 5-6 shows a file diagram of the final Factory Method used in this chapter.
As you can see in the diagram, the helpers and resources, while not part of the design pattern, are used by the products. A dashed box indicates they are separate from the pattern itself, and the large arrow indicates that they are used by the concrete products.
One of the big advantages of using a design pattern is the ease with which you can make changes in a class and not disrupt a much larger program. The secret to making it easy is to keep the same interface but change the contents.
One change that would simplify matters is taking the text out of the concrete products. By placing the write-ups into text files and then loading them into variables, not only would it be easier to change the text contents, but the concrete classes would be a lot cleaner as well.
In the new concrete product, a little routine adds the text to a
private variable, $countryNow
. So,
instead of having a big messy jumble of text, the concrete product has
five lines of code to place the write-up into a variable. The following
shows a new product (Moldova) with a new way of handling the
text:
<?php //MoldovaProduct.php include_once('FormatHelper.php'); include_once('Product.php'); class MoldovaProduct implements Product { private $mfgProduct; private $formatHelper; private $countryNow; public function getProperties() { //Loads text writeup from external text file $this->countryNow = file_get_contents("CountryWriteups/Moldova.txt"); $this->formatHelper=new FormatHelper(); $this->mfgProduct=$this->formatHelper->addTop(); $this->mfgProduct.="<img src='Countries/Moldova.png' class='pixRight' width='208' height='450'>"; $this->mfgProduct .="<header>Moldova</header>"; $this->mfgProduct .="<p>$this->countryNow</p>"; $this->mfgProduct .=$this->formatHelper->closeUp(); return $this->mfgProduct; } } ?>
As you can see, all of the messy text is gone. However, what
remains the same—and is crucial to remain unchanged—is the getProperties()
interface. As long as you keep
an eye on the interface, making changes or additions in a Factory Method
design pattern will not result in a crash. This is true even though an
additional external resource has been added. Figure 5-7 shows that the new results
are like the old results but with a different country.
As your products become more complex—something beyond simple placement of text and graphics in an HTML document—the more important the interface becomes. Fortunately, maintaining a single interface is much easier than attempting to maintain any number of classes and objects. That is why using the Factory Method simplifies the complex creation process: it maintains a common interface.