If you do a Google search for “Factory Design Pattern,” thankfully, the first hits are “Factory Method….,” the correct name of the pattern that Gamma and his associates developed as a fundamental design pattern. I am not at all impressed by nit-pickers, and lest you think me petty by touching upon the notion of “Factory” vs. “Factory Method,” I hope this post will show you why including a factory method in a Factory Method design pattern is both important and necessary.
The Factory Method: Abstract with Concrete Operations
Some of the posts about the Factory Method are more about the idea of a factory than a method within the Creator (Factory) interface. What the key is, though, is to design an interface in the Factory with both abstract and concrete elements which return a concrete Product. The details of the factoryMethod() are left up to the concrete implementations to decide which one to implement. The factoryMethod() is abstract, but with PHP7, we can establish a return type. What is a return type? When stated, it is the type of data that a method must return. In earlier versions of PHP, using type hinting, only certain types of objects could be included in a method’s arguments. Now, though, you can add a return type to a method. For example, the factoryMethod() in this example includes an IProduct return type after the closing parenthesis in the function declaration:
abstract protected function factoryMethod():IProduct;
Like the scalar variables discussed in a pervious post that could be typed as code hints in parameters, a return value of a scalar variable such as a string means the that the method must return a string, as you can see in the IProduct implementations. However, the factoryMethod is designed to return an instance of an IProduct (the object) implementation. While common in other languages, return types are newly added feature in PHP7.
The Elegance of the Factory Method
Every time I go over the original Design Patterns in the GoF book, I find something new. One of my favorite patterns is the Template Method. The method itself is concrete but the operations within the method are abstract. The Factory Method is the opposite. The factory method is abstract, but it is called by a concrete operation defined in the interface. (I use the term interface to reference both PHP interface type classes as well as abstract class types.) To be sure, The Gang of Four, have more than a single implementation suggested for the Factory Method pattern, but in the class diagram, the method is set up in the interface (Creator) as an abstract method along with a concrete method as shown in Figure 1:

Figure 1: Factory Method class diagram
Before continuing, run the program (Play) and download the source code (Download.) The program is one I’m using to build a path from Lambda Calculus to PHP. (To run the downloaded source files, you’ll need PHP 7.)
Once you have the source code downloaded and a sense of what the program produces, you’ll better understand how the Factory Method pattern makes it easy to update the “products” showing the lambda calculus and the PHP program using functional methods. The Creator participant in this pattern (IFactory) includes two methods; one abstract and one concrete as shown in the following listing:
abstract class IFactory
{
//This class is the 'Creator' interface in the class diagram.
protected $productNow;
/*
* Factory Method--returns concrete Product--reutrns any
* implementation of IProduct--it programs to the Interface
*/
abstract protected function factoryMethod():IProduct;
/*
* The createProduct() is identified as 'anOperation()' in the class digram
* While it is a concrete method, it returns the factoryMethod()
* an abstract method.
*/
public function createProduct():IProduct
{
return $this->factoryMethod();
}
}
?>
|
The IFactory abstract class may appear to be both strange and broken. How can a concrete method (createProduct) return an abstract method (factoryMethod)? Far from being broken, it’s brilliant. It means that while the createProduct() must return a factoryMethod(), the factoryMethod() can be implemented any way the developer needs following the structure of the interface.
Thoughtful Structure and Easy Update
As a Creational type of design pattern, the Factory Method may have what some consider an unnecessarily fussy (and complex) structure to get a simple product. In this example, the product returns nothing but strings with some HTML embedded to display text messages. Wouldn’t it be just as effective and a lot easier to have a single object for each product using a single interface? Or even simpler, have a single class and just add a set of properties for each string? The answer to all of those questions is, Yes, of course. However, there’s a caveat: if your product is simple; so is the solution. In the examples on this blog, I’ve tried to clarify how to build different design patterns correctly and clearly. We were stuck with the following paradox:
The clearer a design pattern example, the less useful it appears to be.
So, while generating output from strings is no great shakes, the important point is to see how simple it is to make changes using the Factory Method pattern. For example, instead of generating strings, suppose each product requires calls to a MySql database, a jQuery-based mobile UI, and a JavaScript graphic handler (not jQuery). If you look at Figure 2, you can see how this implementation follows the class diagram in Figure 1. The HTML UI and CSS file call the Client:

Figure 1: Implementation of the Factory Method pattern
Okay, that’s a bit more complex, but the real issue is how to have several such products generated by the same program, each needing regular (e.g., daily) update and changes for several such products. By having a Factory Method take care of all of the new creations (additions and changes), you can rest assured that as the program gets bigger,as long as you follow the rules in the design pattern (attend to the rules laid down in the interfaces), not only will it be easier to maintain, but it will be less prone to bugs.
The Factory: The Method Returns Help the Developer
In creating the examples using PHP7 and the new function return types, I kept running into errors as I attempted to return product instances. The errors indicated that I was returning strings instead of objects (product instances). Because of the return typing, I was able to find the errors and return the objects, which in turn returned the strings from the products. First, look at the IFactory implementations:
class FactoryID extends IFactory
{
protected function factoryMethod():IProduct
{
$this->productNow = new LambdaID();
return $this->productNow;
}
}
?>
class FactoryApp extends IFactory
{
protected function factoryMethod():IProduct
{
$this->productNow = new LambdaApp();
return $this->productNow;
}
}
?>
class FactoryPythag extends IFactory
{
protected function factoryMethod():IProduct
{
$this->productNow = new LambdaPythag();
return $this->productNow;
}
}
?>
|
As you can see each implementation of the factory interface differs only slightly. Each calls a different product implementation. Because the createProduct() method is concrete, it does not need further implementation—even though the method calls an abstract method. (Note: Please remember that each class is saved as the class name with the “.php” extension.)
The Product As an Object
The final element that the Client displays on the screen is a string. However, the string is part of a product object. By returning the object to the Client, the Client can use the available (accessed through public visibility) properties and methods of the product object. The factory’s job is to return the Product object.
The product itself can be any number of different things and can return any kind of property or method it has available. In looking at the abstract Product class, you can see that it is made up of two abstract methods and a single property:
abstract class IProduct
{
//Product methods must return a string
abstract public function getProduct():string;
abstract protected function prodParts():string;
//Properties
protected $lambdaProd;
}
?>
|
As you can see, the IProduct implementation must return a string—not an object as the IFactory implementations do. The implementations use the getProduct() method to get the built-string (built of a lambda calculus formula string concatenated with a PHP coded function string) from the prodParts() method.
class LambdaID extends IProduct
{
public function getProduct():string
{
return $this->prodParts();
}
protected function prodParts():string
{
$st="style='color:#CF5300;font-family:courier new, monospace;font-weight: bold;font-size: 18px'";
$lambdaCode="
|
Because the factoryMethod() returns an object (instead of a raw value) the product object can be anything. In this case the return values in the two methods are defined to be strings, and so this implementation must return a string. As you can imagine, it would not be difficult to return some other scalar variable or even other objects from within the product. Just change the return type from string to some other type and the product will serve it up to the Client via the factory.
The Unchanging Client and the Simple HTML UI
To get the ball rolling in this program, the Client must make a request. Because the request will come from the user, the program needs a UI which is typically made with HTML and perhaps some jQuery UI tools. In this case, the HTML UI is plain vanilla HTML5 using a single set of mutually exclusive radio buttons. This means that only a single value from a single named UI type (radio group name) is passed from HTML to PHP as a superglobal (e.g., $_POST[‘name’]). As more options for the same kind of information are created, the HTML UI can expand, but the Client remains unchanged no matter how many lambda calculus-to-PHP examples the developer wants to generate. First, the UI is the source of the request:
|
Now the client can expect to have the superglobal with a named element, ‘lamcalc‘, to pass the name of the factory to return the product it requests. The Client request() method uses that value (the passed string) to call the appropriate factory method implementation that it returns to the user. That’s it, and it does not have to change as more requests are added to the radio button group in the HTML UI.
error_reporting(E_ALL | E_STRICT);
ini_set("display_errors",1);
// Autoload given function name.
function includeAll($className)
{
include_once($className . '.php');
}
//Register
spl_autoload_register('includeAll');
class Client
{
private $factory,$calcCode,$product, $productContents;
//client request
public function request()
{
$this->factory=$_POST['lamcalc'];
unset($_POST['lamcalc']);
$this->calcCode=new $this->factory();
$this->product= $this->calcCode->createProduct();
$this->productContents=$this->product->getProduct();
echo $this->productContents;
}
}
$worker=new Client();
$worker->request();
?>
|
The line of code calling for error messages, ini_set(“display_errors”,1); should be changed to, ini_set(“display_errors”,0); when launched in production, but otherwise, it’s already for production. If your hosting company does not have PHP7 yet, bug them to include it. By all means, though, you should download PHP7 to your development environment and start using typed method returns and the typed scalar variables for the method parameters.
A Final (Strange) Note about the CSS
The CSS used for this design pattern example seems to have issues—or certain browsers do. When run in Google Chrome or Apple’s Safari browsers, everything looks as it should. However, when using either FireFox or Opera (on either a Windows PC or a Mac), none of the styling from the external CSS kicks in, but the inline CSS in the returned strings does. Go figure. Here’s the external CSS:
@charset "UTF-8"; /* #A6330A (burnt orange) #BF6415 (orange) #731702 (dk terracotta) #F0D47F (cream) #E3B96F (tan) */ body { font-family:"Gill Sans", "Gill Sans MT", "Myriad Pro", "DejaVu Sans Condensed",Verdana, Helvetica, Arial, sans-serif; color:#731702; background-color:#F0D47F; width:500px; margin-left: 5%; } h2 { color:#E3B96F; font-family: "Lucida Grande", "Lucida Sans Unicode", "Lucida Sans", "DejaVu Sans", Verdana, sans-serif; padding-left: 1em; background-color:#A6330A; width: 500px; } iframe { background-color:#ccc; } |
My hunch is that the inline CSS running in Firefox and Opera cancels the imported CSS, but there’s no reason it should do that; especially when both Chrome and Safari don’t have that problem.
Copyright © 2015 William Sanders. All Rights Reserved.
0 Responses to “Factory Method with Return Typing”