admin
PHP设计模式
PHP设计模式 - virus记载的笔记 - 出自燕十三的PHP设计模式视频
在软件开发过程中,经常出现的典型场景的典型解决方案,称为设计模式
是为了程序高内聚、低耦合
更深入理解面向对象
有利于开发出扩展性强的程序
单例模式
用于场景:经典例子是数据库连接(
redis,mongodb,memcache
等),通过单例模式来实现只做一次mysql_connect()
来节约资源。
==两个对象是一个的时候,才全等==
创建一个普通类
class Singleton { } $single = new Singleton();
封锁
new
操作,将构造函数私有化class Singleton { private function __construct(){} }
留个静态方法
getInstance()
来new
对象class Singleton { private function __construct(){} public static function getInstance() { return new self(); } }
getInstance
先顶一个私有静态属性来保存实例,第一次保存之后,后面进行判断这个私有静态属性是否为空,否则就直接返回这个存储实例的私有静态属性,此时还有问题,额外定义一个子类继承这个类,将构造函数改为公有属性,则还是不行。class Singleton { private static $instance = null; private function __construct(){} public static function getInstance() { if (self::$instance === null) { self::$instance = new self(); } return self::$instance; } }
- 用
final
防止继承时,被修改权限
==方法前加final
,方法不能被覆盖,类前加final
,则类不能被继承==
此时,还是有问题,使用clone
函数时,又产生了一个对象
class Singleton {
private static $instance = null;
final private function __construct(){}
public static function getInstance()
{
if (self::$instance === null) {
self::$instance = new self();
}
return self::$instance;
}
}
可以私有化
__clone()
函数class Singleton { private static $instance = null; final private function __construct(){} public static function getInstance() { // 判断有没有实例化 if (self::$instance === null) { self::$instance = new self(); } return self::$instance; } final private function __clone(){} }
- 优化后的就是使用
!self::$instance instanceof self
来代替上述的判断和final
,这里前者是用来判断保存的对象不是从本身或者其派生类产生的,这样就可以避免继承之后改变构造函数公有化代来的烦恼。也减少了代码量。
<?php
class Singleton
{
private static $instance = null;
// 私有 => 防止外部进行实例化 new Singleton
private function __construct()
{
echo __METHOD__;
}
public static function getInstance()
{
// 判断保存的对象不是从本身或者其派生类产生的
if (!self::$instance instanceof self) {
self::$instance = new self();
}
return self::$instance;
}
private function __clone()
{
// TODO: Implement __clone() method.
}
}
$instance = Singleton::getInstance();
var_dump($instance);
运行结果
Singleton::__constructobject(Singleton)#1 (0) { }
观察者模式
定义对象间的一种一对多的依赖关系,当一个对象的状态改变时,所有依赖与它的对象都得到通知并被自动更新
PHP中提供观察者
observer
与被观察者subject
的接口
<?php
/**
* Created By basic
* Author: Virus
* Date: 2020/5/23
* Time: 21:33
* 观察登录的次数
*/
class User implements SplSubject
{
public $login_num;
public $hobby;
protected $observers = null;
public function __construct($hobby)
{
$this->login_num = rand(1, 10);
$this->hobby = $hobby;
$this->observers = new SplObjectStorage();
}
public function login()
{
// 操作session...
// 发送通知
$this->notify();
}
/**
* Attach an SplObserver
* @link https://php.net/manual/en/splsubject.attach.php
* @param SplObserver $observer <p>
* The <b>SplObserver</b> to attach.
* </p>
* @return void
* @since 5.1.0
*/
public function attach(SplObserver $observer)
{
// TODO: Implement attach() method.
$this->observers->attach($observer);
}
/**
* Detach an observer
* @link https://php.net/manual/en/splsubject.detach.php
* @param SplObserver $observer <p>
* The <b>SplObserver</b> to detach.
* </p>
* @return void
* @since 5.1.0
*/
public function detach(SplObserver $observer)
{
// TODO: Implement detach() method.
$this->observers->detach($observer);
}
/**
* Notify an observer
* @link https://php.net/manual/en/splsubject.notify.php
* @return void
* @since 5.1.0
*/
public function notify()
{
// TODO: Implement notify() method.
$this->observers->rewind();
while ($this->observers->valid()) {
$observer = $this->observers->current();
$observer->update($this);
$this->observers->next();
}
}
}
class Security implements SplObserver
{
/**
* Receive update from subject
* @link https://php.net/manual/en/splobserver.update.php
* @param SplSubject $subject <p>
* The <b>SplSubject</b> notifying the observer of an update.
* </p>
* @return void
* @since 5.1.0
*/
public function update(SplSubject $subject)
{
// TODO: Implement update() method.
if ($subject->login_num >= 3) {
echo '这是第'.$subject->login_num.'次安全登录';
} else {
echo '这是第'.$subject->login_num.'次登录,异常';
}
}
}
class Ad implements SplObserver
{
/**
* Receive update from subject
* @link https://php.net/manual/en/splobserver.update.php
* @param SplSubject $subject <p>
* The <b>SplSubject</b> notifying the observer of an update.
* </p>
* @return void
* @since 5.1.0
*/
public function update(SplSubject $subject)
{
// TODO: Implement update() method.
if ($subject->hobby == 'sports') {
echo '台球锦标赛预定';
} else {
echo '好好学习,天天向上';
}
}
}
$user = new User('study');
$user->attach(new Security());
$user->attach(new Ad());
$user->login();
简单工厂模式
这里拿连接多种数据库来当作案例
数据库类一般会有一个连接的接口 ,这是每个数据库连接的共同的接口
Db
按照正常面向接口开发来说,我们不知道各种数据库类的具体内部细节,只知道,数据库类都实现了
Db
接口
<?php
/**
* Created By basic
* Author: Virus
* Date: 2020/5/23
* Time: 18:03
*/
// 共同接口
interface db
{
function conn();
}
// 服务端开发(不知道将会被谁调用)
class DbMysql implements db
{
function conn()
{
// TODO: Implement conn() method.
echo '连接上了mysql';
}
}
class DbSqlite implements db
{
function conn()
{
// TODO: Implement conn() method.
echo '连接上了sqlite';
}
}
$db = new DbMysql();
$db->conn(); // 连接上了mysql
此时我们还是知道服务端有哪些数据库类,对于面向接口编程来说,这里我们要开始认为,客户端现在不知道服务端有什么数据库类!的情况,只知道对方开放了一个
SimpleFactory::createDB()
方法,并且方法允许传递数据库名称,由此衍生出简单工厂模式!
// ...上述代码还是必须的内容,这里省略
class SimpleFactory
{
public static function createDB($type)
{
if ($type == 'mysql') {
return new DbMysql();
} else if ($type == 'sqlite') {
return new DbSqlite();
} else {
return new Exception("Error db type", 1);
}
}
}
$mysql = SimpleFactory::createDB('mysql');
$mysql->conn();
$sqlite = SimpleFactory::createDB('sqlite');
$sqlite->conn();
此时,如果新增
Oracle
类型咋办,一方面,可以直接在上述if/else
里再来一个else if
,这样在PHP
里修改个5、6条还行,但是对于静态类语言,他们是需要重新编译的,所以会很浪费时间。在OOP
重,重要的开闭原则,对于修改是封闭的,对于扩展时开放的。这就是要我们将工厂也进行扩展,不要轻易去修改内容。
所以我们新增了一个工厂的接口提供了一个createDB
的方法
interface Factory
{
public function createDB();
}
class MySQLFactory implements Factory
{
public function createDB()
{
// TODO: Implement createDB() method.
return new DbMysql();
}
}
class SqliteFactory implements Factory
{
public function createDB()
{
// TODO: Implement createDB() method.
return new DbSqlite();
}
}
// 新增Oracle的方式就变了
class Oracle implements db
{
function conn()
{
// TODO: Implement conn() method.
echo '连接上了Oracle';
}
}
class OracleFactory implements Factory
{
public function createDB()
{
// TODO: Implement createDB() method.
return new Oracle();
}
}
职责链模式(chain of responsibility)
每个对象,存储着对自己上级的引用,如果自己处理不了,就交给上一级
拿举报信息提交给能处理的人的案例来说
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>责任链模式</title>
</head>
<body>
<h1>责任链模式</h1>
<form action="action.php" method="post">
<select name="jubao" id="">
<option value="1">粗口</option>
<option value="2">黄赌毒</option>
<option value="3">分裂国家</option>
</select>
<button type="submit">提交</button>
</form>
</body>
</html>
action.php
<?php
/**
* Created By basic
* Author: Virus
* Date: 2020/5/23
* Time: 22:13
*/
header('content-type: text/html;charset=utf-8');
// 版主类
class Board
{
// 权限
public $power = 1;
// 上级
protected $top = 'Admin';
public function process($level)
{
// 如果当前的处理者权限不够,就引导去它的上级去处理
if ($level <= $this->power) {
echo '版主删帖子';
} else {
$top = new $this->top;
$top->process($level);
}
}
}
class Admin
{
protected $power = 2;
protected $top = 'Police';
public function process($level)
{
if ($level <= $this->power) {
echo '管理员封锁账号';
} else {
$top = new $this->top;
$top->process($level);
}
}
}
class Police
{
protected $power;
protected $top = null;
public function process($level)
{
echo '警察抓起来';
}
}
/*
* 这里还是偏向面向过程的解决方式
if ($level == 1) {
$processer = new Board();
$processer->process();
} else if ($level == 2) {
$processer = new Admin();
$processer->process();
} else {
$processer = new Police();
$processer->process();
}
*/
// 责任链模式来处理举报问题
// 接收举报等级
$level = $_POST['jubao'] + 0;
$judge = new Board();
$judge->process($level);