php精粹 php设计模式
本文导语: 1,选择一个最合适的设计模式 没有任何事物是完美的,也没有人说过设计模式一个严格的放之四海而皆准的解决方法。因此你可以改变这些模式,使它们更适合手头的工作。对于某些设计模式而言,他们就是所属程序固有的天...
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解决创建两个不同类型的实例的问题,但仍然不能解决创建两个相同实例的问题(可用注册表模式解决)。
创建两个不同类的实例 代码:
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迭代器实现过滤