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模式得架构。同学们 敬请期待。下期再见