1,选择一个最合适的设计模式
没有任何事物是完美的,也没有人说过设计模式一个严格的放之四海而皆准的解决方法。因此你可以改变这些模式,使它们更适合手头的工作。对于某些设计模式而言,他们就是所属程序固有的天性;而对于其他的一些设计模式,你可以改变其自身的模式。模式之间互相配合、协同工作已经很常见。它们构成了整个应用(至少一部分)的基础。
2.单例模式
// The Database class represents our global DB connection - class Database{
- // A static variable to hold our single instance
- private static $_instance = null;
-
- // Make the constructor private to ensure singleton
- private function __construct()
- {
- echo 'constructor';
- }
// A method to get our singleton instance - public static function getInstance()
- {
- if (!(self::$_instance instanceof Database)) {
- self::$_instance = new Database();
- }
-
- return self::$_instance;
- }
- }
$database = Database::getInstance(); - var_dump($database);
问题:使用单例模式不能创建两个实例,可用Traits解决创建两个不同类型的实例的问题,但仍然不能解决创建两个相同实例的问题(可用注册表模式解决)。
创建两个不同类的实例 代码:
- trait Singleton {
- private static $_instance = null;
-
- public static function getInstance() {
- $class = __CLASS__;
-
- if(!(self::$_instance instanceof $class)) {
- self::$_instance = new $class;
- }
-
- return self::$_instance;
- }
-
- }
- class DB {
- }
-
- class DBWriteConnection extends DB {
- use Singleton;
-
- private function __construct() {
- echo 'DBWriteConnection
'; - }
- }
-
- class DBReadConnection extends DB {
- use Singleton;
-
- private function __construct() {
- echo 'DBReadConnection
'; - }
- }
-
- $dbWriteConnection = DBWriteConnection::getInstance();
- var_dump($dbWriteConnection);
3.注册表模式
注册表模式仅仅是一个单独的全局类,在你需要的时候允许代码检索一个对象的相同实例,也可以在你需要的时创建另一个实例(一经要求将再次访问那些全局实例)。
Registry类:
class Registry { - /**
- * @var array The store for all of our objects
- */
- static private $_store = array();
-
- /**
- * Add an object to the registry
- *
- * If you do not specify a name the classname is used
- *
- * @param mixed $object The object to store
- * @param string $name Name used to retrieve the object
- * @return void
- * @throws Exception
- */
- static public function add($object, $name = null)
- {
- // Use the classname if no name given, simulates singleton
- $name = (!is_null($name)) ?$name:get_class($object);
- if (isset(self::$_store[$name])) {
- throw new Exception("Object already exists in registry");
- }
-
- self::$_store[$name]= $object;
- }
-
- /**
- * Get an object from the registry
- *
- * @param string $name Object name, {@see self::set()}
- * @return mixed
- * @throws Exception
- */
- static public function get($name)
- {
- if (!self::contains($name)) {
- throw new Exception("Object does not exist in registry");
- }
return self::$_store[$name]; - }
-
- /**
- * Check if an object is in the registry
- *
- * @param string $name Object name, {@see self::set()}
- * @return bool
- */
- static public function contains($name)
- {
- if (!isset(self::$_store[$name])) {
- return false;
- }
-
- return true;
- }
-
- /**
- * Remove an object from the registry
- *
- * @param string $name Object name, {@see self::set()}
- * @returns void
- */
- static public function remove($name)
- {
- if (self::contains($name)) {
- unset(self::$_store[$name]);
- }
- }
- }
-
在类外部,使用Registry类:
require 'Registry.php'; class DBReadConnection {} - class DBWriteConnection {}
$read = new DBReadConnection; - Registry::add($read);
$write = new DBWriteConnection; - Registry::add($write);
// To get the instances, anywhere in our code: - $read = Registry::get('DBReadConnection');
- $write = Registry::get('DBWriteConnection');
var_dump($read); - var_dump($write);
-
在类内部使用Registry表类,使用者不与Registry交互。
示例代码:
require 'Registry.php'; abstract class DBConnection { - static public function getInstance($name = null)
- {
- // Get the late-static-binding version of __CLASS__
- $class = get_called_class();
- // Allow passing in a name to get multiple instances
- // If you do not pass a name, it functions as a singleton
- $name = (!is_null($name)) ? $name:$class;
- if (!Registry::contains($name)) {
- $instance = new $class();
- Registry::add($instance, $name);
- }
- return Registry::get($name);
- }
- }
class DBWriteConnection extends DBConnection { - public function __construct()
- {
- echo 'DBWriteConnection
'; - }
- }
class DBReadConnection extends DBConnection { - public function __construct()
- {
- echo 'DBReadConnection
'; - }
- }
$dbWriteConnection = DBWriteConnection::getInstance('abc'); - var_dump($dbWriteConnection);
- $dbReadConnection = DBReadConnection::getInstance();
- var_dump($dbReadConnection);
4.工厂模式
工厂(factory)模式制造对象,就像工业界与它同名的钢筋混泥土行业一样。通常,我们将工厂模式用于初始化相同抽象类或者接口的具体实现。
在通常方式下,虽然人们极少采用工厂模式,但是它仍是最适合初始化基于驱动安装的许多变种的一种。例如不同的配置、会话或缓存存储引擎。工厂模式的最大价值在于它可以将多个对象设置封装成单一、简单的方法调用。
- /**
- * Log Factory
- *
- * Setup and return a file, mysql, or sqlite logger
- */
- class Log_Factory {
- /**
- * Get a log object
- *
- * @param string $type The type of logging backend, file, mysql or sqlite
- * @param array $options Log class options
- */
- public function getLog($type = 'file', array $options)
- {
- // Normalize the type to lowercase
- $type = strtolower($type);
-
- // Figure out the class name and include it
- $class = "Log_" .ucfirst($type);
- require_once str_replace('_', DIRECTORY_SEPARATOR, $class) . '.php';
-
- // Instantiate the class and set the appropriate options
- $log = new $class($options);
- switch ($type) {
- case 'file':
- $log->setPath($options['location']);
- break;
- case 'mysql':
- $log->setUser($options['username']);
- $log->setPassword($options['password']);
- $log->setDBName($options['location']);
- break;
- case 'sqlite':
- $log->setDBPath($otions['location']);
- break;
- }
-
- return $log;
- }
- }
5.迭代模式
迭代模式允许我们将foreach的性能添加到任何对象的内部存储数据,而不仅仅添加到公共属性。它覆盖了默认的foreach行为,并允许我们为循环注入业务逻辑。
(1)使用Iterator迭代器接口
class BasicIterator implements Iterator { - private $key = 0;
- private $data = array(
- "hello",
- "world",
- );
public function __construct() { - $this->key = 0;
- }
public function rewind() { - $this->key = 0;
- }
public function current() { - return $this->data[$this->key];
- }
public function key() { - return $this->key;
- }
public function next() { - $this->key++;
- return true;
- }
public function valid() { - return isset($this->data[$this->key]);
- }
- }
$iterator = new BasicIterator(); - $iterator->rewind();
do { - $key = $iterator->key();
- $value = $iterator->current();
- echo $key .': ' .$value . PHP_EOL;
- } while ($iterator->next() && $iterator->valid());
- $iterator = new BasicIterator();
- foreach ($iterator as $key => $value) {
- echo $key .': ' .$value . PHP_EOL;
- }
(2)使用RecursiveIteratorIterator迭代器遍历数组
$array = array( - "Hello", // Level 1
- array(
- "World" // Level 2
- ),
- array(
- "How", // Level 2
- array(
- "are", // Level 3
- "you" // Level 3
- )
- ),
- "doing?" // Level 1
- );
$recursiveIterator = new RecursiveArrayIterator($array); $recursiveIteratorIterator = new RecursiveIteratorIterator($recursiveIterator); foreach ($recursiveIteratorIterator as $key => $value) { - echo "Depth: " . $recursiveIteratorIterator->getDepth() . PHP_EOL;
- echo "Key: " . $key . PHP_EOL;
- echo "Value: " .$value . PHP_EOL;
- }
(3)用FilterIterator迭代器实现过滤
class EvenFilterIterator extends FilterIterator { - /**
- * Accept only even-keyed values
- *
- * @return bool
- */
- public function accept()
- {
- // Get the actual iterator
- $iterator = $this->getInnerIterator();
-
- // Get the current key
- $key = $iterator->key();
-
- // Check for even keys
- if ($key % 2 == 0) {
- return true;
- }
-
- return false;
- }
- }
$array = array( - 0 => "Hello",
- 1 => "Everybody Is",
- 2 => "I'm",
- 3 => "Amazing",
- 4 => "The",
- 5 => "Who",
- 6 => "Doctor",
- 7 => "Lives"
- );
// Create an iterator from our array - $iterator = new ArrayIterator($array);
// Create our FilterIterator - $filterIterator = new EvenFilterIterator($iterator);
// Iterate - foreach ($filterIterator as $key => $value) {
- echo $key .': '. $value . PHP_EOL;
- }
- ?>
(4)RegexIterator迭代器
// Create a RecursiveDirectoryIterator - $directoryIterator = new RecursiveDirectoryIterator("./");
// Create a RecursiveIteratorIterator to recursively iterate - $recursiveIterator = new RecursiveIteratorIterator($directoryIterator);
// Createa filter for *Iterator*.php files - $regexFilter = new RegexIterator($recursiveIterator, '/(.*?)Iterator(.*?)\.php$/');
// Iterate - foreach ($regexFilter as $key => $file) {
- /* @var SplFileInfo $file */
- echo $file->getFilename() . PHP_EOL;
- }
-
功能:找到所有的php文件
(4)LimitItertor迭代器,像SQL中的LIMIT
// Define the array - $array = array(
- 'Hello',
- 'World',
- 'How',
- 'are',
- 'you',
- 'doing?'
- );
// Create the iterator - $iterator = new ArrayIterator($array);
// Create the limiting iterator, to get the first 2 elements - $limitIterator = new LimitIterator($iterator, 0, 2);
// Iterate - foreach ($limitIterator as $key => $value) {
- echo $key .': '. $value . PHP_EOL;
- }
6.观察者模式(observer)
观察者模式的核心在于云霄你的应用程序注册一个回调,当某个特定的事件发生时便会促发它
/** - * The Event Class
- *
- * With this class you can register callbacks that will
- * be called (FIFO) for a given event.
- */
- class Event {
- /**
- * @var array A multi-dimentional array of events => callbacks
- */
- static protected $callbacks = array();
-
- /**
- * Register a callback
- *
- * @param string $eventName Name of the triggering event
- * @param mixed $callback An instance of Event_Callback or a Closure
- */
- static public function registerCallback($eventName, $callback)
- {
- if (!($callback instanceof Event_Callback) && !($callback instanceof Closure)) {
- throw new Exception("Invalid callback!");
- }
-
- $eventName = strtolower($eventName);
-
- self::$callbacks[$eventName][] = $callback;
- }
-
- /**
- * Trigger an event
- *
- * @param string $eventName Name of the event to be triggered
- * @param mixed $data The data to be sent to the callback
- */
- static public function trigger($eventName, $data)
- {
- $eventName = strtolower($eventName);
-
- if (isset(self::$callbacks[$eventName])) {
- foreach (self::$callbacks[$eventName] as $callback) {
- self::callback($callback, $data);
- }
- }
- }
-
- /**
- * Perform the callback
- *
- * @param mixed $callback An instance of Event_Callback or a Closure
- * @param mixed $data The data sent to the callback
- */
- static protected function callback($callback, $data)
- {
- if ($callback instanceof Closure) {
- $callback($data);
- } else {
- $callback->run($data);
- }
- }
- }
/** - * The Event Callback interface
- *
- * If you do not wish to use a closure
- * you can define a class that extends
- * this instead. The run method will be
- * called when the event is triggered.
- */
- interface Event_Callback {
- public function run($data);
- }
/** - * Logger callback
- */
- class LogCallback implements Event_Callback {
- public function run($data)
- {
- echo "Log Data" . PHP_EOL;
- var_dump($data);
- }
- }
// Register the log callback - Event::registerCallback('save', new LogCallback());
// Register the clear cache callback as a closure - Event::registerCallback('save', function ($data) {
- echo "Clear Cache" . PHP_EOL;
- var_dump($data);
- });
class MyDataRecord { - public function save()
- {
- // Save data
-
- // Trigger the save event
- Event::trigger('save', array("Hello", "World"));
- }
- }
// Instantiate a new data record - $data = new MyDataRecord();
- $data->save(); // 'save' Event is triggered here
7.依赖注入模式
依赖注入模式允许类的使用这为这个类注入依赖的行为。
/** - * Log Class
- */
- class Log {
- /**
- * @var Log_Engine_Interface
- */
- protected $engine = false;
-
- /**
- * Add an event to the log
- *
- * @param string $message
- */
- public function add($message)
- {
- if (!$this->engine) {
- throw new Exception('Unable to write log. No Engine set.');
- }
-
- $data['datetime'] = time();
- $data['message'] = $message;
-
- $session = Registry::get('session');
- $data['user'] = $session->getUserId();
-
- $this->engine->add($data);
- }
-
- /**
- * Set the log data storage engine
- *
- * @param Log_Engine_Interface $Engine
- */
- public function setEngine(Log_Engine_Interface $engine)
- {
- $this->engine = $engine;
- }
-
- /**
- * Retrieve the data storage engine
- *
- * @return Log_Engine_Interface
- */
- public function getEngine()
- {
- return $this->engine;
- }
- }
interface Log_Engine_Interface { - /**
- * Add an event to the log
- *
- * @param string $message
- */
- public function add(array $data);
- }
class Log_Engine_File implements Log_Engine_Interface { - /**
- * Add an event to the log
- *
- * @param string $message
- */
- public function add(array $data)
- {
- $line = '[' .data('r', $data['datetime']). '] ' .$data['message']. ' User: ' .$data['user'] . PHP_EOL;
-
- $config = Registry::get('site-config');
-
- if (!file_put_contents($config['location'], $line, FILE_APPEND)) {
- throw new Exception("An error occurred writing to file.");
- }
- }
- }
$engine = new Log_Engine_File(); $log = new Log(); - $log->setEngine($engine);
// Add it to the registry - Registry::add($log);
依赖注入不想工厂模式,日之类无需了解每一个不同的存储引擎的相关知识。这就意味着任何使用日志类的开发者可以添加他们自己的存储引擎,主要他们复合接口就行。
8.模型-视图-控制器
模型-视图-控制器又称为MVC模式,是描述应用程序3个不同层次之间关系的一种方式。
模型-数据层 所有的输出数据都来自模型。它可能是一个数据库、web服务或者文件。
视图-表现层 负责将数据从模型中取出并输出给用户。
控制器-应用程序流层 根据用户的请求调用相应的模型检索出请求的数据,然后调用视图将操作的结果显示给用户。
一个典型的MVC架构图:
9.对模式的理解 模式是很多常见问题的最佳解决方法。
您可能感兴趣的文章:
- php设计模式之单例模式、工厂模式与观察者模式
- 深入php设计模式实例详解
- php设计模式实例之命令模式
- php设计模式实例之观察者模式(2)
- PHP设计模式实例之观察者模式
- php设计模式实例之工厂模式
- php设计模式实例之单例模式
- PHP设计模式之观察者模式的例子
- php设计模式之工厂模式的实例代码
- php设计模式之单例模式的实例代码
- php常用设计模式之工厂模式与单例模式介绍
- 学习php设计模式之单例模式
- php常用的三种设计模式的学习笔记
- php设计模式之单例模式学习
|