您的位置 首页 php

php基础-设计模式

bigsmoker 51future 技术宅

大家好今天要给大家分享的是设计模式。首先来了解下什么是设计模式。其实所谓设计模式,就是前辈们在编程中遇到了些坑,为了使后人避免入坑所以写了写方法与套路——即设计模式。对于初学者来说,可能无法体会设计模式给编程带来的好处。以下就结合每个设计模式及其给编程带来什么好处来讲解设计模式。

一 简单工厂模式

请看如下代码

无模式
简单 工厂模式

<?php

class Op{

function getResult($a,$b,$flag)

{

$result = 0;

switch($flag) {

case ‘+’:

$result = $a+$b;

break;

case ‘-‘:

$result = $a-$b;

break;

}

return $result;

}

}

//客户端调用代码

$obj =new Op();

$obj->getResult(1,2,’-‘);

$obj->getResult(1,2,’+’);

<?php

class AddClass {

function getResult($a,$b)

{

return $a+$b;

}

}

class SubClass {

function getResult($a,$b)

{

return $a-$b;

}

}

class Factory {

private $obj = null;

function op($flag)

{

switch($flag) {

case “+”:

$this->obj = new AddClass();

break;

case “-“:

$this->obj = new SubClass();

break;

}

return $this->obj;

}

}

//客户端调用代码

$obj = new Factory();

var_dump($obj->op(‘-‘)->getResult(1,2),$obj->op(‘+’)->getResult(1,2))

通过以上对比看上去似乎工厂 模式没什么优势,反而多了很多代码,难道是画蛇添足不成。但是我们通过客户端调用,发现每次业务需求更改时(乘除,开方,等等),左边的程序需要更改服务端业务逻辑代码。(容易出bug)。而使用工厂模式后,因为我们将不同的运算逻辑放入不同的类中,用 Factory 类去调用不同的业务类。这样以前写好的逻辑不需要改变,只需要添加新的运算类,然后再Factory类中初始化新的运算类,减少了代码的高耦合。

关于简单工厂模式的优化

知道了什么是工厂模式,以及在编程上带来了什么好处,那我们再来谈谈这个工厂模式的不足。

首先,大家看到在上表的Factory类中几个调用类都是写好的, 不具备普适性

假如可以根据传入的对象类型 调用不同的运算逻辑。岂不是更好。

下面是工厂模式和优化后的模式的代码对比

简单 工厂模式
优化后的 简单 工厂模式

<?php

class AddClass {

function getResult($a,$b)

{

return $a+$b;

}

}

class SubClass {

function getResult($a,$b)

{

return $a-$b;

}

}

class Factory {

private $obj = null;

function op($flag)

{

switch($flag) {

case “+”:

$this->obj = new AddClass();

break;

case “-“:

$this->obj = new SubClass();

break;

}

return $this->obj;

}

}

//客户端调用代码

$obj = new Factory();

var_dump($obj->op(‘-‘)->getResult(1,2),$obj->op(‘+’)->getResult(1,2))

<?php

interface Alg {

function getResult($a,$b);

}

class AddClass implements Alg {

function getResult($a,$b)

{

return $a+$b;

}

}

class SubClass implements Alg {

function getResult($a,$b)

{

return $a-$b;

}

}

class Factory {

private $obj = null;

function op(Alg $algClass)

{

return $algClass;

}

}

//客户端调用代码

$obj = new Factory();

var_dump($obj->op(new SubClass())->getResult(1,2),$obj->op(new AddClass())->getResult(1,2))

哇塞!感觉是否立马清爽了很多,首先有个高度抽象的接口。再让相关运算类实现接口。形成多态。用factory类调用 普适类型 。省区了一大坨业务判断。是不是感觉好奇妙。

二 工厂方法模式

先将简单工厂模式与工厂方法模式的代码来个对比

简单工厂模式工厂方法模式

<?php

class AddClass {

function getResult($a,$b)

{

return $a+$b;

}

}

class SubClass {

function getResult($a,$b)

{

return $a-$b;

}

}

class Factory {

private $obj = null;

function op($flag)

{

switch($flag) {

case “+”:

$this->obj = new AddClass();

break;

case “-“:

$this->obj = new SubClass();

break;

}

return $this->obj;

}

}

//客户端调用代码

$obj = new Factory();

var_dump($obj->op(‘-‘)->getResult(1,2),

$obj->op(‘+’)->getResult(1,2))

<?php

interface IFactory {

function op();

}

class AddClass {

function getResult($a,$b)

{

return $a+$b;

}

}

class SubClass {

function getResult($a,$b)

{

return $a-$b;

}

}

class AddFactory implements IFactory {

function op()

{

return new AddClass();

}

}

class SubFactory implements IFactory {

function op()

{

return new SubClass();

}

}

//客户端调用代码

$subObj = new SubFactory();

$addObj = new AddFactory();

var_dump($subObj->op()->getResult(1,2),

$addObj->op()->getResult(1,2));

从比较代码后,我们发现简单工厂与工厂方法上唯一的不同就是工厂方法将运算逻辑分成不同的类并且实现了IFactory接口。那么这到底有什么好处呢?

请看,每次客户端调用时,表格左边的代码如果要加一个乘法运算那么是不是要修改Factory类?违背了“ 开放扩展,封闭修改的原则 ”,那么右边的代码就不一样了,只要添加乘法预算类逻辑,而不用更改先前写好的类,客户端 如下调用

$mulObj = new MulFactory();//乘法对象

$mul->op()->getResult(1,2)

象这样便可以了。

知道了工厂方法模式带来的好处,再谈谈这个模式的不足。其实也很明显。每次客户端调用都需要new 一个对应的运算类业务逻辑。代码多了以后,修改的地方会很多 ,很麻烦。所以需要优化。见如下代码

工厂方法模式优化后的工厂方法模式

<?php

interface IFactory {

function op();

}

class AddClass {

function getResult($a,$b)

{

return $a+$b;

}

}

class SubClass {

function getResult($a,$b)

{

return $a-$b;

}

}

class AddFactory implements IFactory {

function op()

{

return new AddClass();

}

}

class SubFactory implements IFactory {

function op()

{

return new SubClass();

}

}

//客户端调用代码

$subObj = new SubFactory();

$addObj = new AddFactory();

var_dump($subObj->op()->getResult(1,2),

$addObj->op()->getResult(1,2));

<?php

interface Alg {

function getResult($a,$b);

}

interface IFactory {

function op();

}

class AddClass implements Alg {

function getResult($a,$b)

{

return $a+$b;

}

}

class SubClass implements Alg {

function getResult($a,$b)

{

return $a-$b;

}

}

class SubFactory implements IFactory {

function op()

{

return new SubClass();

}

}

class AddFactory implements IFactory {

function op()

{

return new AddClass();

}

}

class Factory {

private $obj = null;

function createFac(IFactory $facClass)

{

return $facClass;

}

}

//客户端调用代码

$obj = new Factory();

var_dump($obj->createFac(new SubFactory())->op()->getResult(1,2),$obj->createFac(new AddFactory())->op()->getResult(1,2));

优化后代码调用就统一,可复用。修改时只要将工厂方法对象修改了就行
注意:

什么是 “开放扩展,封闭修改的原则” 简单来说就是设计好的类方法尽量不变,需求有变化,就加新的业务类去扩展。

三 单例模式

下面讲解下什么是单例模式。我们还是老规矩,先看下代码

new 创建对象
单例模式创建对象

<?php

interface MyIF {

function getValue();

}

class Test implements MyIF {

function __construct(){}

function getValue()

{

return 5;

}

}

//客户端调用代码

$obj = new Test();

var_dump($obj->getValue());

<?php

interface MyIF {

function getValue();

}

class TestSinglenten implements MyIF {

private static $ins = null;

private function __construct(){}

private function __clone(){}

public static function getInstance()

{

if (self::$ins == null)

{

return self::$ins = new Test();

}

return self::$ins;

}

function getValue()

{

return 5;

}

}

//客户端调用代码

var_dump(TestSinglenten::getInstance()->getValue());

大家可以看到 左边的代码很直观,就是new 一个对象,然后调用。而右边的代码有点罗里吧嗦。大家请注意看

private static $ins //private static 只能被本类引用

private function __construct() //防止在外部new 对象

private function __clone(){} //防止外部clone 对象

public static function getInstance() // 创建实例赋值给private static $ins,只赋值一次,是单例模式的关键所在

结果输出 :

int(5)

那说了那么多,这个单例模式又又什么好处呢?其实就是节省new对象时的内存资源。因为 getInstance() 会判断对象是否存在,不存在才给self::$ins 赋值对象。

四 观察者模式

试想这么个场景,某天老板出门办事,同事老孙,老张(关心股票),老李老秦(关心足彩)哈哈,一群赌狗在办公室打开各自的软件,畅聊着这几天的经历。这时老板杀了个回马枪。由于老孙比较了解老板。所以买通前台。只要老板回来,就发消息给他们。每次都能化解危机。果然是职场老油条。哈哈。那这个段子与观察者模式有什么关系呢?让我们言归正传。先来看段代码

<?php

//观察者接口

interface Observer {

function doEvent($key);//观察者们赶紧干活,老板回来了。

}

//订阅者接口

interface Subject {

function addObserver($key,Observer $ob);//添加观察者到列表,以便老板回来后,根据列表通知这些观察者

function removeObserver($key);//移除观察者

function notify();//通知列表中的观察者。

}

class StockMember implements Observer {

function doEvent($key)

{

echo $key.”,老板回来了,赶紧关掉股票界面,继续工作\n”;

}

}

class FootballMember implements Observer {

function doEvent($key)

{

echo $key.”,老板回来了,赶紧关掉足彩界面,继续工作\n”;

}

}

class Listener implements Subject {

public $observers = [];

function addObserver($key,Observer $ob)

{

$this->observers[$key] = $ob;

}

function removeObserver($key)

{

unset($this->observers[$key]);

}

function notify()

{

foreach($this->observers as $k=> $v)

{

$v->doEvent($k);

}

}

}

class FootballMember implements Observer {

function doEvent($key)

{

echo $key.”,老板回来了,赶紧关掉足彩界面,继续工作\n”;

}

}

class Listener implements Subject {

public $observers = [];

function addObserver($key,Observer $ob)

{

$this->observers[$key] = $ob;

}

function removeObserver($key)

{

unset($this->observers[$key]);

}

function notify()

{

foreach($this->observers as $k=> $v)

{

$v->doEvent($k);

}

}

}

以上代码实现了通知观察者,老板回来了,赶紧干活!!!

结果输出 :

老孙,老板回来了,赶紧关掉股票界面,继续工作

老张,老板回来了,赶紧关掉股票界面,继续工作

老李,老板回来了,赶紧关掉足彩界面,继续工作

老秦,老板回来了,赶紧关掉足彩界面,继续工作

哎,虽然不太厚道,不过还是很生动的一个例子

五 注册表模式

话说王老板设擂台比武招亲,欲将爱女嫁给擂台得胜冠军。王家大小姐长得是倾国倾城。这是大家都知道的事。于是乎,一呼百应。适婚男士们纷至沓来。摩拳擦掌,跃跃欲试。最终有个其貌不扬的家伙赢得比赛冠军。可老丈人和小姐看了都不满意。怎么办呢?至此危难之际,比赛组织者瞧出端倪。他看了下这位冠军的个人信息,发现有一个地方并不十分符合报名要求。于是乎借此取消了此人的冠军资格。至于比武招亲一事又不了了之。各位看官,看出点什么来了吗?没错,这个故事告诉我们做任何事情之前一定要先了解规则,要知道,即便是 暗韵 规则,最后获得胜利。也不能保证你就是那个胜利者。么错,因为规则是别人定的,你在别人的地盘, 得按照别人的规矩做事。这就是注册表模式。将某个对象先报上名来。然后按照规则才能让你运行。

请看以下代码

<?php

class Reg {

private $ins = null;

private static $objArr = null;

private function __construct(){}

private function __clone(){}

static function set($key,$val)

{

if($key != “cat”)

{

self::$objArr[$key] = $val;

}

echo “你是猫,不能参加比赛”

}

static function get($key)

{

return self::$objArr[$key];

}

}

class Dog {

function Say()

{

echo “大家好,我是一只旺”;

}

}

class Cat {

function Say()

{

echo “大家好,我是一只喵”;

}

}

//猫猫狗狗的都到碗里来!!!,否则没饭吃( 任何对象都得先注册,才能有资格运行

Reg::set(‘dog’,new Dog());

Reg::set(‘cat’,new Cat());

var_dump(Reg::get(‘dog’)->Say());


六 代理模式

王经理是一家房地产中介的销售主管,一天有位客户来他小店看房。要是平时他也就让小弟小妹接手这个客户了,但是听说这位老先生说要买个1000多平方的房子,正好看上了他这的一个豪宅房源。王经理一得到消息,立马亲自接待。虚寒温暖。一番谈话之后。这位老先生说他是来给他孙儿买房的。但是他不久后就要出国。所以这段时间,希望这个房源能给他保留。那王经理一听,觉得是个机会,于是边说:”老人家,这个房源很是抢手,如果等你回来,恐怕这房子就被别的买家买了“。老先生一听,也就急了。王经理是职场老手,见刚才那话起了效果,又假装安慰老先生,说:”您不用着急,这种事,您可招代理替您代办,您只管出国办自己的事情去,一切交给委托的代理就行了“。

老先生听了王经理的介绍,就高高兴兴的出国,委托代理给他办了买房的事情。出国办事两不误。那这个故事跟代理模式又什么关系呢?别急让我们看下面这一段代码

普通的模式
代理模式
<?php

class Caller {

//老先生买房

function buyHouse($houseId)

{

$p = new OldMan();

$p->buyHouse($houseId);

}

//通过代理买房

function __call($func,$arg)

{

$p = new Proxy();

call_user_func_array(array($p, $func), array($arg[0]));

}

}

class Proxy {

function buyHouse($houseId)

{

echo “我要替老先生买”.$houseId.”这套房子”;

}

}

class OldMan {

function buyHouse($houseId)

{

echo “我要买”.$houseId.”这套房子”;

}

}

class House {

private $houseId = 0;

function __construct($id)

{

$this->houseId = $id;

}

function getHouse()

{

return $this->houseId;

}

}

//客户端调用

$houseIdList= [1,3,2];

$c = new Caller();

$h = new House($houseIdList[0]);

$c->buyHouse($h->getHouse());

<?php

class Caller {

function __call($func,$arg)

{

$p = new Proxy();

call_user_func_array(array($p, $func), array($arg[0]));

}

}

class Proxy {

function buyHouse($houseId)

{

echo “我要替老先生买”.$houseId.”这套房子”;

}

}

class House {

private $houseId = 0;

function __construct($id)

{

$this->houseId = $id;

}

function getHouse()

{

return $this->houseId;

}

}

//客户端调用

$houseIdList= [1,3,2];

$c = new Caller();

$h = new House($houseIdList[0]);

$c->buyHouse($h->getHouse());

右面的buyHouse是老先生自己买房,但是如果老先生不在,那就委托右边的代理买房。注意右边使用了__Call魔术方法,只要在客户端调用buyHouse时 ,Caller 类中没有buyHouse方法,就会执行__call 方法去调用Proxy代理来买房。

其实还有很多模式,如何依赖倒置,适配器等等。有兴趣的同学自己可以去看看。设计模式就先讲到这里,接下来要讲得是如何一步步设计mvc模式得架构。同学们 敬请期待。下期再见

文章来源:智云一二三科技

文章标题:php基础-设计模式

文章地址:https://www.zhihuclub.com/76510.shtml

关于作者: 智云科技

热门文章

网站地图