相关内容:
1. PHP 三种基础设计模式(工厂模式、单例模式、注册器模式)以及适配器模式
2. PHP 设计模式之策略模式、数据对象映射模式、观察者模式、原型模式、装饰器模式、迭代器模式、代理模式
1. 工厂模式;
- 使用一个工厂方法或者类生成对象,而不是在代码中直接 new
- 如果不使用工厂模式,如果想要创建一个对象,就需要 new 这个对象。如果是工厂模式的话,就是用一个工厂方法来替换直接 new 对象的操作
- 在之前的基础框架上继续演示
- 新增:
Library/Database.php
<?php
namespace Library;
class Database{
}
- 新增:
Library/Factory.php
<?php
namespace Library;
// 工厂类
class Factory{
static function createDatabase(){
$db = new Database;
return $db;
}
}
- 修改:
index.php
<?php
define('BASEDIR', __DIR__);
include BASEDIR . '/Library/Loader.php';
spl_autoload_register('\\Library\\loader::autoload');
// 工厂模式
// 需要一个工厂方法替换掉这个 new 对象的操作
// $db = new \Library\Database();
// 工厂模式和直接 new 一个对象相比的优势是:
// 如果需要 new 的那个类在很多个 PHP 文件里都有 new 的操作
// 如果这个对象发生了一些变更,比如类名或者参数发生了变化
// 那这时候如果不使用工厂模式,就需要每一个 PHP 文件都去修改代码
// 而使用了工厂模式之后,只需要在工厂方法中吧类的名称或者参数修改即可
// 其它很多高级的设计模式也都依赖于工厂模式
$db = Library\Factory::createDatabase();
2. 单例模式;
- 使某个类的对象只允许被创建一次
- 案例:假设我们有一个数据库的类要实现到连接数据库。
- 如果我们不使用单例模式,就像之前的工厂模式那样,那就可以有很多个 PHP 文件创建数据库连接,这就是一种对资源的浪费。实际只要创建一个数据库链接即可。
- 修改文件:
Library/Database.php
<?php
namespace Library;
class Database{
protected static $db;
// 构造方法声明为 private,屏蔽在其它地方直接创建数据库连接操作
private function __construct(){
}
// 获取实例
// 类本身的代码里可以调用上面的私有方法
static function getInstance(){
if(is_null(self::$db)){
// 构造对象赋值给静态属性
self::$db = new self();
}
return self::$db;
}
function where($where){
return $this;
}
function order($order){
return $this;
}
function limit($limit){
return $this;
}
}
- 修改:index.php
<?php
define('BASEDIR', __DIR__);
include BASEDIR . '/Library/Loader.php';
spl_autoload_register('\\Library\\loader::autoload');
// 单例模式
$db = Library\Database::getInstance();
- 修改:
Library/Factory.php
<?php
namespace Library;
// 工厂加单例
class Factory{
static function createDatabase(){
// $db = new Database;
$db = Database::getInstance(); // 单例
return $db;
}
}
3. 注册器模式;
- 解决全局共享和交换对象
- 工厂模式和单例模式的缺点是必须去调用工厂或者类。用注册器模式可以直接取到对象。
- 注册器模式用来将一些对象注册到全局树上,就可以用来被任何地方直接访问
- 实例:新建
Library/Register.php
<?php
<?php
namespace Library;
class Register{
protected static $objects;
// 将一个对象注册到全局注册树上
function set($alias, $object){
self::$objects[$alias] = $object;
}
static function get($name){
return self::$objects[$name];
}
// 从注册树上移除
function _unset(){
unset(self::$objects[$alias]);
}
}
- 修改:
Library/Factory.php
<?php
namespace Library;
// 工厂加单例
class Factory{
static function createDatabase(){
// $db = new Database;
$db = Database::getInstance(); // 单例
Register::set('db1',$db); // 注册
return $db;
}
}
- 修改:
index.php
<?php
define('BASEDIR', __DIR__);
include BASEDIR . '/Library/Loader.php';
spl_autoload_register('\\Library\\loader::autoload');
// 工厂方法只需要调用一次
// 其它任何地方再要调用数据库对象不需要调用工厂方法、也不需要调用单例模式获取实例
// 直接在注册器上获取对象
Library\Factory::createDatabase(); // 工厂模式里注册
$db = Library\Register::get("db1");
4. 适配器模式。
- 适配器模式可以将截然不同的函数接口封装成统一的 API 接口
- 实际应用举例,PHP 的数据库操作有 mysqli、pdo 等,可以应用适配器模式统一成一致。类似的场景还有 cache 适配器,将 memcached、redis、file、apc 等不同的缓存函数,统一成一致
- 实例:修改文件
Library/IDatabase.php
<?php
// 声明接口
// 接口约定了统一的 API 方式
// 之后分别创建适配器实例,实现接口的方法
namespace Library;
interface IDatabase{
// 连接数据库
function connect($host, $user, $password, $dbname);
// 查询
function query($sql);
// 关闭数据库
function close();
}
- 新增:
Library/Database/MySQLi.php
<?php
namespace Library\Database;
class MySQli implements IDatabase{
protected $conn;
function connect($host, $user, $password, $dbname){
$conn = mysqli_connect($host, $user, $password, $dbname);
$this->conn = $conn;
}
function query($sql){
return mysqli_query($this->conn, $sql);
}
function close(){
mysqli_close($this->conn);
}
}
- 新增:
Library/Database/PDO.php
<?php
namespace Library\Database;
class PDO implements IDatabase{
protected $conn;
function connect($host, $user, $password, $dbname){
$conn = new \PDO("mysql:host=$host;dbname=$dbname", $user, $password);
$this->conn = $conn;
}
function query($sql){
return $this->conn->query($sql);
}
function close(){
unset($this->conn);
}
}
- 修改:
index.php
<?php
// 调用数据库
$db = new \Library\Database\MySQLi();
// $db = new \Library\Database\PDO();
$db->connect('127.0.0.1', 'root', 'asdf', 'test');
$db->query("show databases");
$db->close();