Skip to content

Commit 80d73c4

Browse files
author
Dominik Liebler
committed
added FluentInterface
2 parents 1f37ca3 + b025906 commit 80d73c4

File tree

7 files changed

+510
-4
lines changed

7 files changed

+510
-4
lines changed
Lines changed: 90 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,90 @@
1+
<?php
2+
3+
namespace DesignPatterns;
4+
5+
/**
6+
* chain of responsibilities pattern
7+
*
8+
* Purpose:
9+
* to build a chain of objects to handle a call. if one object cannot handle a call, it delegates the call to the next
10+
* in the chain and so forth
11+
*
12+
* Examples:
13+
* - Caching: first object is an instance of e.g. a Memcached Interface, if that "misses" it delegates the call to the
14+
* Database Interface
15+
*
16+
*/
17+
18+
interface KeyValueStorage
19+
{
20+
public function get($key);
21+
}
22+
23+
class SlowStorage implements KeyValueStorage
24+
{
25+
protected $_data = array();
26+
27+
public function __construct($data = array())
28+
{
29+
$this->_data = $data;
30+
}
31+
32+
/**
33+
* this class has no next handler, so it MUST be able to handle all requests
34+
*
35+
* @param $key
36+
* @return mixed
37+
*/
38+
public function get($key)
39+
{
40+
return $this->_data[$key];
41+
}
42+
}
43+
44+
class FastStorage implements KeyValueStorage
45+
{
46+
/**
47+
* @var array
48+
*/
49+
protected $_data;
50+
51+
/**
52+
* the next handler in the chain
53+
*
54+
* @var \DesignPatterns\KeyValueStorage
55+
*/
56+
protected $_nextHandler;
57+
58+
public function __construct(array $data, KeyValueStorage $nextHandler)
59+
{
60+
$this->_data = $data;
61+
$this->_nextHandler = $nextHandler;
62+
}
63+
64+
/**
65+
* when this storage gets a "miss", search in next handler
66+
*
67+
* @param $key
68+
* @return mixed
69+
*/
70+
public function get($key)
71+
{
72+
if (true /* miss */) {
73+
// delegate the call to the next handler in the chain
74+
return $this->_nextHandler->get($key);
75+
}
76+
}
77+
}
78+
79+
// BUILD THE STORAGES AND CHAIN
80+
81+
$slowStorage = new SlowStorage(array('foo' => 'bar'));
82+
$fastStorage = new FastStorage(array('bar' => 'baz'), $slowStorage);
83+
84+
$fastStorage->get('foo'); // will be handled by SlowStorage
85+
$fastStorage->get('bar'); // will be handled by FastStorage
86+
87+
/**
88+
* In this example we could also add a abstract class and extend it to build Fast- and SlowStorage. That class would
89+
* then manage the chain and when the cache hits a "miss", it would check if there is a next handler
90+
*/

Composite/Composite.php

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -6,13 +6,12 @@
66
* composite pattern
77
*
88
* Purpose:
9-
* to treat a group of objects the same way as a single instance of the object, it establishes 1-to-n relationships
10-
* between objects
9+
* to treat a group of objects the same way as a single instance of the object
1110
*
1211
* Example:
1312
* - a form class instance handles all its form elements like a single instance of the form, when render() is called, it
14-
* subsequently runs trough all its child elements and calls render() on them
15-
* - a class to process files would process it by running process on all row objects in the file
13+
* subsequently runs trough all its child elements and calls render() on them
14+
* - Zend_Config: a tree of configuration options, each one is a Zend_Config object
1615
*
1716
*/
1817
class Form

Decorator/Decorator.php

Lines changed: 84 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,84 @@
1+
<?php
2+
3+
namespace DesignPatterns;
4+
5+
/**
6+
* Decorator pattern
7+
*
8+
* Purpose:
9+
* to dynamically add new functionality to class instances
10+
*
11+
* Examples:
12+
* - Zend Framework: decorators for Zend_Form_Element instances
13+
* - Web Service Layer: Decorators JSON and XML for a REST service (in this case, only one of these should be allowed of
14+
* course)
15+
*
16+
*/
17+
class Webservice
18+
{
19+
protected $_data;
20+
21+
/**
22+
* an array to holds all added decorators, often there would be defaults set in this
23+
* array, e.g. the service could be defaulted to use JSON and only for special APIs
24+
* use XML
25+
*
26+
* @var array
27+
*/
28+
protected $_decorators = array();
29+
30+
public function __construct($data)
31+
{
32+
$this->_data = $data;
33+
}
34+
35+
/**
36+
*
37+
*
38+
* @param WebserviceDecorator $decorator
39+
* @return void
40+
*/
41+
public function addDecorator(WebserviceDecorator $decorator)
42+
{
43+
$this->_decorators[] = $decorator;
44+
}
45+
46+
/**
47+
* @return string
48+
*/
49+
public function renderData()
50+
{
51+
$response = '';
52+
foreach ($this->_decorators as $decorator) {
53+
$response = $decorator->renderData($this->_data);
54+
}
55+
56+
return $response;
57+
}
58+
}
59+
60+
interface WebserviceDecorator
61+
{
62+
public function renderData($data);
63+
}
64+
65+
class JsonDecorator implements WebserviceDecorator
66+
{
67+
public function renderData($data)
68+
{
69+
return json_encode($data);
70+
}
71+
}
72+
73+
class XmlDecorator implements WebserviceDecorator
74+
{
75+
public function renderData($data)
76+
{
77+
// do some fany conversion to xml from array ...
78+
return simplexml_load_string($data);
79+
}
80+
}
81+
82+
$service = new Webservice(array('foo' => 'bar'));
83+
$service->addDecorator(new JsonDecorator());
84+
echo $service->renderData();

FluentInterface/FluentInterface.php

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
<?php
2+
3+
namespace DesignPatterns;
4+
5+
/**
6+
* fluent interface pattern
7+
*
8+
* Purpose:
9+
* to write code that is easy readable just like "real" sentences
10+
*
11+
* Examples:
12+
* - Doctrine2's QueryBuilder works something like that example class below
13+
* - PHPUnit uses fluent interfaces to build mock objects
14+
*
15+
*/
16+
class SQL
17+
{
18+
protected $_fields = array();
19+
protected $_from = array();
20+
protected $_where = array();
21+
22+
/**
23+
*
24+
* @param array $fields
25+
* @return SQL
26+
*/
27+
public function select(array $fields = array())
28+
{
29+
$this->_fields = $fields;
30+
return $this;
31+
}
32+
33+
/**
34+
*
35+
* @param string $table
36+
* @param string $alias
37+
* @return SQL
38+
*/
39+
public function from($table, $alias)
40+
{
41+
$this->_from[] = $table . ' AS ' . $alias;
42+
return $this;
43+
}
44+
45+
/**
46+
* @param string $condition
47+
* @return SQL
48+
*/
49+
public function where($condition)
50+
{
51+
$this->_where[] = $condition;
52+
return $this;
53+
}
54+
}
55+
56+
$instance = new SQL();
57+
$instance->select(array('foo', 'bar'))
58+
->from('foobar', 'f')
59+
->where('f.bar = ?');

Iterator/Iterator.php

Lines changed: 109 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,109 @@
1+
<?php
2+
3+
namespace DesignPatterns;
4+
5+
/**
6+
* iterator pattern
7+
*
8+
* Purpose:
9+
* to make an object iterable
10+
*
11+
* Examples:
12+
* - to process a file line by line by just running over all lines (which have an object representation) for a file
13+
* (which of course is an object, too)
14+
*
15+
* Note:
16+
* Standard PHP Library (SPL) defines an interface Iterator which is best suited for this!
17+
* Often you would want to implement the Countable interface too, to allow count($object) on your iterable object
18+
*
19+
* THIS EXAMPLE ALSO APPLIES THE COMPOSITE PATTERN
20+
*
21+
*/
22+
class File
23+
{
24+
protected $_rowset;
25+
26+
protected $_pathName;
27+
28+
public function __construct($pathName)
29+
{
30+
$this->_rowset = new Rowset($this);
31+
}
32+
33+
public function process()
34+
{
35+
$this->_rowset->process();
36+
}
37+
}
38+
39+
class Rowset implements Iterator
40+
{
41+
protected $_currentRow;
42+
43+
protected $_file;
44+
45+
public function __construct($file)
46+
{
47+
$this->_file = $file;
48+
}
49+
50+
/**
51+
* composite pattern: run through all rows and process them
52+
*
53+
* @return void
54+
*/
55+
public function process()
56+
{
57+
// this actually calls rewind(), { next(), valid(), key() and current() :}
58+
foreach ($this as $line => $row) {
59+
$row->process();
60+
}
61+
}
62+
63+
public function rewind()
64+
{
65+
// seek to first line from $this->_file
66+
}
67+
68+
public function next()
69+
{
70+
// read the next line from $this->_file
71+
if (!$eof) {
72+
$data = ''; // get the line
73+
$this->_currentRow = new Row($data);
74+
} else {
75+
$this->_currentRow = null;
76+
}
77+
}
78+
79+
public function current()
80+
{
81+
return $this->_currentRow;
82+
}
83+
84+
public function valid()
85+
{
86+
return null !== $this->_currentRow;
87+
}
88+
89+
public function key()
90+
{
91+
// you would want to increment this in next() or whatsoever
92+
return $this->_lineNumber;
93+
}
94+
}
95+
96+
class Row
97+
{
98+
protected $_data;
99+
100+
public function __construct($data)
101+
{
102+
$this->_data = $data;
103+
}
104+
105+
public function process()
106+
{
107+
// do some fancy things here ...
108+
}
109+
}

0 commit comments

Comments
 (0)