PHP十二种设计模式
程序员文章站
2022-05-19 14:13:31
PSR-0规范的设计基础
1.全部使用命名空间
2.所有php文件必须自动载入,不能有include/require
spl_autoload_register
3.单一入口模式...
PSR-0规范的设计基础
1.全部使用命名空间
2.所有php文件必须自动载入,不能有include/require
spl_autoload_register
3.单一入口模式
1.三种基本的设计模式
工厂模式
用一个工厂方法去替换掉一个new
class Factory{
static function createDatabase(){
$db = new Database;
return $db;
}
}
使用的时候就可以用 $db = Factory::createDatabase();
单例模式
class Database{
private $db;
private function __construct(){
//这里可以写连接数据库
}
static function getInstance(){
if(self::$db){
return self::$db;
}else{
self::$db=new self()
return self::$db;//private可以自身调用
}
}
function where(){
}
}
如果是工厂加单例模式
class Factory{
static function createDatabase(){
$db = Database::getInstance();
return $db;
}
}
注册器(树)模式
class Register{
protected static $object;
static function set($alias,$object){
self::$object[$alias]=$object;
}
static function get($name)
{
return self::$object[$name];
}
function _unset($alias){
unset(self::$object[$alias]);
}
}
跟工厂方法结合
class Factory{
static function createDatabase(){
$db = Database::getInstance();
Register::set('db1',$db);
return $db;
}
}
索引直接调用
$db = Register::get('db1');
适配器模式
1.适配器模式,可以将截然不同的函数接口封装成统一的API
2.实际应用举例,PHP的数据库操作有mysql,mysqli,pdo3种,可以用适配器模式
统一成一致,类似的场景还有cache适配器,将memcache,redis,file,apc等不同的缓存函数,统一成一致,
比如说有一个Database.php里面有一个接口
interface IDatabase
{
function connect($host,$user,$pwd,$dbname);
function query($sql);
function close();
}
再下面有三个类
class mysql implements IDatabase{
private $con;
function connect($host,$user,$pwd,$dbname){
$this->con = mysql_connect($host,$user,$pwd);
mysql_select_db($dbname,$this->con);
}
function query($sql){
return mysql_query($sql,$this->con);
}
function close(){
return mysql_close($this->con);
}
}
class mysqli implements IDatabase{
protected $con;
function connect($host,$user,$pwd,$dbname)
{
$this->con = mysqli_connect($host,$user,$pwd,$dbname);
}
function query($sql)
{
return mysqli_query($this->con,$sql);
}
function close()
{
return mysqli_close($this->con);
}
}
class PDO implements IDatabase{
protected $con;
function connect($host,$user,$pwd.$dbname)
{
$con = new \PDO("mysql:host=$host;dbname=$dbname",$user,$pwd);
$this->con=$con;
}
function query($sql){
return $this->con->query($sql);
}
function close(){
unset($this->con);
}
}
这样我们调用的时候
$db = new mysql();或new mysqli();或new PDO();
$db->connect('127.0.0.1','root','root');
$db->query();
$db->close();
策略模式
将一组特定的行为和算法封装成类,以适应某些特定的上下文环境,这种模式就是策略模式
实际应用距离,假如一个电商系统的网站系统,针对男性女性用户要各自跳转到不同的商品类别
首先声明一个策略的接口文件
interface UserStrategy{
function showAd();
function showcategory();
}
//第一个策略 针对女性用户
class femaleUserStrategy implements UserStrategy{
function showAd(){
echo '2014新款女装';
}
function showCategory()
{
echo '女装';
}
}
//第二个策略,针对于男性用户
class maleUserStrategy implements UserStrategy{
function showAd(){
echo '2014新款男装';
}
function showCategory()
{
echo '男装';
}
}
//如果有一个page类
class page{
protected $strategy;
function index(){
$this->strategy->showAd();
$this->strategy->showCategory();
}
function setStrategy(\UserStrategt $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语句映射成对象属性的操作
class User{
public $id;
public $name;
public $mobile;
public $regtime;
protected $db;
function __construct($id){
//先取数据
$this->db = new mysql();
$this->db->connect('xxxxx'xxxx);
$res = $this->db->query('select * from XXX where id = {$id}');
$data = $res->fetch_assoc();
$this->id=$data['id'];
$this->name=$data['name'];
$this->mobile=$data['mobile'];
$this->regtime=$data['regtime'];
return $res;
}
function __destruct(){
//可以作为修改使用
$this->db->query('update xx set name={$this->name} mobile={$this->mobile}XXXXX where id = {$this->id}');
}
}
$user = new User(1);//1对应数据库中id为一
$user->mobile = '155555555';
$user->name='test';
$user->regtime=time();
//在这里没有sql语句.只有对对象的操作
综合运用(工厂模式,注册器模式,适配器模式)
与
观察者模式
1.观察者模式,当一个对象状态发生改变时,依赖他的对象全部会收到通知,并自动更新。
2.场景:一个事件发生后,要执行一连串更新操作,传统的编程方式,就
是在事件的代码之后直接加入处理逻辑,当更新的逻辑增多之后,代码会变得难以维护,这种方式是耦合的,侵入式的,
增加心的逻辑需要修改事件主体的代码
3.观察者模式实现了低耦合,非侵入式的通知更新机制。
demo
class Event{
function trigger(){
echo "Event";//表示事件发生了
//开始写更新逻辑了
echo '逻辑1';
echo '逻辑2';
echo '逻辑3';
}
}
$event = new Event();//传统的方式是耦合的,侵入式的,
//必须要改源码,所以我们定义一个观察者模式
demo
//在来一个接口
//先来一个基类抽象类
abstract class EventGenerator{
private $observers = array();
function addObserver(Observer$observer){
$this->obervers[]=$oberver;
}
function notify(){
foreach($this->obervers as $observer)
{
$observer->updata();
}
}
}
interface Oberver{
function update($event_info = null);
}
//所以说这个时候我们需要Event类继承这个基类
class Event extends EventGenerator{
function trigger(){
echo "Event";//表示事件发生了
$this->notify();
}
}
class Observer1 implements Observer{
function updata($event_info=null)
{
echo "逻辑一";
}
}
class Oberver2 implements Oberver{
function updata($event_info=null)
{
echo "逻辑二";
}
}
原型模式
1.与工厂模式作用类似,都是用来创建对象
2.与工厂模式的实现不同,原型模式先创建好一个原型
对象,然后通过clone原型对象来创建新的对象,这样就免去了类
创建时重复的初始化操作
3.原型模式适合于大对象的创建,创建一个大对象需要很大的开销,如果每次new就会消耗很大,
原型模式仅仅拷贝内存即可。
假如有一个画布类。new很复杂
我又想使用他两次
这样我们就可以用原型模式解决new的问题,用clone替代new
初始化之后直接clone即可。
装饰器模式
1.装饰器模式,可以动态的添加修改类的功能。
2.一个类提供了一项功能,如果要在修改并添加额外的功能,传统的
编程模式,需要写一个子类继承他,并重新实现类的方法。
3.使用装饰器模式,仅需在运行时添加一个装饰器对象即可实现,可以实现最大的灵活性
如果我们有一个画布类。只能打印一个正方形,假如我们想要添加一个颜色
一般是写一个子类,继承那个画布类。
重写产生画布的方法。那我们如果要增加很多功能呢?
是不是要重写很多类?
下面我们用装饰器模式解决这个问题
首先我们先声明一个画布的装饰器的接口
interface DrawDecorator{
function beforeDraw();
function afterDraw();
}
比如我们要修改画布类的draw()方法
所以我们在draw()方法中调用
function draw(){
$this->beforeDraw();
//这里是原来代码的内容
$this->afterDraw();
}
再在画布类中添加一个protected $decorators[]=array();
在添加一个方法,用来接收装饰器接口
function addDecorator(DrawDecorator $decorator){
$this->decorators[]=$decorator;
}
再添加两个调用装饰器的方法
function beforeDraw(){
foreach($this->decorators as $decorator)
{
$decorator->beforeDraw();
}
}
function afterDraw(){
//进行反转,后进先出
$decorators = array_reverse($this->decorators);
foreach($decorators as $decorator)
{
$decorator->afterDraw();
}
}
我们有一个颜色装饰器
class ColorDrawDecorator implements DrawDecorator{
protected $color;
function __construct($color='red')
{
$this->color= $color;
}
function beforDraw()
{
echo "
}
}
在这里就不用去继承去实现了
$a = new canvas();//实例化画布类
$a -> init();//初始化
$a -> addDecorator(new colorDrawDecorator('green'));//添加一个颜色的装饰器类
迭代器模式
1.迭代器模式,在不需要了解内部实现的前提下,遍历yige
聚合对象的内部元素
2.相比传统的编程模式,迭代器模式可以隐藏遍历元素的所需的操作
比如遍历一个数据库,然后拿到所有对象
class Alluser implements Iterator{
protected $ids;
protected $index;//迭代器当前位置
protected $data=array();
//Iterator为迭代器接口
fucntion __construct(){
$db = Factory::getDatabase();
$result = $db->query("selecy id from user");
$this->ids = $db->mysql_fetch_assoc($result);
}
function current(){
//获取当前元素
$id=$this->ids[$this->index]['id'];
return Factory::getUser($id);
}
function next(){
//下一个元素
$this->index ++;
}
function valid()
{
//判断是否有数据
return $this->index ids);
}
function rewind(){
$this->index=0;//第一步到开头
}
function key(){
//获取当前索引
return $this->index;
}
}
$users = new Alluser();
foreach ($users as $user)
{
var_dump($user);
}
代理模式
1.在客户端与实体之间建立一个代理对象(proxy),客户端对实体进行操作全部委派给代理对象,隐藏实体具体实现细节。
就是写一个
面向对象编程的基本原则
1.单一职责:一个类,只需要做好一件事情
2.开放封闭:一个类,应该是可扩展的,而不可修改的
3.依赖倒置:一个类,不应该强依赖另外一个类,每个类对于另外一个类都是可替换的
4.配置化:尽可能的使用配置,而不是硬编码。
5.面向接口编程:只需要关心接口,不需要关心实现。
MVC架构原理
我们先new 一个Config的对象
$config = new Config(__DIR__.'/configs');
$config['controller'];
那么有一个Config类
class Config implements \ArrayAccess{
//ArrayAccess接口是内置的接口,表示允许数组传值,其中有要实现四个方法
protected $path;
protected $configs=array();
function __construct($path)
{
$this->path=$path;
}
function offsetGet($key){
//获取该配置数组文件名key
if(empty($this->configs[$key]))
//如果原配置文件中不存在该数组文件名,那么就去加载
{
$file_path=$this->path.'/'.$key.'.php';//生成加载路径
$config = require $file_path;
$this->config[$key]=$config;
}
return $this->configs[$key];
}
function offsetSet($key,$value)
{
//设置数组的key
}
function offsetExists($key)
{ //检测数组的key是否存在
return isset($this->configs[$key]);
}
function offsetUnset($key)
{ //删除数组的key
}
}
配置文件比如controller.php
$config = array(
'home'=>array(
'decorator'=>array(
'IMooc\Dectorator\Template',
),
),
);
配置与设计模式
1.PHP中使用ArrayAccess实现配置文件的加载
2.在工厂方法中读取配置,生成可配置化的对象
3.使用装饰器模式实现权限验证,模板渲染,json串化
4.使用观察者模式实现数据更新事件的一系列更新操作
5.使用代理模式实现数据库的主从自动切换
1.全部使用命名空间
2.所有php文件必须自动载入,不能有include/require
spl_autoload_register
3.单一入口模式
1.三种基本的设计模式
工厂模式
用一个工厂方法去替换掉一个new
class Factory{
static function createDatabase(){
$db = new Database;
return $db;
}
}
使用的时候就可以用 $db = Factory::createDatabase();
单例模式
class Database{
private $db;
private function __construct(){
//这里可以写连接数据库
}
static function getInstance(){
if(self::$db){
return self::$db;
}else{
self::$db=new self()
return self::$db;//private可以自身调用
}
}
function where(){
}
}
如果是工厂加单例模式
class Factory{
static function createDatabase(){
$db = Database::getInstance();
return $db;
}
}
注册器(树)模式
class Register{
protected static $object;
static function set($alias,$object){
self::$object[$alias]=$object;
}
static function get($name)
{
return self::$object[$name];
}
function _unset($alias){
unset(self::$object[$alias]);
}
}
跟工厂方法结合
class Factory{
static function createDatabase(){
$db = Database::getInstance();
Register::set('db1',$db);
return $db;
}
}
索引直接调用
$db = Register::get('db1');
适配器模式
1.适配器模式,可以将截然不同的函数接口封装成统一的API
2.实际应用举例,PHP的数据库操作有mysql,mysqli,pdo3种,可以用适配器模式
统一成一致,类似的场景还有cache适配器,将memcache,redis,file,apc等不同的缓存函数,统一成一致,
比如说有一个Database.php里面有一个接口
interface IDatabase
{
function connect($host,$user,$pwd,$dbname);
function query($sql);
function close();
}
再下面有三个类
class mysql implements IDatabase{
private $con;
function connect($host,$user,$pwd,$dbname){
$this->con = mysql_connect($host,$user,$pwd);
mysql_select_db($dbname,$this->con);
}
function query($sql){
return mysql_query($sql,$this->con);
}
function close(){
return mysql_close($this->con);
}
}
class mysqli implements IDatabase{
protected $con;
function connect($host,$user,$pwd,$dbname)
{
$this->con = mysqli_connect($host,$user,$pwd,$dbname);
}
function query($sql)
{
return mysqli_query($this->con,$sql);
}
function close()
{
return mysqli_close($this->con);
}
}
class PDO implements IDatabase{
protected $con;
function connect($host,$user,$pwd.$dbname)
{
$con = new \PDO("mysql:host=$host;dbname=$dbname",$user,$pwd);
$this->con=$con;
}
function query($sql){
return $this->con->query($sql);
}
function close(){
unset($this->con);
}
}
这样我们调用的时候
$db = new mysql();或new mysqli();或new PDO();
$db->connect('127.0.0.1','root','root');
$db->query();
$db->close();
策略模式
将一组特定的行为和算法封装成类,以适应某些特定的上下文环境,这种模式就是策略模式
实际应用距离,假如一个电商系统的网站系统,针对男性女性用户要各自跳转到不同的商品类别
首先声明一个策略的接口文件
interface UserStrategy{
function showAd();
function showcategory();
}
//第一个策略 针对女性用户
class femaleUserStrategy implements UserStrategy{
function showAd(){
echo '2014新款女装';
}
function showCategory()
{
echo '女装';
}
}
//第二个策略,针对于男性用户
class maleUserStrategy implements UserStrategy{
function showAd(){
echo '2014新款男装';
}
function showCategory()
{
echo '男装';
}
}
//如果有一个page类
class page{
protected $strategy;
function index(){
$this->strategy->showAd();
$this->strategy->showCategory();
}
function setStrategy(\UserStrategt $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语句映射成对象属性的操作
class User{
public $id;
public $name;
public $mobile;
public $regtime;
protected $db;
function __construct($id){
//先取数据
$this->db = new mysql();
$this->db->connect('xxxxx'xxxx);
$res = $this->db->query('select * from XXX where id = {$id}');
$data = $res->fetch_assoc();
$this->id=$data['id'];
$this->name=$data['name'];
$this->mobile=$data['mobile'];
$this->regtime=$data['regtime'];
return $res;
}
function __destruct(){
//可以作为修改使用
$this->db->query('update xx set name={$this->name} mobile={$this->mobile}XXXXX where id = {$this->id}');
}
}
$user = new User(1);//1对应数据库中id为一
$user->mobile = '155555555';
$user->name='test';
$user->regtime=time();
//在这里没有sql语句.只有对对象的操作
综合运用(工厂模式,注册器模式,适配器模式)
与
观察者模式
1.观察者模式,当一个对象状态发生改变时,依赖他的对象全部会收到通知,并自动更新。
2.场景:一个事件发生后,要执行一连串更新操作,传统的编程方式,就
是在事件的代码之后直接加入处理逻辑,当更新的逻辑增多之后,代码会变得难以维护,这种方式是耦合的,侵入式的,
增加心的逻辑需要修改事件主体的代码
3.观察者模式实现了低耦合,非侵入式的通知更新机制。
demo
class Event{
function trigger(){
echo "Event";//表示事件发生了
//开始写更新逻辑了
echo '逻辑1';
echo '逻辑2';
echo '逻辑3';
}
}
$event = new Event();//传统的方式是耦合的,侵入式的,
//必须要改源码,所以我们定义一个观察者模式
demo
//在来一个接口
//先来一个基类抽象类
abstract class EventGenerator{
private $observers = array();
function addObserver(Observer$observer){
$this->obervers[]=$oberver;
}
function notify(){
foreach($this->obervers as $observer)
{
$observer->updata();
}
}
}
interface Oberver{
function update($event_info = null);
}
//所以说这个时候我们需要Event类继承这个基类
class Event extends EventGenerator{
function trigger(){
echo "Event";//表示事件发生了
$this->notify();
}
}
class Observer1 implements Observer{
function updata($event_info=null)
{
echo "逻辑一";
}
}
class Oberver2 implements Oberver{
function updata($event_info=null)
{
echo "逻辑二";
}
}
原型模式
1.与工厂模式作用类似,都是用来创建对象
2.与工厂模式的实现不同,原型模式先创建好一个原型
对象,然后通过clone原型对象来创建新的对象,这样就免去了类
创建时重复的初始化操作
3.原型模式适合于大对象的创建,创建一个大对象需要很大的开销,如果每次new就会消耗很大,
原型模式仅仅拷贝内存即可。
假如有一个画布类。new很复杂
我又想使用他两次
这样我们就可以用原型模式解决new的问题,用clone替代new
初始化之后直接clone即可。
装饰器模式
1.装饰器模式,可以动态的添加修改类的功能。
2.一个类提供了一项功能,如果要在修改并添加额外的功能,传统的
编程模式,需要写一个子类继承他,并重新实现类的方法。
3.使用装饰器模式,仅需在运行时添加一个装饰器对象即可实现,可以实现最大的灵活性
如果我们有一个画布类。只能打印一个正方形,假如我们想要添加一个颜色
一般是写一个子类,继承那个画布类。
重写产生画布的方法。那我们如果要增加很多功能呢?
是不是要重写很多类?
下面我们用装饰器模式解决这个问题
首先我们先声明一个画布的装饰器的接口
interface DrawDecorator{
function beforeDraw();
function afterDraw();
}
比如我们要修改画布类的draw()方法
所以我们在draw()方法中调用
function draw(){
$this->beforeDraw();
//这里是原来代码的内容
$this->afterDraw();
}
再在画布类中添加一个protected $decorators[]=array();
在添加一个方法,用来接收装饰器接口
function addDecorator(DrawDecorator $decorator){
$this->decorators[]=$decorator;
}
再添加两个调用装饰器的方法
function beforeDraw(){
foreach($this->decorators as $decorator)
{
$decorator->beforeDraw();
}
}
function afterDraw(){
//进行反转,后进先出
$decorators = array_reverse($this->decorators);
foreach($decorators as $decorator)
{
$decorator->afterDraw();
}
}
我们有一个颜色装饰器
class ColorDrawDecorator implements DrawDecorator{
protected $color;
function __construct($color='red')
{
$this->color= $color;
}
function beforDraw()
{
echo "
";
}
function afterDraw()
{
echo "
}
}
在这里就不用去继承去实现了
$a = new canvas();//实例化画布类
$a -> init();//初始化
$a -> addDecorator(new colorDrawDecorator('green'));//添加一个颜色的装饰器类
迭代器模式
1.迭代器模式,在不需要了解内部实现的前提下,遍历yige
聚合对象的内部元素
2.相比传统的编程模式,迭代器模式可以隐藏遍历元素的所需的操作
比如遍历一个数据库,然后拿到所有对象
class Alluser implements Iterator{
protected $ids;
protected $index;//迭代器当前位置
protected $data=array();
//Iterator为迭代器接口
fucntion __construct(){
$db = Factory::getDatabase();
$result = $db->query("selecy id from user");
$this->ids = $db->mysql_fetch_assoc($result);
}
function current(){
//获取当前元素
$id=$this->ids[$this->index]['id'];
return Factory::getUser($id);
}
function next(){
//下一个元素
$this->index ++;
}
function valid()
{
//判断是否有数据
return $this->index ids);
}
function rewind(){
$this->index=0;//第一步到开头
}
function key(){
//获取当前索引
return $this->index;
}
}
$users = new Alluser();
foreach ($users as $user)
{
var_dump($user);
}
代理模式
1.在客户端与实体之间建立一个代理对象(proxy),客户端对实体进行操作全部委派给代理对象,隐藏实体具体实现细节。
就是写一个
面向对象编程的基本原则
1.单一职责:一个类,只需要做好一件事情
2.开放封闭:一个类,应该是可扩展的,而不可修改的
3.依赖倒置:一个类,不应该强依赖另外一个类,每个类对于另外一个类都是可替换的
4.配置化:尽可能的使用配置,而不是硬编码。
5.面向接口编程:只需要关心接口,不需要关心实现。
MVC架构原理
我们先new 一个Config的对象
$config = new Config(__DIR__.'/configs');
$config['controller'];
那么有一个Config类
class Config implements \ArrayAccess{
//ArrayAccess接口是内置的接口,表示允许数组传值,其中有要实现四个方法
protected $path;
protected $configs=array();
function __construct($path)
{
$this->path=$path;
}
function offsetGet($key){
//获取该配置数组文件名key
if(empty($this->configs[$key]))
//如果原配置文件中不存在该数组文件名,那么就去加载
{
$file_path=$this->path.'/'.$key.'.php';//生成加载路径
$config = require $file_path;
$this->config[$key]=$config;
}
return $this->configs[$key];
}
function offsetSet($key,$value)
{
//设置数组的key
}
function offsetExists($key)
{ //检测数组的key是否存在
return isset($this->configs[$key]);
}
function offsetUnset($key)
{ //删除数组的key
}
}
配置文件比如controller.php
$config = array(
'home'=>array(
'decorator'=>array(
'IMooc\Dectorator\Template',
),
),
);
配置与设计模式
1.PHP中使用ArrayAccess实现配置文件的加载
2.在工厂方法中读取配置,生成可配置化的对象
3.使用装饰器模式实现权限验证,模板渲染,json串化
4.使用观察者模式实现数据更新事件的一系列更新操作
5.使用代理模式实现数据库的主从自动切换
推荐阅读