Home >Backend Development >PHP Tutorial >PHP十二种设计模式

PHP十二种设计模式

WBOY
WBOYOriginal
2016-06-23 13:33:40937browse

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 "

";
}
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.使用代理模式实现数据库的主从自动切换
Statement:
The content of this article is voluntarily contributed by netizens, and the copyright belongs to the original author. This site does not assume corresponding legal responsibility. If you find any content suspected of plagiarism or infringement, please contact admin@php.cn