laravel之设计模式

更新:这篇文章已经不推荐阅读,大家想了解 PHP 的设计模式,建议阅读这篇文章:

https://laravel-china.org/docs/php-design-patterns/2018/php-design-pattern-reading-list/1525

laravel的面向对象编程:

1:使用namespace防止命名冲突

2:使用autoload来自动加载函数

使用ArrayAccess实现配置文件的加载,使一个对象可以通过数组的方式访问。

class Config implements \ArrayAccess {

        protected $path;

        protected $configs = array();

        function __construct($path) {

                $this->path = $path;

        }

        function offsetGet($key) {

                if (empty($this->configs[$key])) {

                        $file_path = $this->path.'/'.$key.'.php';

                        $config = require $file_path;

                        $this->configs[$key] = $config;

                }

                return $this->configs[$Key];

        }

        function offsetSet($key, $value) {

                throw new \Exception("cannot write config file.");

        }

        function offsetExists($key) {

                return isset($this->configs[$key];

        }

        function offsetUnset($key) {

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

        }

$config = array(

        'home' = array(

                'someFile' = array(

                       //filePath,

                       ……

                ),

        ),

        'other'……

)

return $config;

$config = new Config(__dirname__.'/configs');

$whatkey = $config['what_key'];

3:psr-4规范

4:链式调用

只要在方法的最后:return $this;

5:魔术方法

1)访问不存在的属性,__set()和__get()

2)调用不存在的方法 __call()和__callstatic()

3)对象作为字符串使用,__toString()

4)对象作为方法使用,__invoke()

6:单一职责

一个文件只有一个类,一个类只做好一件事,尽量不要复杂。

7:开放封闭原则

一个类的功能应该是可扩展而不可修改的。

8:依赖倒置

一个类不应该强依赖另一个类,每个类对于另一个类都是可替换的。

9:配置化

尽可能的使用配置而不是硬编码。

10:面向接口编程

只需要关心接口,不需要关心实现。


1:工厂模式

例如:Auth::user()

此处Auth这个类就是工厂中的方法,Auth是注册树中的别名。

好处:

类似于函数的封装,使对象有一个统一的生成(实例化)入口。当我们对象所对应的类的类名发生变化的时候,我们只需要改一下工厂类类里面的实例化方法即可。

2:单例模式

好处:

对象不可外部实例化并且只能实例化一次,节省资源。

实现方式:

private static $ins = null;                                                //设置私有的属性

private function __construct() {}                                       //使外部无法new这个类

public static function getIns() {                                        //暴露给外部的调用方法

        if(self::$ins instanceof self) {

                return self::$ins;

        } else {

                self::$ins = new self();

                return self::$ins;

        }

}

声明一个类的私有或者保护的静态变量,构造方法声明为私有(不允许外部进行new操作),如果不存在则实例化它,然后返回,如果存在则直接返回。

3:注册树模式

使用:

config/app里的aliases数组便是一个注册树

好处:

注册树模式就是使用数组结构来存取对象,工厂方法只需要调用一次(可以放到系统环境初始化这样的地方),以后需要调用该对象的时候直接从注册树上面取出来即可,不需要再调用工厂方法和单例模式。

实现方法:

class Register {

        protected static $objects

        function set($alias,$object) {                            //将对象映射到全局树上

                self::$objects[$alias]=$object;

        }

        static function get($name) {                             //获取对象

                return self::$objects[$name];

        }

        function _unset($alias) {                                  //从全局树移除对象

                unset(self::$onjects[$alias]);

        }

}

$alias表示别名,自己设定

在工厂模式中添加

Register::set('db1',$db);

其他任何地方调用只需要调用注册器读取即可

Register::$objects['db1'];

4:适配器模式

将不同工具的不同函数接口封装成统一的API,方便调用。如:mysql,mysqli,PDO。

实现:在接口类里面申明统一的方法体,再让不同的类去实现这个接口,和重写其抽象方法。

interface Database {                                                  

        function connect($host,$user,$password,$dbname);

        function query($sql);

        function close();

}

然后再去用不同的工具函数去实现相同的接口。

5:策略模式

好处:

将一组特定的行为和算法封装成类,以适应某些特定的上下文环境,将逻辑判断和具体实现分离,实现了硬编码到解耦,并可实现IOC、依赖倒置、反转控制。

实现:

1.定义一个策略接口文件(UserStrategy.php),定义策略接口,声明策略

2.定义具体类(FemaleUserStrategy.php,MaleUserStrategy.php),实现策略接口,重写策略方法

class Page {

        protected $strategy;

        function index() {

                if($request->get('female')) {

                        $strategy=new FemaleUserStrategy();

                } else {

                        $strategy=new MaleUserStrategy();

                }

                $this->strategy->method();

        }

        public function __construct(UserStrategy $strategy) {

                $this->strategy=$strategy;

        }

}

6:数据对象映射模式

好处:将对象和数据存储映射起来,对一个对象的操作会映射为对数据存储的操作,这也是ORM的实现机制。

class Model {

        public $id;

        public $name;

        public $email;

        ……

        function __construct($id) {

               //构造函数,调用class时自动执行,用来初始化。

               //查询逻辑

        }

        function __destruct() {

               //析构函数,当class调用完成后自动执行,用它来销毁实例,释放资源。

               //增删改逻辑

        }

}

7:观察者模式

使用:

Event::fire(new /event);

好处:

当一个对象状态发生改变时,依赖它的对象全部会收到通知并自动更新,实现低耦合,非侵入式的通知与更新机制。

(PS:有关abstract和interface:http://blog.csdn.net/sunlylorn/article/details/6124319)

实现:

EventGenerator.php                                            //事件产生者

abstract class EventGenerator{

         private $obserers = array();                        //观察者对事件发生者不可见

         function addObsever(Observer $observer) {

                 $this->obserers[] = $observer;

        }

        function ontify() {                                        //逐个调用观察者的handle方法

                 foreach ($this->obserers as $observer){

                         $observer->handle();

                 }

        }

}

event.php                                                           //事件类

class Event extends EventGenerator{

        function trigger(){

                $this->ontify();

        }

}

Observer.php                                                             //观察者接口

interface Observer {

        function update($event_info = null);                    //更新操作,可接受事件信息参数

}

Observer1.php                                                           //EventListener

class Observer1 implements Observer {

        function handle($event_info = null){

                echo "逻辑1";

        }

}

index.php                                                                   //Controller中function

$event = new \Event();

$event->addObsever(new \Observer1());

$event->trigger();

8:原型模式

与工厂模式类似,用于创建对象,不同在于:原型模式是先创建好一个原型对象,再通过clone原型对象来创建新的对象,原型模式适用于大对象的创建,仅需要内存拷贝即可。

$Object = new Object();

$object_1 = clone $Object;

$object_2 = clone $Object;

……

9:装饰器模式

若要修改或添加一个类的功能,传统的方式是写一个子类继承它,并重新实现类的方法。装饰器模式仅需在运行时添加一个装饰器对象即可动态的添加或修改类的功能。

传统方法:

class Method2 extends Method {

        function doSomething() {

                echo "<div style='color:red'>"

                parent::doSomething();

                echo "</div>";

        }

}

interfa Decorator {                                             //定义装饰器接口

        function beforeAction();

        function afterAction();

        //more decoratorMethod……

}

class SomeClass {

        protected $decorators = [];

        function addDecorator(Decorator $decorator) {

                $this->decorators[] = $decorator;

        }

        function beforeMethod() {

                foreach ($this->decorators as $row) {

                        $row->beforeAction();

                }

        }

        function afterMethod() {

                $decorators = array_reverse($this->decorators);     //做一个反转

                foreach ($this->decorators as $row) {

                        $row->afterAction();

                }

        }

        function action() {

                $this->beforeMethod();

                //method;

                $this->afterMethod();

        }

}

class OneDecorator implements Decorator {

        protected $datas;

        function __construct($datas = 'request') {

                 $this->datas = $datas;

        }

        function beforeAction() {

                  echo "<div style='color:{$this->datas};'>";

        }

        function afterAction() {

                  echo "</div>";

        }

}

$Object = new \SomeClass();

$Object->addDecorator(new \OneDecorator('blue'));

//Add other decorator...

$Object->action();

10:迭代器模式

在不需要了解内部实现的前提下,遍历一个聚合对象的内部元素,相对于传统编程方式它可以遍历元素所需的操作。

例如:Object::all()

Iterator extends Traversable {                       //PHP内置迭代器接口

/* 方法 */

        abstract public mixed current (void)

        abstract public scalar key (void)

        abstract public void next (void)

        abstract public void rewind (void)

        abstract public boolean valid (void)

}

class ObjectAll implements \Iterator {

        protected $ids;                      //所有对象的id

        protected $index;                  //迭代器的当前位置

        protected $data = array();     //保存从数据库取到的所有对象

        function __construct() {

        //取出所有的id,$ids

}

        function current() {

                //获取当前的元素的数据,第三个调用

                $id = $this->ids[$this->index]['id'];

                return Object::find($id);

        }

        function next() {

                //获取下一个元素,第四个调用

                $this->index ++;

         }

         function valid() {

                 //验证当前元素是否还有下一个元素(查询当前是否有数据),第二个调用

                 return $this->index < count($this->$ids);

         }

         function rewind() {

                 //当迭代器执行到末尾时,重置迭代器到整个集合的开头,最先调用

                 $this->index = 0;

         }

         function key() {

                  //获取当前的索引,最后调用

                  return $this->index;

         }

}

$objects = new \ObjectAll();

foreach ($objects as $row) {

        dump($row->field);

        //增删改查操作

}

11:代理模式

在客户端与实体之间建立一个代理对象,客户端对实体进行操作全部委派给代理对象,隐藏实体的具体实现细节(slave读库与master写库分离)。代理对象还可以与业务代码分离,部署到另外的服务器,业务代码中通过PRC来委派任务。

有关mysql的master-slave:http://www.cnblogs.com/jirglt/p/3549047.html

interface DBproxy {

        function getInfo($id);

        function setInfo($id, $value);

}

class Proxy implements DBproxy {

        function get() {

                //DB::('slave');

                query

        }

        function set() {

                //DB::('master');

                query

        }

}

$proxy = new Proxy();

$proxy->get($id);

$proxy->set($id, $value);

12:MVC结构(非设计模式,而是一种工程组织结构)

1:model——数据和存储的封装

2:view——展现层的封装

3:controller——逻辑层(业务代码,功能)的封装

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,456评论 5 477
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,370评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,337评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,583评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,596评论 5 365
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,572评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,936评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,595评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,850评论 1 297
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,601评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,685评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,371评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,951评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,934评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,167评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 43,636评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,411评论 2 342

推荐阅读更多精彩内容

  • Spring Cloud为开发人员提供了快速构建分布式系统中一些常见模式的工具(例如配置管理,服务发现,断路器,智...
    卡卡罗2017阅读 134,585评论 18 139
  • 1. Java基础部分 基础部分的顺序:基本语法,类相关的语法,内部类的语法,继承相关的语法,异常的语法,线程的语...
    子非鱼_t_阅读 31,560评论 18 399
  • 工厂模式类似于现实生活中的工厂可以产生大量相似的商品,去做同样的事情,实现同样的效果;这时候需要使用工厂模式。简单...
    舟渔行舟阅读 7,716评论 2 17
  • 转至元数据结尾创建: 董潇伟,最新修改于: 十二月 23, 2016 转至元数据起始第一章:isa和Class一....
    40c0490e5268阅读 1,678评论 0 9
  • 读石黑一雄的作品《NEVER LET ME GO》给我留下了很深刻的印象。喜欢作者对这个故事的冷静讲述。扣人心弦的...
    pennyli8765阅读 705评论 0 0