Home > Article > Backend Development > PHP十二种设计模式
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 "