设计模式--使用案例

2021-05-02

原则

  1. 单一职责原则:每个类实现单一的职责
  2. 里氏替换原则:子类尽量不要对父类的方法进行重写和重载
  3. 依赖倒转原则:
  4. 接口隔离原则:每个接口中不存在子类用不到却必须实现的方法,(将接口拆分,使用多个隔离的接口,比使用单个接口更好)
  5. 迪米特原则:一个类对自己依赖的类知道的越少越好(无论被依赖的类有多复杂,都应该将逻辑封装在方法的内部,通过public提供给外面)
  6. 合成复用原则:尽量首先使用合成/聚合的方式,而不是使用继承

使用案例

  • 使用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);
}

 

{/if}