Zihao

Make small but daily progress

0%

Laravel之设计模式

Laravel 是一个非常优雅的Web框架,使用了多种设计模式。php本身是非常自由的脚本语言,但是随着互联网企业的发展,业务越来越复杂,也需要更多的人进行团队协作。作为优秀的开发者,不仅要完成基础的业务开发,为了更好的合作需要遵循面向对象的一系列设计模式。

Laravel的面向对象编程原则

  • 1:使用namespace防止命名冲突

  • 2:使用autoload来自动加载函数
    使用ArrayAccess实现配置文件的加载,使一个对象可以通过数组的方式访问。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    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 = 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:单例模式

好处:

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

实现方式:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
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数组便是一个注册树

好处:

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

实现方法:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
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表示别名,自己设定

在工厂模式中添加

1
Register::set(‘db1’,$db);

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

1
Register::$objects[‘db1’];

4:适配器模式

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

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

1
2
3
4
5
6
7
8
9
interface Database {

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

function query($sql);

function close();

}

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

5:策略模式

好处:

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

实现:

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

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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
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的实现机制。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
class Model {

public $id;

public $name;

public $email;

……

function __construct($id) {

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

//查询逻辑

}

function __destruct() {

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

//增删改逻辑

}

}

7:观察者模式

使用:

1
Event::fire(new /event);

好处:

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

(PS:有关abstractinterfacehttp://blog.csdn.net/sunlylorn/article/details/6124319)

实现:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
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 //事件类

1
2
3
4
5
6
7
8
9
class Event extends EventGenerator{

function trigger(){

$this->ontify();

}

}

Observer.php // 观察者接口

1
2
3
4
5
interface Observer {

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

}

Observer1.php // EventListener

1
2
3
4
5
6
7
8
9
class Observer1 implements Observer {

function handle($event_info = null){

echo “逻辑1”;

}

}

index.php //Controller中function

1
2
3
4
5
$event = new \Event();

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

$event->trigger();

8:原型模式

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

1
2
3
4
5
6
7
$Object = new Object();

$object_1 = clone $Object;

$object_2 = clone $Object;

……

9:装饰器模式

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

传统方法:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
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()

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
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:代理模式

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

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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
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——逻辑层(业务代码,功能)的封装

欢迎关注我的其它发布渠道