PHP中多种常用的设计模式举例
1.适配器模式,可以将截然不同的函数接口封装成统一的API
2.实际应用举例,PHP的数据库操作有mysql,musqli,pdo三种,可以用适配器模式统一成一致。类似的场景还有cache适配器,将memcache,redis,file,apc等不同的缓存函数,统一成一致
Database.php
<?php
interdace IDatabase{
function connect($host, $user, $passwd, $dbname);
function query($sql);
function close();
}在Database.php中定义了数据库操作的接口,接下来将MySQL、MySQLi、PDO三种数据库操作适配为接口中定义的方法。
MySQL.php
<?php
namespace Database;
class MySQL implements IDatabase{
protected $conn;
function connect($host, $user, $passwd, $dbname){
$conn = mysql_connect($host, $user, $passwd);
mysql_select_db($dbname, $conn);
this->conn = $conn;
}
function query($sql){
$res = mysql_query($sql, $this->conn);
return $res;
}
function close(){
mysql_close($this->conn);
}
}MySQLi.php
<?php
namespace Database;
class MySQLi implements IDatabase{
protected $conn;
function connect($host, $user, $passwd, $dbname){
$conn = mysqli_connect($host, $user, $passwd, $dbname);
this->conn = $conn;
}
function query($sql){
$res = mysqli_query($this->conn, $sql);
return $res;
}
function close(){
mysqli_close($this->conn);
}PDO.php
<?php
namespace Database;
class PDO implements IDatabase{
protected $conn;
function connect($host, $user, $passwd, $dbname){
new \PDO("mysql:host=$host;dbname=$dbname", $user, $passwd);
$this->conn = $conn;
}
function query($sql){
return $this->conn->query($sql);
}
function close(){
unset($this->conn);
}然后在应用中可以这样使用:
index.php
<?php
$db = new Database\MySQL();
$db->connect('localhost', 'root', 'root', 'test');
$db->query('show database');
$db->close();或者实例化其他类型的数据库,只需要使用同一种标准。
1.策略模式,将一组特定行为和算法封装成类,以适应某些特定的上下文环境,这种模式就是策略模式
2.实际应用举例,假如一个电商网站系统,针对男性女性用户要各自跳转到不同的商品类目,并且所有广告位展示不同的广告
3.使用策略模式可以实现Ioc,依赖倒置、控制反转
UserStrategy.php
<?php
interface UserStrategy {
function showAd();
function showCategory();
}UserStrategy.php文件定义了用户策略的接口,面对不同的用户将分别实现相应的内容。
FemaleUserStrategy.php
<?php
class FemaleUserStrategy implements UserStrategy {
function showAd() {
echo "2017新款女装";
}
function showCategory() {
echo "女装";
}
}MaleUserStrategy.php
<?php
class MaleUserStrategy implements UserStrategy {
function showAd() {
echo "IPhone7";
}
function showCategory() {
echo "电子产品";
}
}在index.php中这样做就可以实现从硬编码到实现解耦,即不需要修改Page类的内容,只需要传递不同的参数。
index.php
<?php
class Page {
function index() {
echo "AD:";
$this->strategy->showAd();
echo "Category:";
$this->strategy->showCategory();
}
function setStrategy(UserStrategy $strategy) {
$this->strategy = $strategy;
}
}
$page = new Page();
if (isset($_GET['female'])) {
$strategy = new FemaleUserStrategy();
} else {
$strategy = new MaleUserStrategy();
}
$page->setStrategy($strategy);
$page->index();数据对象映射模式,是将对象和数据存储映射起来,对一个对象的操作会映射为对数据存储的操作。
在下面的代码中实现数据对象映射模式,我们将实现一个ORM类,将复杂的SQL语句映射成对象属性的操作。
User.php
<?php
class User {
public $id;
public $mobile;
public $regtime;
protected $db;
function __construct($id) {
// 数据库查询操作
$this->db = new MySQLi();
$this->db->connect('localhost', 'root', 'root', 'test1');
$res = $this->db->query("select * from user where id={$this->id} limit 1");
$data = $res->fetch_assoc();
$this->id = $data['id'];
$this->name = $data['name'];
$this->mobile = $data['imobile];
$this->regtime = $data[regtimed'];
}
function __destruct() {
// 数据库写入操作
$this->db->query("update user set name = '{$this->name}',
mobile='{$this->mobile}', regtime='{$this->regtime}' where id = {$this->id} limit 1");
}
}这样来使用:
index.php
<?php
$user = new User(1);
$user->mobile = '18812345678';
$user->name = 'test';
$user->regtime = date('Y-m-d H:i:s');下面结合使用数据对象映射模式,工厂模式,注册器模式:
index.php
<?php
class Page {
function index() {
$user = Factory::getUser(1); // 工厂模式的实现
$user->name = 'rango';
$this->test();
}
function test() {
$user = Factory::getUser(1); // 工厂模式的实现
$user->mobile = '18844448888';
}
}
$page = new Page();Factory.php
<?php
class Factory {
static function getUser($id) {
// 注册器模式的实现
$key = 'user_'.$id;
$user = Register::get($key);
if (!user) {
$user = new User($id);
Register::set($key,$user);
}
return $user;
}
}1.观察者模式(Observer),当一个对象状态发生改变时,依赖它的对象全部会收到通知,并自动更新
2.场景:一个事件发生后,要执行一连串更新操作,传统的编程方式,就是在事件的代码之后直接加入处理逻辑。当更新的逻辑增多之后,代码会变得难以维护。这种方式是耦合的,侵入式的,增加新的逻辑需要修改事件主体的代码
3.观察者模式实现了低耦合,非侵入式的通知与更新机制
index.php
<?php
class Event extends EventGenerator {
function trigger() {
echo "Event<br />";
$this->notify();
}
}
class Observer1 implements Obsrver {
function update($event_info = null) {
echo "逻辑1<br />";
}
}
class Observer2 implements Obsrver {
function update($event_info = null) {
echo "逻辑2<br />";
}
}
$event = new Event;
$event->addObserver(new Observer1); // 观察者模式的实现
$event->addObserver(new Observer2); // 观察者模式的实现
$event->trigger();EventGenerator.php
<?php
abstract class EventGenerator {
private $observers = array();
function addObserver(Observer $observer) {
$this->observers[] = $observer;
}
function notify() {
foreach($this->observers as $ovserver) {
$observer->update();
}
}
}Observer.php
<?php
interface Observer {
function update($event_info = null);
}1.与工厂模式作用类似,都是用来创建对象
2.与工厂模式的实现不同,原型模式是先创建好一个原型对象,然后通过clone原型对象来创建新的对象。这样就免去了类创建时重复的初始化操作
3.原型模式适用于大对象的创建。创建一个大对象需要很大的开销,如果每次new就会消耗很大,原型模式内存拷贝即可
Canvas.php
<?php
class Canvas {
...
}index.php将实例化Canvas类以实现图像绘制,并使用关键字clone实现原型模式:
index.php
<?php $prototype = new Canvas(); $prototype->init(); // 原型模式的实现 $canvas1 = clone $prototype; $canvas2 = clone $prototype; $canvas1->rect(1,2,3,4); $canvas1->draw(); $canvas2->rect(5,6,7,8); $canvas2->draw();
1.装饰器模式(Decorator),可以动态地添加修改类的功能
2.一个类提供了一项功能,如果要在修改并添加额外的功能,传统的编程模式,需要写一个子类继承它,并重新实现类的方法
3.使用装饰器模式,仅需要在运行时添加一个装饰器对象即可实现,可以实现最大的灵活性
DrawDecorator.php
<?php
interface DrawDecorator {
function beforeDraw();
function afterDraw();
}DrawDecorator.php定义了装饰器的接口,将会在装饰器类中用到。
Canvas.php
<?php
class Canvas {
protected $decorator = array();
function draw() {
// 装饰器模式实现点
$this->beforeDraw();
...
$this->afterDraw();
}
function addDecorator(DrawDecorator $decorator) {
$this->decorators[] = $decorator;
}
function beforeDraw() {
foreach($this->decorators as $decorator) {
$decorator->beforeDraw();
}
}
fucntion afterDraw() {
$decorators = array_reverse($this->decorators); // 反转,后进先出
foreach($decorators as $decorator) {
$decorator->afterDraw();
}
}
}ColorDrawDecorator.php
<?php
// 第一个装饰器:颜色装饰器
class ColorDrawDecortor implements DrawDecorator {
function beforeDraw() {
...
}
function afterDraw() {
...
}
}1.迭代器模式,在不需要了解内部实现的前提下,遍历一个聚合对象的内部元素
2.相比于传统的编程模式,迭代器模式可以隐藏遍历元素所需的操作
index.php
<?php
$users = new AllUser();
foreach($users as $user) {
var_dump($user);
}迭代器的实现:
AllUser.php
<?php $canvas1 = new Canvas(); $canvas1->init(); $canvas1->addDecorator(new ColorDrawDecortor()); // 添加装饰器 $canvas1->draw();
这样来使用:
index.php
<?php
class AllUser implements \Iterator {
protected $ids;
protected $data = array();
protected $index;
function __construct() {
$db = Factory::getDatabase();
$result = $db->query('select id from user');
$this->ids = $result->fetch_all(MUSQLI_ASSOC);
}
function current() {
$id = $this->ids[$this->index]['id'];
return Factory::getUser($id);
}
function next() {
$this->index ++;
}
function valid() {
return $this->id < count($this->ids);
}
function rewind() {
$this->index = 0;
}
function key() {
return $this->index;
}
}1.在客户端与实体之间建立一个代理对象(proxy),客户端对实体进行操作全部委派给代理对象,隐藏实体的具体实现细节
2.Proxy还可以与业务代码分离,部署到另外的服务器,业务代码中通过RPC来委派任务
index.php
$proxy = new Proxy(); $proxy->getUserName(); $proxy->setUserName($id, $proxy);
Proxy.php
<?php
class Procy implemets IUserProxy {
function getUserName($id) {
$db = Factory::getDatabase('slave');
$db->query('select name from user where id = 1 limit 1');
}
function setUserName($id, $name) {
$db1 = Factory::getDatabase('master');
$db->query('update user name = $name from user where id = 1 limit 1');
}
}IUserProxy.php
<?php
interface IUserName {
function getUserName($id);
function setUserName($id, $name);
}