// Abstract Factory
/*
({}).createInstance()
(function (a, b, c) {
this.sum = a + b + c;
}).createInstance([1, 2, 3])
*/
Object.defineProperty(
// (C) WebReflection - Mit Style License
Object.prototype,
"createInstance",
{
value: (function (create) {
return function createInstance(args) {
var
self = this,
isFunction = typeof self == "function",
obj = create(isFunction ? self.prototype : self)
;
isFunction && args != null && self.apply(obj, args);
return obj;
};
}(Object.create))
}
);
// Abstract Builder
/*
var person = Object.builder({
setup: function (name) {
this.create();
this.instance.name = name;
}
});
person.setup("WebReflection");
alert(person.instance.name);
person.create();
person.instance.name = "Andrea";
alert(person.instance.name);
*/
Object.defineProperty(
// (C) WebReflection - Mit Style License
Function.prototype,
"builder",
{
value: function (methods) {
var
$create = Object.create,
self = this,
proto = self.prototype,
obj
;
return $create(methods, {
instance: {
get: function get() {
return obj;
}
},
create: {
value: function create() {
obj = $create(proto);
self.apply(obj, arguments);
}
}
});
}
}
);
// Multiton + Singleton pattern
// (via lazy initialization)
/*
function Car(){}
var car = Car.getInstance();
alert(car === Car.getInstance());
alert(car !== Car.getInstance("bmw"));
alert(Car.getInstance("bmw") === Car.getInstance("bmw"));
*/
Object.defineProperty(
// (C) WebReflection - Mit Style License
Function.prototype,
"getInstance",
{
value: function (key) {
var
create = Object.create,
instances = {},
self = this,
proto = self.prototype,
instance
;
Object.defineProperty(
self,
"getInstance",
{
value: function getInstance(key) {
return key == null ?
instance || (instance = create(proto)) :
instances.hasOwnProperty(key) ?
instances[key] :
instances[key] = create(proto)
;
}
}
);
return self.getInstance(key);
}
}
);
// Prototype
/*
var definition = {some:"thing"};
var inherited = Object.create(definition);
*/
Object.create;
// Abstract Adapter
/*
function Person() {}
Person.prototype.setName = function setName(_name) {
this._name = _name;
};
var getter = {
toString: function () {
return this._name;
}
};
var me = {};
me.adapt(Person);
me.setName("WebReflection");
me.adapt(getter);
alert(me);
*/
Object.defineProperty(
// (C) WebReflection - Mit Style License
Object.prototype,
"adapt",
{
value: (function (proto) {
return proto in {} ?
function adapt(Class) {
this[proto] = typeof Class == "function" ? Class.prototype : Class;
} :
function adapt(Class) {
var self = this;
typeof Class == "function" && Class = Class.prototype;
for (proto in Class)
self.hasOwnProperty(proto) || (self[proto] = Class[proto])
;
}
;
}("__proto__"))
}
);
// Abstract Composite
/*
function AddToBody(value) {
this.value = value;
}
AddToBody.prototype.value = "";
AddToBody.prototype.exec = function () {
document.body.appendChild(
document.createElement("p")
).innerHTML = this.value;
};
var many = AddToBody.composite();
many.push(
new AddToBody("this"),
new AddToBody("is"),
new AddToBody("a"),
new AddToBody("test")
);
this.onload = function () {
many.exec();
alert(many.value);
many.value = "everybody like this";
many.exec();
alert(many.value);
};
*/
Object.defineProperty(
// (C) WebReflection - Mit Style License
Function.prototype,
"composite",
{
value: (function (defineProperty) {
return function composite() {
function get(key) {
function retrieve(item) {
return item[key];
}
return function get() {
return map.call(this, retrieve);
};
}
function set(key) {
function assign(item) {
item[key] = this;
}
return function set(value) {
forEach.call(this, assign, value);
};
}
function wrap(method) {
function apply(item) {
method.apply(item, this);
}
return function wrap() {
forEach.call(this, apply, arguments);
};
}
var
composite = [],
forEach = composite.forEach,
map = composite.map,
proto = this.prototype,
key, value
;
for (key in proto) {
if (typeof(value = proto[key]) == "function") {
composite[key] = wrap(value);
} else {
defineProperty(
composite,
key,
{
get: get(key),
set: set(key)
}
);
}
}
return composite;
};
}(Object.defineProperty))
}
);
// Observer/Listener
/*
function hello(e) {
alert(e.type);
}
var obj = new Listener;
obj.addEvent("hello", hello);
obj.addEvent("hello", hello);
obj.fireEvent("hello");
obj.fireEvent({type:"hello"});
obj.removeEvent("hello", hello);
obj.fireEvent({type:"hello"});
*/
var Listener = (function () {
// (C) WebReflection - Mit Style License
function Listener() {
handler.value = {};
defineProperty(this, "_handler", handler);
}
function fire(callback) {
callback.call(this.target, this);
}
var
proto = Listener.prototype
defineProperty = Object.defineProperty,
handler = {
value: proto
},
empty = []
;
Object.defineProperties(
Listener.prototype,
{
addEvent: {
value: function addEvent(type, callback) {
var stack = this._handler[type] || (this._handler[type] = []);
stack.indexOf(callback) < 0 && stack.push(callback);
}
},
removeEvent: {
value: function removeEvent(type, callback) {
var
stack = this._handler[type] || empty,
i = stack.indexOf(callback)
;
-1 < i && stack.splice(i, 1);
}
},
fireEvent: {
value: function fireEvent(e) {
typeof e == "string" && (e = {type: e});
e.target = this;
(this._handler[e.type] || empty).forEach(fire, e);
}
}
}
);
return Listener;
}());
behind the design
My JavaScript book is out!
Don't miss the opportunity to upgrade your beginner or average dev skills.
Showing posts with label Singleton. Show all posts
Showing posts with label Singleton. Show all posts
Monday, December 27, 2010
ES5 Common Design Patterns Examples - Part 1
Wednesday, September 02, 2009
PHP 5.3 Singleton - Fast And Abstract
In this same blog I talked different times about Singleton Pattern, in latter link "poorly" implemented in PHP 5.
I say poorly, because being Singleton a pattern, there are many ways to implement it and via PHP 5.3 things are more interesting.
There are several ways to define a Singleton class and to extend it, being able to automatically create another one that will follow that pattern.
Here is my implementation, which is extremely fast, logic, and simple as well.
static is a magic keywords able to open hundreds of closed doors with old PHP versions. Thanks to this keyword it is possible to avoid a lot of redundant code, being sure that when static is called, it will be the current class call and not the one where self has been used. Thanks to this keyword is then possible to refer directly the current class instance, the one that will extend pattern\Singleton, using its own init method if preset, the empty abstract inherited otherwise.
Above test case will produce exatly this output:
assuming the file autoload.php is present in the same level:
The reason I posted about my own PHP 5.3 implementation is a php mailing list discussion which pointed to another extended Singleton for PHP 5.3.
That implementation will perform for each getInstance() call a callback which aim is to discover the class caller, get_called_class(), plus 2 up to 3 lookups plus an assignment over a static associative array, self::$instance[$class].
Finally, even if it could not make sense, extended Singleton classes cannot access to their own Singleton instances, aka: less control and overhead being Singleton a truly common pattern.
At least you know there is an alternative which aim is to let us remember that a singleton is a unique instance, the one we need to define as protected $INSTANCE, and that performances are always welcome, at least in my daily code/life style.
Enjoy!
I say poorly, because being Singleton a pattern, there are many ways to implement it and via PHP 5.3 things are more interesting.
There are several ways to define a Singleton class and to extend it, being able to automatically create another one that will follow that pattern.
Here is my implementation, which is extremely fast, logic, and simple as well.
<?php // Singleton :: The WebReflection Way
namespace pattern;
// this is just a pattern ...
// so no new Singleton is allowed
// thanks ot abstract definition
abstract class Singleton {
// note, no static $INSTANCE declaration
// this makes next declaration a must have
// for any extended class
// protected static $INSTANCE;
// @constructor
final private function __construct() {
// if called twice ....
if(isset(static::$INSTANCE))
// throws an Exception
throw new Exception("An instance of ".get_called_class()." already exists.");
// init method via magic static keyword ($this injected)
static::init();
}
// no clone allowed, both internally and externally
final private function __clone() {
throw new Exception("An instance of ".get_called_class()." cannot be cloned.");
}
// the common sense method to retrieve the instance
final public static function getInstance() {
// ternary operator is that fast!
return isset(static::$INSTANCE) ? static::$INSTANCE : static::$INSTANCE = new static;
}
// by default there must be an inherited init method
// so an extended class could simply
// specify its own init
protected function init(){}
}
?>
The static Trick
static is a magic keywords able to open hundreds of closed doors with old PHP versions. Thanks to this keyword it is possible to avoid a lot of redundant code, being sure that when static is called, it will be the current class call and not the one where self has been used. Thanks to this keyword is then possible to refer directly the current class instance, the one that will extend pattern\Singleton, using its own init method if preset, the empty abstract inherited otherwise.
Example
<?php
// for this test only, this class
// is in the root, same level of autoload.php
// include basic stuff ...
require_once 'autoload.php';
// define a singleton class
class SingA extends pattern\Singleton {
// my Singleton requires a
// protected static $INSTANCE variable
// if not present, nothing will
// be executed - Fatal error
protected static $INSTANCE;
// let's define something else
protected $a = 'A';
protected $b;
// let's try the init method
protected function init(){
// assign a random value to b
$this->b = rand();
}
}
// define another singleton class
class SingB extends pattern\Singleton {
protected static $INSTANCE;
}
// let's try the Singleton
$sa = SingA::getInstance();
$sb = SingB::getInstance();
$sb->runTime = 'here I am';
$sa2 = SingA::getInstance();
echo '<pre>',
var_dump($sa),
var_dump($sb),
var_dump($sa2),
var_dump($sa === $sa2),
var_dump($sa !== $sb),
'</pre>'
;
?>
Above test case will produce exatly this output:
object(SingA)#2 (2) {
["a":protected]=>
string(1) "A"
["b":protected]=>
int(31994)
}
object(SingB)#3 (1) {
["runTime"]=>
string(9) "here I am"
}
object(SingA)#2 (2) {
["a":protected]=>
string(1) "A"
["b":protected]=>
int(31994)
}
bool(true)
bool(true)
assuming the file autoload.php is present in the same level:
<?php
// simple autoload function
spl_autoload_register(function($class){
// assuming this file is in the root
// (just as example)
require __DIR__.
DIRECTORY_SEPARATOR.
// fix namespace separator ...
str_replace(
'\\',
DIRECTORY_SEPARATOR,
$class
).
// add classes suffix
'.class.php'
;
});
// that's it
?>
Why This Is Faster, Why This Is Better
The reason I posted about my own PHP 5.3 implementation is a php mailing list discussion which pointed to another extended Singleton for PHP 5.3.
That implementation will perform for each getInstance() call a callback which aim is to discover the class caller, get_called_class(), plus 2 up to 3 lookups plus an assignment over a static associative array, self::$instance[$class].
Finally, even if it could not make sense, extended Singleton classes cannot access to their own Singleton instances, aka: less control and overhead being Singleton a truly common pattern.
At least you know there is an alternative which aim is to let us remember that a singleton is a unique instance, the one we need to define as protected $INSTANCE, and that performances are always welcome, at least in my daily code/life style.
Enjoy!
Thursday, June 19, 2008
A completely revisited Singleton and Factory design pattern for PHP and JavaScript
Singleton
From Wikipedia
In software engineering, the singleton pattern is a design pattern that is used to restrict instantiation of a class to one object. This is useful when exactly one object is needed to coordinate actions across the system. Sometimes it is generalized to systems that operate more efficiently when only one or a few objects exist. It is also considered an anti-pattern by some people, who feel that it is often used as a euphemism for global variable
Basically, the last point is true.
Whatever we think about Singleton, we cannot say that we do not use this pattern to have the same instance, or object, in every place of our application.
The most common case scenario, is usually a database object, or a global queue, used as a stack, or something similar, like a template engine instance or a DOM / XML node.
The worst thing ever, is that with languages like PHP and JavaScript, the Singleton pattern is really hard to implement correctly.
Why bother with a class?
In a lot of frameworks, as in a lot of libraries, I have seen every kind of Singleton implementation, and most of them, are conceptually hilarious.
// PHP Singleton classic example
Singleton::load('MyCLassName');
MyClassName::getInstance();
// JavaSript classic example
MyConstructor.getInstance();
// where in different cases, getInstance
// is not even defined inside a closure
// to preserve singleton integrity ...
// ... but does exist a way to make
// a JS constructor private? NO
With PHP, problems are different:
- if there's no magic __clone method, it does not make sense
- if you serialize and unserialize objects, it could not make sense
- if you create a Singleton class, it is nearly impossible to extend correctly its behaviour (come on lazy binds and PHP 5.3!!!)
- if you try to create a __callStatic method, you simply have to wait next PHP release
In PHP again, as is for JavaScript, outside a closure, every static function is global.
This means that we do not need to use global something, in PHP, and we do not use, usually, window as prefix to use declared function.
It is true, the most horrible piece of code you can spot in an entire PHP application, is the usage of global keyword to transport variables everywhere.
We do not need that, and we can have a Singleton behaviour, simply using a function !!!
function Singleton($__CLASS__){
// webreflection.blogspot.com
static $list = array();
if(!isset($list[$__CLASS__])){
$arguments = func_get_args();
array_shift($arguments);
$instance = new ReflectionClass($__CLASS__);
$list[$__CLASS__] = $instance->getConstructor() ? $instance->newInstanceArgs($arguments) : $instance->newInstance();
}
return $list[$__CLASS__];
}
Is static variable private inside function scope? Yes
Is this function smarter than a public static method? Yes
class A {
protected $value = '123';
function write($what){
echo $what.$this->value;
return $this;
}
}
class B extends A {
function __construct($value){
$this->value = $value;
}
}
echo '', var_dump(Singleton('A') === Singleton('A')), '';
echo '', var_dump(';
Singleton('B', 'my value')->write('Hello World') === Singleton('B')
), '
// true, Hello Worldmy value, true
Do you really want a class?
Ok, somebody could thing that above function is pointless, so here there is a class that will use the same function.
class Singleton {
// webreflection.blogspot.com
private $_class,
$_instance;
public function __construct($__CLASS__){
$arguments = func_get_args();
$this->_class = new ReflectionClass($this->_instance = call_user_func_array('Singleton', $arguments));
}
public function __get($property){
return $this->_instance->$property;
}
public function __call($method, array $arguments){
return $this->_class->getMethod($method)->invokeArgs($this->_instance, $arguments);
}
public function __set($property, $value){
$this->_instance->$property = $value;
}
public function equal($_instance){
return $_instance instanceof Singleton ? $this->_instance === $_instance->_instance : $this->_instance === $_instance;
}
}
With above class, using the Singleton function as well, you can even use the new keyword to obtain every time the same instance.
$b = new Singleton('B', 'my value');
echo '', var_dump(';
$b->equal(Singleton('B')->write('Hello World')) &&
$b->equal(new Singleton('B'))
), '
Well, at this point we have the shortest way to obtain the same behaviour, using, or not, a class.
Factory
From Wikipedia
The Factory pattern is a creational design pattern used in software development to encapsulate the processes involved in the creation of objects.
The creation of an object often requires complex processes not appropriate to include within a composing object. The object's creation may lead to a significant duplication of code, may require information not accessible to the composing object, may not provide a sufficient level of abstraction, or may otherwise not be part of the composing object's concerns.
Specially in PHP, a Factory pattern is useful to avoid problems with new keyword when you create an object.
For example, this is not possible:
new Class("stuff")->doStuff();
With a Factory behaviour it is natural to do something like this:
Factory('Class')->doStuff();
In those case when we need an instance once, or few times, and never more, to do some super cool computation, we could avoid variable assignment and, in some case, use a function with the same class name as proposed few days ago.
But this time, using exactly the same concept of Singleton, it is even more simple to create a general purpose Factory function:
function Factory($__CLASS__){
// webreflection.blogspot.com
static $list = array();
if(!isset($list[$__CLASS__]))
$list[$__CLASS__] = new ReflectionClass($__CLASS__);
$arguments = func_get_args();
array_shift($arguments);
return $list[$__CLASS__]->getConstructor() ? $list[$__CLASS__]->newInstanceArgs($arguments) : $list[$__CLASS__]->newInstance();
}
Some example?
class A {
public function setName($name){
$this->name = $name;
return $this;
}
}
$me = Factory('A')->setName('Andrea');
echo $me->name; // Andrea
Not every consideration I did for Singleton pattern is true for Factory one, but the structure of the function, as the possible class, is about the same.
At this point, assuming that in my implementation Factory is an extended version of the Singleton, creating more instances than one, you can have a look into the complete source of my Factory and Singleton implementation.
Why there is JavaScript in this post topic?
The reaon is simple, everything I have done with PHP, is simply replicable with JavaScript, but this time, with only 8 lines of code:
// webreflection.blogspot.com
Factory = function(__CLASS__){
for(var i = 1, length = arguments.length, args = new Array(length - 1); i < length; i++)
args[i - 1] = "arguments[" + i + "]";
return Function("return new " + __CLASS__ + "(" + args.join(",") + ")").apply(null, arguments);
};
Singleton = function(list){return function(__CLASS__){
return __CLASS__ in list ? list[__CLASS__] : list[__CLASS__] = Factory.apply(null, arguments);
}}({});
Seems to be simple, isn't it? :geek:
Subscribe to:
Posts (Atom)