Currently, I use an abstract factory to allow the specification of a custom class name for generating a request object. My reasoning for doing this is to allow me to easily extend core functionality without altering code. Recently, though, I've had some doubts as to the efficacy of this approach. So my question is this:
Is allowing the factory to instantiate any submitted class name that
matches the expected interface a bastardization of the factory concept?
Would I be better served to avoid this?
UPDATE
The logic here is this: on the one hand, a real-life car factory (for example) can't create a car if it's not equipped with the machinery to make that kind of car. On the other hand, the code below is like giving that same car factory the blueprint to make the custom car it wasn't originally intended to build.
An alternative would be to pass in a configuration object specifying a custom class name that may be used with the factory and limit the factory to producing a custom class only if it specifically matches the config-specified custom class name. Any thoughts?
And the relevant code ...
<?php
interface AbstractRequestFactory
{
public function buildRequest($type);
}
class RequestFactory implements AbstractRequestFactory
{
public function buildRequest($type='http')
{
if ($type == 'http') {
return new HttpRequest();
} elseif ($type == 'cli') {
return new CliRequest();
} elseif ($custom = $this->makeCustom($type)){
return $custom;
} else {
throw new Exception("Invalid request type: $type");
}
}
protected function makeCustom($type)
{
if (class_exists($type, FALSE)) {
$custom = new $type;
return $custom instanceof RequestInterface ? $custom : FALSE;
} else {
return FALSE;
}
}
}
// so using the factory to create a custom request would look like this:
class SpecialRequest implements RequestInterface {}
$factory = new RequestFactory();
$request = $factory->buildRequest('\SpecialRequest');
What you have looks pretty good. The point of having a factory is to pass in some criteria, and have the method return you back an object, which you assume will have the same callable methods available to the calling code. You are enforcing this assumption by implementing the RequestInterface, so as long as any custom request classes implement the same interface, you won't end up in a 'unable to call function on non-object' scenario.
A couple of recommendations (just personal preference):
I would use switch / case on $type in buildRequest
I would return null or object from makeCustom(), otherwise you are mixing return types (object and bool)
Depending on how many custom types you have, I would actually hard code them into the switch case, just to alleviate any confusion. Don't get me wrong, what you have is great if you have a lot of classes, but chances are you don't.
Did you ever consider putting the "easily extend core functionality without altering code" piece into an abstract parent class, which can be extended by custom type classes?
Also, because a factory creates objects, it's common practice to set it as static.
Example code snippet:
public static function getRequest($type='http')
{
switch ($type) {
case 'http':
return new HttpRequest();
case 'cli':
return new CliRequest();
case 'myCustom1':
return new MyCustom1();
case 'myCustom2':
return new MyCustom2();
default:
throw new Exception("Invalid request type: $type");
}
}
$request = RequestFactory::getRequest($type);
// As long as all objects in factory have access to same methods
$request->doSomething();
$request->andDoSomethingElse();
// Otherwise you end up with that feared 'unable to call function on non-object'
$request->iAmASneakyMethodNotEnforcedByAnInterfaceOrAvailableByExtension();
This is pretty subjective, so the following is just one opinion:
I wouldn't be quick to use something like this. If you only have a handful of classes that the factory will ever care about, then I'd just hard code them. But if you have a large set of these, I think it can be appropriate.
Given that you are validating that the class extends the appropriate interface, I would say that there is nothing wrong with what you are doing because it is fail-safe. The code using that factory method will appear clean; I think that's the most important thing.
If you were making use of such techniques all over the place, then I would argue against it. But since this is hidden away in the implementation, I think you can have more leeway with doing slightly inappropriate things.
Why not use a dispatch array? i.e.
class RequestFactory
{
private static $requests = array(
'http' => 'HttpRequest',
'cli' => 'CliRequest',
'summatelse' => 'Summat'
);
public static GetRequest($type)
{
if (array_key_exists($type, $requests)) return new $requests[$type];
else throw new Exception("Invalid request type: $type");
}
}
Related
I'm a bit lost here because I want to do something that is very easy in Java but seems a bit complicated in PHP.
We are building an SDK for our product and in Java, we have this one class that must not (!) be instantiated by the user (i.e. the coder), since there are several constraints regarding it's integrity. So we've built that as a nested class "X" inside of the "XFactory" and you will get an instance of X by calling XFactory.buildMeMyX(); - Easy...
Now PHP does not support nested classes at all, and I wonder how to apply the same here. In Java, X's constructor is hidden (private), so only XFactory can call it.
In PHP, it looks like I will have to make __construct() public and move the nested class X out of XFactory. Hence, the user will be able to create an instance without the Factory.
Now - I COULD move the factory functionality to X itself and move all the stuff there, but this would kind of break the design of the SDK. Is there a useful way to do such things in PHP after all?
For PHP 5.x you already described your options, there are no private/protected classes or inner classes at all, so there is no further way to restrict instantiation.
However, with PHP 7 this is going to change.
There are still no nested classes (although we might get them in the future, see: https://stackoverflow.com/a/31454435/664108), but you could instantiate an anonymous class and only provide the consumer with its interface like this:
class XFactory
{
public function buildMeMyX()
{
return new class() implements XInterface {
public function doWhatEverAnXCanDo()
{
// X X X
}
// ...
};
}
}
interface XInterface
{
function doWhatEverAnXCanDo();
}
As the others have said, there currently is no clean way to implement this behavior in PHP. In my opinion, the only valid use case for private constructors are factories inside the class that implement that factories.
Whenever you try to get around that use case it gets messy. No one should ever try to invent clever ways to bypass PHP's language limiations.
I just violated that rule by myself just to prove it is indeed possible. But please refrain from using that in production, or better: using it anywhere. I will try to find some bulletproof arguments for that suggestion and edit the answer afterwards.
<?php
class Dependency {}
class SomeClass {
protected $dep;
private function __construct(Dependency $dep)
{
$this->dep = $dep;
}
public function doSomething()
{
var_dump($this->dep);
echo "Doing Stuff and even having dependencies";
}
}
class SomeClassFactory {
public function buildSomeClass()
{
return $this->instantiateSomeClassWith(new Dependency);
}
protected function instantiateSomeClassWith()
{
$reflectionClass = new ReflectionClass('SomeClass');
$someClass = $reflectionClass->newInstanceWithoutConstructor();
$constructor = $reflectionClass->getConstructor();
$constructorClosure = $constructor->getClosure($someClass);
call_user_func_array($constructorClosure, func_get_args());
return $someClass;
}
}
$factory = new SomeClassFactory();
$someClass = $factory->buildSomeClass();
$someClass->doSomething();
?>
Output: object(Dependency)#2 (0) { } Doing Stuff and even having dependencies
The theory is simple. The constructor of the class that will be built via the Factory is made private. We make use of reflection within the factory to create an instance of the class without invoking the constructor.
Once we have an instance, we grab the closure of the constructor and invoke it via call_user_func_array(). That way you can make use of Dependency Injection just as you would if the constructor was public.
As I said before. That way is a single smell. By creating an object without invoking it's constructor, there is no real way to validate an objects state upon creation
This is a proof of concept, but the concept sucks.
There is no native way to do so, yet. However, if you really want to "enforce" that your class is only created from your factory class, there is a little "hackish" way to do so limiting the instantiation by inistantiating class.
class X
{
function __construct()
{
new Y();
}
}
class Y
{
function __construct()
{
$trace = debug_backtrace(DEBUG_BACKTRACE_PROVIDE_OBJECT, 2);
if (!isset($trace[1]['object']) || !($trace[1]['object'] instanceof X)) {
throw new \RuntimeException('This is a private class');
}
}
}
new X(); // All is fine
new Y(); // Exception
Please note that there is no "real" way to protect the class from being instantiated from elsewhere even using this approach - it still can be done via reflection by bypassing the constructor, or simply modifying your source.
I've been trying to grasp OOP concepts and while I do get the general ideas behind most of them, I often find myself in need of some advice regarding their practical implementation. One of such cases is the factory method.
I'm writing a PHP app that's going to handle requests incoming from both web and command-line interface, so I came up with the following simple class inheritance structure to cover both types of requests:
abstract class Request {
}
class HttpRequest extends Request {
}
class CliRequest extends Request {
}
Now I need a factory method that would return a concrete Request instance, depending on the value returned by php_sapi_name():
public function create() {
if(php_sapi_name() === 'cli')
return new CliRequest();
else
return new HttpRequest();
}
My question is: where do I put it? I can think of at least three possibilities:
1) Static method in a separate class:
class RequestFactory {
public static function create() {
// ...
}
}
2) Regular method in a separate class (would require instantiating the class first):
class RequestFactory {
public function create() {
// ...
}
}
3) Static method in the abstract parent class:
abstract class Request {
public static function create() {
// ...
}
}
What are the pros and cons of each solution and which would be considered "proper" and why?
All these possibilities will work as expected. I don't really get any "cons" as it fulfils, what is IMHO, your encapsulation objective.
Now, let's look at Factory Method pattern essence:
Define an interface for creating an object, but let the classes that
implement the interface decide which class to instantiate. The Factory
method lets a class defer instantiation to subclasses.
I'm not sure if what you're willing to do perfectly matches this definition.
Instead, it looks like you want to implement something called "Simple Factory" in which instantiation process is encapsulated into a class.
But having this kind of method directly into the abstract class that defines the interface of your "Request" objects doesn't look like a bad idea.
As Nicolas said, it's a rather common pattern in Java, C#, and Cocoa lands.
For these reasons, my choice would go to 3rd option
So, I have an idea, to do what I think you want, using method overloading.
class Request {
private $request;
private $valid = true;
private $type;
private $vars;
private $methods;
public function __construct() {
$this->type = php_sapi_name() === 'cli' ? 'cli' : 'http';
if($this->is_cli()) $this->request = new CliRequest();
else if($this->is_http()) $this->request = new HttpRequest();
else {
$this->valid = false;
return;
}
$this->vars = get_class_vars($this->request);
$this->methods = get_class_methods($this->request);
}
public function __get( $var ){
if(!$this->valid) return false;
if(!in_array($var, $this->vars)) return false;
return $this->request->$var;
}
public function __set( $var , $val ){
if(!$this->valid) return false;
if(!in_array($var, $this->vars)) return false;
return $this->request->$var = $val;
}
public function __call( $meth, $args ){
if(!$this->valid) return false;
if(!in_array($meth, $this->methods)) return false;
return call_user_func_array($this->request->$var, $args);
}
public function is_cli( ){
return $this->type == 'cli';
}
public function is_http( ){
return $this->type == 'http';
}
}
// Then, when calling the function...
$request = new Request;
$request->variable; // will get the variable from the Cli or Http request class
$request->method("a","b","c"); // Will run the method from the Cli or Http request class
To create truely loosely coupled code you could use Ray.Di or Injektor and do something similar to the following:
<?php
use Ray\Di\Di\Inject;
use Ray\Di\Di\Scope;
/**
* #Scope("Singleton")
*/
abstract class Request {
}
class HttpRequest extends Request {
}
class CliRequest extends Request {
}
class ARequestConsumer {
/* #var Request */
private $request;
public function __construct( Request $request )
{
$this->request = $request;
}
public function foo()
{
//...
}
}
class Global extends Ray\Di\AbstractModule {
public function configure()
{
$this->bind( 'Request' )
->toProvider( 'RequestProvider' );
}
}
class RequestProvider implements \Ray\Di\ProviderInterface {
/**
* #return Request
*/
public function get()
{
//.. factory method logic goes here that produces a concrete instance of Request
}
}
$injector = Injector::create([new Global]);
$consumer = $injector->getInstance('ARequestConsumer');
$consumer->foo();
Using a static method in the parent class doesn't seem an awful solution to me at all.
Take a look at the Calendar class in Java: There's a getInstance method (many actually) which return a Calendar instance depending on your Locale, and some others criteria.
In this case I rather use the Base Abstract class as the creator of the Instance using the static method (3rd Option)
I will use an external class, like in the first option when I need to create some dependencies that Can break the encapsulation like having different dependencies for different implementations. and will turn the class less maintainable.
Design patterns are not restricted to OOP and a lot of implementations of OOP design patterns are written with some memory management in thought.
I come from the Java world and in Java you would have to use a strict OOP design pattern. Simply because everything in Java is an object. Sometimes you must create an object and a method even if it is actually not needed for the pattern itself. The factory method design pattern is such an example.
It is very good to design by interface for the implementations of the factory, but you don't need a class and method to implement the factory.
The reason that an implementation of a design pattern is sometimes confusing is that the programming language sometimes requires an implementation that is not strictly needed in the design pattern itself. The creation of a class with a method in the factory method is such an example.
My solution is not purely OOP, but PHP is that not too and in the long run is it not about OOP in my opinion, but about the best implementation of the design pattern factory method.
I think that the elegancy of PHP is that it combines best of both worlds. It delivers a solid OOP design possibility, yet it has not thrown away the good elements of procedural programming.
You can simply create code like this:
function createRequest($pRequesttype){
switch($pRequesttype){
case "cli":
$tmp = new CliRequest();
break;
case "http":
$tmp = new HttpRequest();
break;
default:
$tmp = new DefaultRequest();
}
return $tmp;
}
Always return a default implementation to handle the request.
A switch statement is the best choice to extend the number of choices in a software engineer friendly way.
Now have you the call php_sapi_name in your create function. I advice you to get it out the implementation of the function. It is best practice to let a function do one job only and getting the request and handling the request are two functions. Make a createRequest function that has a parameter like I showed you.
To answer your question:
1, 2 or 3? Uh, 4 actually. :-) If 1, 2 or 3?
Definitely 1, because I don't want to load too much classes for a simple method, but to simplify this situation I have proposed solution 4.
I would not use method 2, because it is not efficient to create a class for one moment in time. I would consider it best practice, but not the best practical implementation. If using this solution, then please also support the class with an interface for factories in general. Best OOP design, but not best practical implementation.
I would certainly not use method 3, because abstract classes are there to abstract data objects and interfaces to abstract behaviour. A factory method is an abstraction of an interface, never of an abstract class.
I have a DataMapperFactory and I think I am doing it correctly and it makes sense to have one but I have a DomainObjectFactory too but it just seems pointless. This is it:
namespace libs\factories;
use models as Models;
class DomainObjectFactory {
public function build($name) {
$className = 'Models\\' . $name;
return new className();
}
}
The only advantage I can see of this is that I am keeping the new operator from being present all over my code.
There has to be more to a DomainObjectFactory than this right?
Any help would be great thanks.
There are there major reasons to use factories:
1. Abstract the creation of object
This is one of the most useful structures in your architecture when it comes to unit testing. Having a factory be responsible for the creation of instance makes easier to introduce mocks when testing.
Also, as added benefit, your is not anymore tightly coupled to the name of the classes that you utilize.
2. Simplify instantiation
Here you have two aspect that you have to consider. First - the ability to instantiate different objects based on some condition - was already quite well described in helmbert's answer (+1 for him).
The other case is when you are instantiating domain objects, which more complex.
Something like this:
$employees = new EmployeeCollection;
$address = new Location;
$class = $type . `Company`;
$company = new $class( $employee, $address );
There is quite a lot to do before you can create an instance of HoldingCompany. But this whole process can be done withing the factory. Especially if your domain object factory makes a good use of correctly implemented DIC (which is quite rare, btw).
3. Prepare objects before they are released in the application
You should never do any computation in the constructor. It make impossible to test that code. Constructors should only contains simple variable assignments.
But this introduces an issue: sometimes you need to do few logical operations, before you can let other code structures to deal with your instantiated object. As beginners we usually do that in the constructor. But where to put it now?
This is where factories come to the rescue.
public function create( $name )
{
$instance = new $name;
if ( is_callable($instance, false, 'prepare') )
{
$instance->prepare();
}
return $instance;
}
Now, when you use $factory->create('foobar'), your object is fully primed to be used.
In general, you can use the factory to abstract from specific implementations. If you use the new <classname> operator, you instantiate a specific class every time. If you want to interchange this class with another implementation at a later time, you will have to manually change every new statement.
The factory pattern allows you to abstract from specific classes. A valid minimal use case might be something like this:
interface UserInterface {
public function getName();
}
class UserImplementationA implements UserInterface {
private $name;
public function getName() { return $this->name; }
}
class UserImplementationB implements UserInterface {
public function getName() { return "Fritz"; }
}
class UserFactory {
public function createUser() {
if (/* some condition */) return new UserImplementationA();
else return new UserImplementationB();
}
}
$f = new UserFactory();
$u = $f->createUser(); // At this point, you don't really have to care
// whether $u is an UserImplementationA or
// UserImplementationB, you can just treat it as
// an instance of UserInterface.
One use case (of many) when this becomes extremely useful is when working with unit tests. In Test-Driven Development, you often replace dependencies of classes with mock objects (objects that implement a certain interface, but don't really do anything). Using the factory pattern, it is quite easy to transparently substitute specific classes with mock classes.
public function build($name) {
$className = 'Models\\' . $name;
return new $className();
}
That would work for you.
Defining object factories is a good practice, when you would like to set some default properties to objects, and also, you will not have to worry in what namespace or directory some class exists.
Example:
public function createButton($name){
require("home/lib/display/Button.php") ;
$button = new Button($name, "some default param") ;
$button->visible = true ;
return $button ;
}
You just make default objects so quickly via such factories, besides keeping word new away.
I saw this code on a different question - 2nd answer link and the first comment was that it is a static factory anti-pattern and that it violates SRP:
class User {
public static function create($userid) {
// get user from the database
// set $isPartner to true or false
// set $isClient to true or false
// set $isModerator to true or false
if ($isPartner) {
return new Partner($userid);
} elseif ($isClient) {
return new Client($userid);
} elseif ($isModerator) {
return new Moderator($userid);
} else {
return new User($userid);
}
}
}
$person = User::create($userid);
Now I can understand why it violates SRP - because it deals with connecting to the database as well as building the new class, but besides that I'm not sure if I understand why it is an anti-pattern.
I wanted to write a bit of code that seemed quite similar to this so I am now wondering whether to avoid it, this is my code (in pseudo-code):
class DatabaseClass()
{
...deals with getting a result from the database...
}
abstract class User()
{
...base class for all users...
}
class AdminUser extends User(){}
class StaffUser extends User(){}
class BasicUser extends User(){}
class UserFactory()
{
function createUser($privilege)
{
if($privilege=="high")
return new AdminUser($privilege);
else if($privilege=="med")
return new StaffUser($privilege);
else
return new BasicUser($privilege);
}
$db=new DatabaseClass($username,$password);
$result=$db->getUser();
$userfactory=new UserFactory();
$user=$userfactory->createUser($result);
Now at the moment I am not using a static method but would my oop still be considered an anti-pattern?
Especially since I don't really see any difference in then doing something like this instead and it being pretty much the same thing:
$result=DatabaseClass::getUser($username,$password);
$user=UserFactory::createUser($result);
No, it's not an anti-pattern. Personally, I take the term "anti-pattern" with a grain of salt whenever I see it. It's far too easily tossed around by people who don't like your code but can't really articulate why.
The problem with a static factory is that any class which uses the factory must explicitly depend on it. That violates the principle that we should depend on abstractions rather than concretions (the 'D' in SOLID). This makes code using the factory harder to re-use and unit test. But keep in mind that the approach has benefits too. It's easier to write and easier to understand.
Your code is equivalent to a static factory method. The problem in both cases is that the caller must know the concrete class of the factory.
Your factory is not the issue, is the conection to the db i guess.
Other than that, you're using the factory method well.
Upon seen the edit, its for the best that you separate the data access from the factory.
It's not so much an "anti-pattern" as a bad idea from the maintenance perspective.
I would still be ok (not so good but still ok) if you had your data access code inside the factory as long as that code was in a separate class (that is reused across the application for data access) and you just call it to get something you need. In that case it'd be a combination of two patterns, a factory and a facade.
What i'd really pay attenntion to is to find out if the data isn't going to change during the session, if so just go one time to the db an keep the results. If you only create the User (or derived classes) once, make damm sure you only do it once.
That i think is more important that respecting patterns blindly.
PHP has functionality of dynamical class instantiation where class name that should be instantiated could be a variable. The following code works fine:
$classname='User';
$Object=new $classname; //instantiates new User()
This code instantiates that class whose name is stored in $classname variable.
I'm not so well with the Factory Pattern, however, if you want to have some benefit, it could abstract the creation based on persistence variation, e.g. if it's adapting the database for users or not.
class DatabaseUserFactory implements UserFactory
{
private $dbClass;
function __construct(DatabaseClass $dbClass)
{
$this->dbClass = $dbClass;
}
/**
* #return user
*/
function createUser()
{
$result = $db->getUser();
return $this->createUserByPrivilege($result->getPrivilege());
}
private function createUserByPrivilege($privilege)
{
if ($privilege == "high")
return new AdminUser($privilege);
else if ($privilege == "med")
return new StaffUser($privilege);
else
return new BasicUser($privilege);
}
}
$db = new DatabaseClass($username, $password);
$userfactory = new DatabaseUserFactory($db);
// ...
$user = $userfactory->createUser();
Using php 5.2, I'm trying to use a factory to return a service to the controller. My request uri would be of the format www.mydomain.com/service/method/param1/param2/etc. My controller would then call a service factory using the token sent in the uri. From what I've seen, there are two main routes I could go with my factory.
Single method:
class ServiceFactory {
public static function getInstance($token) {
switch($token) {
case 'location':
return new StaticPageTemplateService('location');
break;
case 'product':
return new DynamicPageTemplateService('product');
break;
case 'user'
return new UserService();
break;
default:
return new StaticPageTemplateService($token);
}
}
}
or multiple methods:
class ServiceFactory {
public static function getLocationService() {
return new StaticPageTemplateService('location');
}
public static function getProductService() {
return new DynamicPageTemplateService('product');
}
public static function getUserService() {
return new UserService();
}
public static function getDefaultService($token) {
return new StaticPageTemplateService($token);
}
}
So, given this, I will have a handful of generic services in which I will pass that token (for example, StaticPageTemplateService and DynamicPageTemplateService) that will probably implement another factory method just like this to grab templates, domain objects, etc. And some that will be specific services (for example, UserService) which will be 1:1 to that token and not reused. So, this seems to be an ok approach (please give suggestions if it is not) for a small amount of services. But what about when, over time and my site grows, I end up with 100s of possibilities. This no longer seems like a good approach. Am I just way off to begin with or is there another design pattern that would be a better fit? Thanks.
UPDATE: #JSprang - the token is actually sent in the uri like mydomain.com/location would want a service specific to loction and mydomain.com/news would want a service specific to news. Now, for a lot of these, the service will be generic. For instance, a lot of pages will call a StaticTemplatePageService in which the token is passed in to the service. That service in turn will grab the "location" template or "links" template and just spit it back out. Some will need DynamicTemplatePageService in which the token gets passed in, like "news" and that service will grab a NewsDomainObject, determine how to present it and spit that back out. Others, like "user" will be specific to a UserService in which it will have methods like Login, Logout, etc. So basically, the token will be used to determine which service is needed AND if it is generic service, that token will be passed to that service. Maybe token isn't the correct terminology but I hope you get the purpose.
I wanted to use the factory so I can easily swap out which Service I need in case my needs change. I just worry that after the site grows larger (both pages and functionality) that the factory will become rather bloated. But I'm starting to feel like I just can't get away from storing the mappings in an array (like Stephen's solution). That just doesn't feel OOP to me and I was hoping to find something more elegant.
I think there is no way to avoid this token-service-mapping maintaining work when your site growing large. No matter how you implement this list, switch block, array, etc. this file will become huge someday. So my opinion is to avoid this list and make each token a service class, for those generic services, you can inherit them, like this
class LocationService extends StaticPageTemplateService {
public function __construct(){
parent::__construct('location');
}
}
class ServiceFactory {
public static function getInstance($token) {
$className = $token.'Service';
if(class_exist($className)) return new $className();
else return new StaticPageTemplateService($token);
}
}
in this way, you can avoid to edit the factory class file each time a token added or changed, you just need to change the specific token file.
I have a better factory pattern solution that will allow you to add new services without doing anything more than creating a new class for that specific service. Outlined below:
For the Factory:
class ServiceFactory{
private static $instance = null;
private static $services = array();
private function __construct(){
// Do setup
// Maybe you want to add your default service to the $services array here
}
public function get_instance(){
if($this->instance){
return $this->instance;
}
return $this->__construct();
}
public function register_service($serviceName, $service){
$this->services[$serviceName] = $service;
}
public function get_service($serviceName){
return $this->services[$serviceName]->get_new();
}
}
An Abstract Service:
include('ServiceFactory.php');
class AbstractService{
public function __construct($serviceName){
$factory = ServiceFactory::get_instance();
$factory->register_service($serviceName, $this);
}
public function get_new(){
return new __CLASS__;
}
}
And then a concrete service:
include('AbstractService.php');
class ConcreteService extends AbstractService{
// All your service specific code.
}
This solution makes your dependencies one way and you can add new services by simply extending the AbstractService, no need to modify any existing code. You call into the factory with the get_service('news') or whichever you want, the factory looks up the associated object in its $services array and calls the get_new() function on that particular object which gets you a new instance of the specific service to work with.
I'm not a PHP developer, so I'm not going to attempt to show any code, but here's what I would do. I would implement the Strategy Pattern and create an IServiceProvider interface. That interface could have a GetService() method. Then you would create four new objects: LocationService, ProductService, UserService, and DefaultService, all of which would implement the IServiceProvider interface.
Now, in your factory, the constructor would take in a IServiceProvider and have one public GetService() method. When the method is called, it will use the strategy of the injected IServiceProvider. This improves extensability as you won't have to open the Factory everytime you have a new service, you would just create a new class that implements IServiceProvider.
I decided quick to mock this up quick in C# so you would have an example. I understand this isn't the language you are using, but maybe it will help clarify what I'm saying. Code shown below.
public interface IServiceProvider
{
Service GetService();
}
public class UserServiceProvider : IServiceProvider
{
public Service GetService()
{
//perform code to get & return the service
}
}
public class StaticPageTemplateServiceProvider : IServiceProvider
{
public Service GetService()
{
//perform code to get & return the service
}
}
public class DynamicPageTemplateServiceProvider : IServiceProvider
{
public Service GetService()
{
//perform code to get & return the service
}
}
public class DefaultServiceProvider : IServiceProvider
{
public Service GetService()
{
//perform code to get & return the service
}
}
public class ServiceFactory
{
public ServiceFactory(IServiceProvider serviceProvider)
{
provider = serviceProvider;
}
private IServiceProvider provider;
public Service GetService()
{
return provider.GetService();
}
}
Service factory implementation (with an interface that we'll use in concrete classes):
class ServiceFactory
{
private static $BASE_PATH = './dirname/';
private $m_aServices;
function __construct()
{
$this->m_aServices = array();
$h = opendir(ServiceFactory::$BASE_PATH);
while(false !== ($file = readdir($h)))
{
if($file != '.' && $file != '..')
{
require_once(ServiceFactory::$BASE_PATH.$file);
$class_name = substr($file, 0, strrpos($file, '.'));
$tokens = call_user_func(array($class_name, 'get_tokens'));
foreach($tokens as &$token)
{
$this->m_aServices[$token] = $class_name;
}
}
}
}
public function getInstance($token)
{
if(isset($this->m_aServices[$token]))
{
return new $this->m_aServices[$token]();
}
return null;
}
}
interface IService
{
public static function get_tokens();
}
$BASE_PATH.'UserService.php':
class UserService implements IService
{
function __construct()
{
echo '__construct()';
}
public static function get_tokens()
{
return array('user', 'some_other');
}
}
So, what we're doing essentially is self-registering all tokens for any concrete class implementation. As long as your classes reside in $BASE_PATH, they'll automatically be loaded by the ServiceFactory when it's instantiated (of course, you could change ServiceFactory to provide this via static methods if you wanted to).
No need to have a big switch statement providing access to concrete implementations as they're all help in an internal map that's built by the get_tokens() function that are implemented at the concrete class level. The token->class relationship is stored in a 1:1 map within the service factory, so you'd need to refactor this if you're chaining tokens for whatever reason.
Here's how I do a singleton factory (comments removed for brevity):
Updated to better serve your purpose.
class ServiceFactory {
private static $instance;
private function __construct() {
// private constructor
}
public function __clone() {
trigger_error('Clone is not allowed.', E_USER_ERROR);
}
public static function init() {
if (!isset(self::$instance)) {
$c = __CLASS__;
self::$instance = new $c;
}
return self::$instance;
}
public function get_service($name, $parameter) {
$name .= 'TemplateService';
return $this->make_service($name, $parameter);
}
private function make_service($name, $parameter) {
if (class_exists($name)) {
return new $name($parameter);
} else {
throw new LogicException('Could not create requested service');
return false;
}
}
}
In it's simplest form like this, just pass a string name of the service:
function whatever() {
$ServiceFactory = ServiceFactory::init();
$new_service = $ServiceFactory->get_service('StaticPage', 'location');
return $new_service;
}
And some that will be specific services (for example, UserService) which will be 1:1 to that token and not reused. So, this
seems to be an ok approach (please give suggestions if it is not) for a small amount of services. But what about when, over
time and my site grows, I end up with 100s of possibilities. This no longer seems like a good approach. Am I just way off
to begin with or is there another design pattern that would be a better fit? Thanks.
Sorry to say, but I think you're now trying to solving a problem that you've created for yourself.
the token is actually sent in the uri like mydomain.com/location would want a service specific to
loction and mydomain.com/news would want a service specific to news. Now, for a lot of these, the
service will be generic. For instance, a lot of pages will call a StaticTemplatePageService in which
the token is passed in to the service. That service in turn will grab the "location" template or
"links" template and just spit it back out.
Some have already suggested using a Dependency Injection Container to solve the whole factory issue, but I wonder why there is a need for a factory in the first place? You seem to be writing a Controller (I guess), that can generate a response for a multitude of different types of request, and you're trying to solve it all in one class. I'd instead make sure that the different requests (/location, /news) map to dedicated, small, readable controllers (LocationController, NewsController). As one controller needs only one service this should be much easier to write, maintain and expand.
That way, you solve the dependencies in dedicated, concise, readable classes instead of one giant God class. That means you'll have no issues with a switch of hundreds of lines either, you should just map "location" to LocationController, "news" to NewsController, etc. A lot of PHP frameworks these days use a FrontController for that, and I imagine that is the way to go for you as well.
PS: to make sure the NewsService actually makes into the NewsController, I would suggest using a dependency injection container. It makes your life easier ;)