作为程序员一定要保持良好的睡眠,才能好编程

大话PHP设计模式

发布时间:2019-04-02

大话PHP设计模式

最常见的设计模式 工厂模式   单例模式  注册模式  这是最基本的PHP设计模式

还会有 适配器模式 、策略模式、数据映射模式(ORM)、观察者模式、原型模式、装饰器模式

设计模式并不是单独出现的,有时设计项目会用到多种设计模式,相结合,完成项目。

设计模式简要素:

1、单一类只做一件事

2、使用扩展来增加功能,而不可修改

3、通过依赖注入,不要直接写在类中   解耦合

4、尽可能的使用配置化,而不是硬编码

5、面向接口编程,面向对象编程。


公共方法:


function.php 代码实现:

//自动加载类
function __autoload($class){
    if(file_exists($class.".php")){
        include_once $class.".php";
    }
}

function P($str){
    echo "<pre style='font-size:22px;color:blue'>";
    print_r($str);
    echo "</pre>";
}



PSR-0 要求

1、要求命名空间与文件名保持一致

2、类名首字母必须大写

3、不能有执行文件



PHP面向对象高级特性

SPL库的使用(PHP标准库)


1、SplStack、SplQueue、SplHeap、SplFixedArray 数据结构类


栈 SplStack

//栈 后进先出  实现了  Iterator , ArrayAccess 相关接口
$stack=new SplStack();

$stack->push("abc");
$stack->push("def"); 

var_dump($stack->count());

$stack->add(1,"99999"); //可以动态向栈中添加数据,但是这个不太常用  1 是offset
var_dump($stack->count());

// var_dump($stack->pop());
// var_dump($stack->pop());
// var_dump($stack->pop());

//可以动态获取到栈中所有的数据
$stack->rewind();
while($stack->valid()){
    echo $stack->current(),"\n";
    $stack->next();
}

var_dump($stack->count());


队列 SplQueue SplQueue 类通过使用一个双向链表来提供队列的主要功能。

//队列 后进先出  实现了  Iterator , ArrayAccess 相关接口
$queue=new SplQueue();

$queue->push("abc");
$queue->push("def"); 

var_dump($queue->count());

//$queue->add(1,"99999"); //可以动态向栈中添加数据,但是这个不太常用  1 是offset
var_dump($queue->count());

var_dump($queue->pop());
var_dump($queue->pop());
// var_dump($queue->pop());

//可以动态获取到栈中所有的数据
/*$queue->rewind();
while($queue->valid()){
    echo $queue->current(),"\n";
    $queue->next();
}*/

var_dump($queue->count());


堆 

将数据insert到堆中

堆分2种,最小堆和最大堆,其实最大堆的实现和最小堆基本一样。最小堆的根是最小值,而最大堆的根是最大值,最小堆在某些判断上符号改变下就是最大堆了

$heap=new SplMinHeap();

$heap->insert(3);
$heap->insert(2);
$heap->insert(8);
$heap->insert(1);


var_dump($heap->extract());
var_dump($heap->extract());

int(1)

int(2)


最大堆

$heap=new SplMaxHeap();


$heap->insert(3);
$heap->insert(2);
$heap->insert(8);
$heap->insert(1);

var_dump($heap->extract());
var_dump($heap->extract());
var_dump($heap->extract());
var_dump($heap->extract());


var_dump($heap->isEmpty());


=====================
int(8)
int(3)
int(2)
int(1)
bool(true)
=====================


声明固定长度的数组

//不管有没有设置值,都会分配每一个的内存空间
// $array=new SplFixedArray(5);

// $array[0]=1;

// $array[1]=10;

$data=[0=>"abc",9=>"ccc"];

$array=SplFixedArray::fromArray($data,true);
var_dump($array);
var_dump($array->getSize());
var_dump($array->count());
var_dump($array->toArray());




2、ArrayIterator、AppendIterator、Countable、ArrayObject



3、SPL提供的函数






工厂模式

工厂方法 或类生成对象 而不是在代码中使用new关键字来创建


接口文件Food.php:

abstract class Food{

    abstract function cooking();

}

实现接口 面条类:

class Noodle extends Food{


    function cooking()
    {
        // TODO: Implement cooking() method.
        return "做面条";

    }
}

实现接口 饺子类:

class Dumpling extends Food{

    function cooking()
    {
        // TODO: Implement cooking() method.
        return "包饺子";
    }
}


工厂类:

require_once("../function.php");
class Factory{
    //做饭
    public static function cook($type){
        switch($type){
            case 1:
                return new Noodle();
                break;
            case 2:
                return new Dumpling();
                break;
            default:
                exit("传值错误");
                break;
        }
    }
}


调用实现:

require_once("../function.php");
$noodle=Factory::cook(1);
P($noodle);
P($noodle->cooking());

$dumpling=Factory::cook(2);
P($dumpling);
P($dumpling->cooking());



单例模式

使某个类的对象仅允许创建一次


单例类 Mysql:

class Mysql{
    public static $instance;
    public static function getInstance(){
        if(self::$instance instanceof self){
            return self::$instance;
        }else{
            $_obj=new Mysql();
            self::$instance=$_obj;
            return $_obj;
        }
    }
    //私有不能外部调用
    private  function __construct(){
        
    }
    public function p($str){
        echo $str;
    }
}


调用类:

//测试单例模式

require_once("../function.php");

$first=Mysql::getInstance();
$first->p("123");

$second=Mysql::getInstance();
$second->p("456");


P($first==$second);  //这是相等的  相同的一个类




注册模式

全局共享和交换对象


抽象类或接口:

abstract class Food{

    abstract function cooking();

}

实现类 面条类 Noodle.php

class Noodle extends Food{


    function cooking()
    {
        // TODO: Implement cooking() method.
        return "做面条";

    }
}


实现类 饺子类 Dumpling.php

class Dumpling extends Food{


    function cooking()
    {
        // TODO: Implement cooking() method.
        return "包饺子";

    }
}


工厂new新对象 Factory.php

class Factory{

    //生产一个noodle
    public  static function noodle(){
        return new Noodle();
    }
    
    //生产一个饺子
    public static function dumpling(){
        return new Dumpling();
    }

}


初始化类 init.php

Register::set("noodle",Factory::noodle());
Register::set("dumpling",Factory::dumpling());


使用类  index.php

include_once("../function.php");

//把noodle注册到Register上   初始化工作
include_once("init.php");


var_dump(Register::get("noodle"));
var_dump(Register::get("noodle"));
//这两个是同一个对象

//那么 noodle  这个对象直接获取就可以使用了

$noodle=Register::get("noodle");

P($noodle->cooking());


//与第二个不同
var_dump(new Noodle());



适配器模式

将所有的接口修改成统一的一个接口类型,就是适配

犹如 手机充电器接口




策略模式

不管声明哪个类,都是统一的API 操作


接口文件  strtaegy.php

interface Strategy{


    public function ad();
    public function faviator();


}

实现类  Man.php

class Man implements Strategy{


    public function ad()
    {
        // TODO: Implement ad() method.

        P("男士 广告");
    }

    public function faviator()
    {
        // TODO: Implement faviator() method.

        P("电脑  手机  游戏");


    }
}


实现类 Female.php

class Female implements Strategy{


    public function ad()
    {
        // TODO: Implement ad() method.
        P("女士广告");
    }

    public function faviator()
    {
        // TODO: Implement faviator() method.

        P("购物 裙子  内衣");
    }
}


调用 index.php

/**
 *
 * 使用说明:比如说  一个页面  根据不同的访问者  显示不同的爱好   那么怎么做?
 *
 *
 * 如果按照默认的方法  我们通过  if  else  来进行注册  执行不同的代码
 *
 * 那么如何进行改进呢,这就是策略模式   ,我们通过注册对象的形式  进行操作
 *
 *看代码:
 *
 *
 * 不同的策略  实现同一个接口  API   如同  适配器模式
 */

require_once "../function.php";

class Page{
    protected $strategy;
    public function index(){
        $this->strateg->ad();
        $this->strateg->faviator();
    }
    public function set(Strategy $strategy){
        $this->strateg=$strategy;
    }
}

$page=new Page();
if(isset($_GET['t']) && $_GET['t']=="female"){
    $page->set(new Female());
}else{
    $page->set(new Man());
}
$page->index();



数据映射模式

操作一个对象映射成对另外一个事物的操作。 比如说  操作 orm 对象  关系到  mysql数据库


ps:创建orm对象  有 增删改查  数据库连接  对一组对象的操作



观察者模式  又名:订阅模式

当一个对象状态发生变化是,依赖它的对象都会受到通知,并自动更新。

怎么算是依赖呢?


ps:一个时间发生后,要执行一连串的更新操作,传统的编程方式就是在事件代码后直接加入处理逻辑。当更新的逻辑增多后,就变得不好维护了。


简单举例说明: 同志们大家喝水   所有人都喝水   


同志们大家喝水  就是一个事件处理

所有人喝水  就是一个一个的人  并  喝水


这就是简单的例子 ,观察者模式

观察者模式多用于实现订阅功能的场景,例如微博的订阅,当我们订阅了某个人的微博账号,当这个人发布了新的消息,就会通知我们


当目标对象有变化的时候,观察者 就更新




下面我们举例来说下:


有两位老师  李老师  和 张老师  是目标对象


两位学生  是观察者


当老师 说 起立  的时候  观察者  就起立


当老师说 跑步 的时候 ,观察者就跑步


那么代码如何实现呢?





ObServer 这是观察者  就是学生  同学


观察者API

//这是观察者  API
interface ObServer{

    public function update($who,$message);


}


观察者实例1

//首先实现了第一个API 观察者1
class ObServerCustom1 implements ObServer{
    protected $name="同学1";
    public function update($who,$message){
        P($this->name.":{$who} ".$message);
    }

    public function __get($name){
        return $this->$name;
    }

}


观察者实例2

class ObServerCustom2 implements ObServer{
    protected $name="同学2";
    public function update($who,$message)
    {
        // TODO: Implement update() method.

        P($this->name.":{$who} ".$message);
    }

    public function __get($name){
        return $this->$name;
    }

}



ObjectEvent 这是目标对象


目标对象API

//这是一个对象 API 所有的都要实现这个API 才可以作为目标对象

interface ObjectEvent{
    public function setObServer(ObServer $obServer);
    public function notify($message);
}


目标 老师 TeacherEvent.php

//实现了所有的方法 可以作为一个目标对象使用
class TeacherEvent implements ObjectEvent{

    protected $_observer;
    protected $_name;

    public function __construct($_name){
        $this->_name=$_name;
    }

    public function setObServer(ObServer $obServer)
    {
        // TODO: Implement setObServer() method.
        $this->_observer[]=$obServer;
    }

    public function notify($message)
    {
        // TODO: Implement notify() method.
        if(sizeof($this->_observer)>0){
            foreach($this->_observer as $_obj){
                $_obj->update($this->_name,$message);
            }
        }
    }
}


实例index.php

require_once "../function.php";

//创建一个老师 目标对象
$teacher=new TeacherEvent("张老师");

//添加观察者  也就是学生
$stu1=new ObServerCustom1();
$stu2=new ObServerCustom2();

$teacher->setObServer($stu1);
$teacher->setObServer($stu2);

//老师说 起立  所有对象 所有人 收到指令后 更新一下
$teacher->notify("起立");


//创建一个老师 目标对象
$teacher2=new TeacherEvent("李老师");
$teacher2->setObServer($stu1);

$teacher2->notify("去跑步");

 

把一对多对象之间的通知依赖关系的变得更为松散,大大地提高了程序的可维护性和可扩展性,也很好的符合了开放-封闭原则。


原型模式


适用于大对象的创建。clone 创建知识内存拷贝。

原型模式与工厂模式类似,都是用来创建对象。与工厂模式不同的是,原型模式是先创建好一个原型对象,通过clone 来创建其他对象,免去了创建重复的初始化工作。


那么  clone 创建对象快   还是 通过 单例模式 获取快?   还是先注册好 以后获取快?

class Student{
    protected $name;
    protected $age;
    public function __construct($name,$age){
        $this->name=$name;
        $this->age=$age;
    }
    public function __set($name,$val){
        $this->$name=$val;
    }
    public function __get($name){
        return $this->$name;        
    }
}
//这是创建一个对象,那么创建原型对象,就是通过clone的方式来创建了
$stu1=new Student("job",14);
//创建原型对象
$stu2=clone $stu1;

等于创建了一个新的对象,做任何操作与stu1 无关



装饰器模式

可以动态添加修改类的功能,一个类提供了一项功能,如果要修改并添加额外的功能,传统的编程方式 就是继承,然后扩展功能。

那么以后再次需要 增加功能,怎么办?  也可以重新打开,再次编辑的。

那么如何在运行时,添加一个装饰器对象,即可实现最大的灵活性。


装饰器API Decorator.php

interface Decorator{

    public function beforeDraw();
    public  function afterDraw();
}


两个装饰器  一个文字变大  SizeDecorator.php

class SizeDecorator implements Decorator{


    public function beforeDraw()
    {
        // TODO: Implement beforeDraw() method.

        echo "<div style='font-size:30px;'>";

    }

    public function afterDraw()
    {
        // TODO: Implement afterDraw() method.
        echo "</div>";
    }
}


ColorDecorator.php

class ColorDecorator implements Decorator{

    public function beforeDraw()
    {
        // TODO: Implement beforeDraw() method.

        echo "<div style='color:blue'>";


    }

    public function afterDraw()
    {
        // TODO: Implement afterDraw() method.
        echo "</div>";
        echo "<p>我是添加了颜色</p>";
        echo "*********";

    }
}


实例 Photo.php

class Photo{

    public $decorator=[];

    //动态的把装饰器类注入进来
    public function addDecorator(Decorator $decorator){

        $this->decorator[]=$decorator;
    }

    //循环遍历
    public function beforeDraw(){
        if(sizeof($this->decorator)){
            foreach($this->decorator as $_obj){
                $_obj->beforeDraw();
            }
        }
    }

    public function afterDraw(){
        //这里需要把 decorator 翻转一下,先进 后出 和上边的匹配成一对
        if(sizeof($this->decorator)){
            $decorator=array_reverse($this->decorator);
            foreach($decorator as $_obj){
                $_obj->afterDraw();
            }
        }
    }

    //这就叫做装饰器模式
    public function draw(){
        $this->beforeDraw();
        for($i=1;$i<10;$i++){

            for($j=1;$j<8;$j++){
                echo "*";
            }
            echo "<br>";
        }
        $this->afterDraw();

    }

}



运行实例 index.php

include_once "../function.php";

$photo=new Photo();

//装饰器执行的顺序按照 添加的顺序执行的。

//增加装饰器  加大
$photo->addDecorator(new SizeDecorator());


//颜色
$photo->addDecorator(new ColorDecorator());

$photo->draw();


以上就是装饰器的编码。



代理模式

客户端与实体之间建立一个代理对象,客户端对实体的进行操作,全部委托给代理对象,隐藏实体具体细节。


这里最突出的代理模式是  Mysql主从数据库 读写的分离。


业务代码中 RPC来委派任务   proxy可以与业务代码分离 部署到另外服务器上


传统编程是:

//这是写操作
$mysql=mysql_connect($root,$username,$password);
mysql_select_db("a1");
mysql_query("set names utf8");

$sql="update user set username='123' where id=1;";
mysql_query($sql);
mysql_close();


//那么读操作

$mysql=mysql_connect($root,$username,$password);
mysql_select_db("b1");
mysql_query("set names utf8");
$sql="select * from user order by id desc limit 0,10;";
$result=mysql_query($sql);
$_objects=[]
while($_obj=mysql_fetch_object($res)!=false){
    $_objects[]=$_obj;
}
mysql_close();