原则
- 单一职责原则:每个类实现单一的职责
- 里氏替换原则:子类尽量不要对父类的方法进行重写和重载
- 依赖倒转原则:
- 接口隔离原则:每个接口中不存在子类用不到却必须实现的方法,(将接口拆分,使用多个隔离的接口,比使用单个接口更好)
- 迪米特原则:一个类对自己依赖的类知道的越少越好(无论被依赖的类有多复杂,都应该将逻辑封装在方法的内部,通过public提供给外面)
- 合成复用原则:尽量首先使用合成/聚合的方式,而不是使用继承
使用案例
- 使用ArrayAccess实现配置文件的加载
- 在工厂方法中读取配置,生成可配置化的对象
- 使用装饰器实现权限验证,模板渲染,JSON串化
- 使用观察者模式实现数据更新事件的一系列更新操作
- 使用代理模式实现数据库的主从自动切换
配置文件
<?php
// Config/decorators.php
return [
'home' => [
'ValidateDecorator',
'DisplayDecorator',
'TempateDecorator'
]
];
// Config/observer.php
return [
'user' => [
'EventoBserver1',
'EventoBserver2'
]
];
// Config/database.php
return [
'master' => [
'host' => '127.0.0.1',
'port' => 3306,
'user' => 'root',
'passsword' => 'root',
'dbname' => 'dbname1',
],
'salve' => [
[
'host' => '127.0.0.1',
'port' => 3306,
'user' => 'root',
'passsword' => 'root',
'dbname' => 'dbname1',
],
[
'host' => '127.0.0.1',
'port' => 3306,
'user' => 'root',
'passsword' => 'root',
'dbname' => 'dbname1',
]
]
];
调用代码(代码仅为示例,不见得能完美运行),代码中没有的类是来自于前面文章中的类
// ArrayAccess是一个让对象变成可以使用数组的使用方式
class Config implements \ArrayAccess
{
private $_path;
private $_configs = array();
public function __construct($path)
{
$this->path = $path;
}
public function offsetGet($key)
{
if (empty($this->_configs[$key]))
{
$file_path = $this->_path . '/' . $key . '.php';
$config = require $file_path;
$this->_configs[$key] = $config;
}
return $this->_configs[$key];
}
public function offsetSet($key, $value)
{
throw new \Exception('cannot write config file');
}
public function offsetExists($key)
{
return isset($this->_configs[$key]);
}
public function offsetUnset($key)
{
unset($this->_configs[$key]);
}
}
class Factory
{
private static $_proxy;
// $type proxy/slave/master
public static function getDatabase($type = 'proxy')
{
if ($type == 'proxy') {
if (!self::$_proxy) {
self::$_proxy = new Proxy;
}
return self::$_proxy;
}
$key = 'database_'.$type;
$db = Register::get($key);
if (!$db) {
$config = new Config(__DIR__.'/config');
$configs = $config->config['database'][$type];
$db_config = $type = 'slave' ? $configs[array_rand($configs)] : $configs;
$db = new Db1;
$db->connect($db_conf['host'], $db_conf['port'], $db_conf['user'], $db_conf['password'], $db_conf['dbname']);
Register::set($key, $db);
}
return $db;
}
}
控制器及模型
<?php
class Home
{
// 使用文件中的装饰器
public function index()
{
return ['q', 'b', 'c'];
}
// 使用文件中配置的观察者
public function index2()
{
$user = new User();
$user->index();
return ['q', 'b', 'c'];
}
// 代理模式
public function index3()
{
$db = Factory::getDatabase();
$db->query('');
$db->query('');
}
}
class Modle
{
private $_observers = array();
function __construct()
{
$name = strtolower(get_class($this));
$config = new Config(__DIR__.'/config');
if (isset($config->config['observer'][$name]))
{
$observers = $config->config['observer'][$name];
foreach($observers as $class)
{
$this->_observers[] = new $class;
}
}
}
function notify($data)
{
foreach($this->_observers as $observer)
{
$observer->update($data);
}
}
}
class User extends Modle
{
public function index()
{
echo __METHOD__;
echo '通知观察者';
$this->notify('1');
}
}
入口文件
<?php
// index.php
$controller = 'Home';
$function = 'index';
$config = new Config(__DIR__.'/config');
$decorators = $config->config['decorators'];
$class = new $controller();
//读取并设置指定控制器的装饰器
$decorators = array();
if (isset($decorators[$controller]))
{
$conf_decorator = $decorators[$controller];
foreach($conf_decorator as $class)
{
$decorators[] = new $class;
}
}
foreach($decorators as $decorator)
{
$decorator->beforeRequest($obj);
}
// 执行方法获取返回值
$return_value = $class->$function();
// 运行装饰器
foreach($decorators as $decorator)
{
$decorator->afterRequest($return_value);
}