作者归档:admin

PHP设计模式笔记:使用PHP实现观察者模式

PHP设计模式笔记:使用PHP实现观察者模式

【意图】
定义对象间的一种一对多的依赖关系,当一个对象的状态发生改变时,所有依赖于它的对象都得到通知并被自动更新【GOF95】
又称为发布-订阅(Publish-Subscribe)模式、模型-视图(Model-View)模式、源-监听(Source-Listener)模式、或从属者(Dependents)模式

【观察者模式结构图】

观察者模式

观察者模式

【观察者模式中主要角色】
抽象主题(Subject)角色:主题角色将所有对观察者对象的引用保存在一个集合中,每个主题可以有任意多个观察者。抽象主题提供了增加和删除观察者对象的接口。
抽象观察者(Observer)角色:为所有的具体观察者定义一个接口,在观察的主题发生改变时更新自己。
具体主题(ConcreteSubject)角色:存储相关状态到具体观察者对象,当具体主题的内部状态改变时,给所有登记过的观察者发出通知。具体主题角色通常用一个具体子类实现。
具体观察者(ConcretedObserver)角色:存储一个具体主题对象,存储相关状态,实现抽象观察者角色所要求的更新接口,以使得其自身状态和主题的状态保持一致。

【观察者模式的优点和缺点】
观察者模式的优点:
1、观察者和主题之间的耦合度较小;
2、支持广播通信;

观察者模式的缺点:
1、由于观察者并不知道其它观察者的存在,它可能对改变目标的最终代价一无所知。这可能会引起意外的更新。

【观察者模式适用场景】
1、当一个抽象模型有两个方面,其中一个方面依赖于另一个方面。
2、当对一个对象的改变需要同时改变其它对象,而不知道具体有多少个对象待改变。
3、当一个对象必须通知其它对象,而它又不能假定其它对象是谁。换句话说,你不希望这些对象是紧密耦合的。

【观察者模式与其它模式】
中介者模式(Mediator):通过封装复杂的更新语义,ChangeManager充当目标和观察者之间的中介者。
单例模式(singleton模式):ChangeManager可使用Singleton模式来保证它是唯一的并且是可全局访问的。

【观察者模式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
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
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
<?php
 
/**
 * 观察者模式 2010-09-23 sz
 * @author phppan.p#gmail.com  http://www.phppan.com                                             
 * 哥学社成员(http://www.blog-brother.com/)
 * @package design pattern
 */
 
/**
 * 抽象主题角色
 */
interface Subject {
 
    /**
     * 增加一个新的观察者对象
     * @param Observer $observer
     */
    public function attach(Observer $observer);
 
    /**
     * 删除一个已注册过的观察者对象
     * @param Observer $observer
     */
    public function detach(Observer $observer);
 
    /**
     * 通知所有注册过的观察者对象
     */
    public function notifyObservers();
}
 
/**
 * 具体主题角色
 */
class ConcreteSubject implements Subject {
 
    private $_observers;
 
    public function __construct() {
        $this->_observers = array();
    }
 
    /**
     * 增加一个新的观察者对象
     * @param Observer $observer
     */
    public function attach(Observer $observer) {
        return array_push($this->_observers, $observer);
    }
 
    /**
     * 删除一个已注册过的观察者对象
     * @param Observer $observer
     */
    public function detach(Observer $observer) {
        $index = array_search($observer, $this->_observers);
        if ($index === FALSE || ! array_key_exists($index, $this->_observers)) {
            return FALSE;
        }
 
        unset($this->_observers[$index]);
        return TRUE;
    }
 
    /**
     * 通知所有注册过的观察者对象
     */
    public function notifyObservers() {
        if (!is_array($this->_observers)) {
            return FALSE;
        }
 
        foreach ($this->_observers as $observer) {
            $observer->update();
        }
 
        return TRUE;
    }
 
}
 
/**
 * 抽象观察者角色
 */
interface Observer {
 
    /**
     * 更新方法
     */
    public function update();
}
 
class ConcreteObserver implements Observer {
 
    /**
     * 观察者的名称
     * @var <type>
     */
    private $_name;
 
    public function __construct($name) {
        $this->_name = $name;
    }
 
    /**
     * 更新方法
     */
    public function update() {
        echo 'Observer', $this->_name, ' has notified.<br />';
    }
 
}
 
/**
 * 客户端
 */
class Client {
 
    /**
     * Main program.
     */
    public static function main() {
        $subject = new ConcreteSubject();
 
        /* 添加第一个观察者 */
        $observer1 = new ConcreteObserver('Martin');
        $subject->attach($observer1);
 
        echo '<br /> The First notify:<br />';
        $subject->notifyObservers();
 
        /* 添加第二个观察者 */
        $observer2 = new ConcreteObserver('phppan');
        $subject->attach($observer2);
 
        echo '<br /> The Second notify:<br />';
        $subject->notifyObservers();
 
        /* 删除第一个观察者 */
        $subject->detach($observer1);
 
        echo '<br /> The Third notify:<br />';
        $subject->notifyObservers();
    }
 
}
 
Client::main();
?>

数据源架构模式之表数据入口

数据源架构模式之表数据入口

【表数据入口的意图】
充当到数据库表的入口的对象。一个实例处理表中的所有行。
表数据入口包含了用于访问单个表或视图的所有SQL,如CRUD等。其它的代码调用它的方法来实现所有与数据库的交互。

【表数据入口的适用场景】
1、表数据入口可以同表模块一起使用。
2、适用于事务脚本处理

【表数据入口的运行机制】
表数据入口的实现非常简单,一般会包括几个从数据库中获取数据的查找方法以及更新,插入和删除方法。
每个方法都将输入参数映射为一个SQL调用并在数据库连接上执行该语句。

【表数据入口的优点和缺点】
1、简单。表数据入口可能是使用起来最简单的数据库接口模式。
2、为数据源的精确访问逻辑提供了一种自然的方法。
3、相同的接口即可以用于SQL操作操作数据库,又可以用于存储过程。

【表数据入口的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
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
100
101
102
103
104
105
106
107
<?php
/**
 * 企业应用架构 数据源架构模式之表数据入口 2010-09-18 sz
 * @author phppan.p#gmail.com  http://www.phppan.com
 * 哥学社成员(http://www.blog-brother.com/)
 * @package architecture
 */
 
class PersonGateway {
 
    /**
     * 查询所有人员数据
     * @return <type>
     */
    public function findAll() {
        $sql = "SELECT * FROM person";
        return DB::query($sql);
    }
 
    /**
     * 根据名字查找人员数据
     * @param <type> $name
     * @return <type>
     */
    public function findByName($name) {
        $sql = "SELECT * FROM person WHERE `name` = '" . $name . "'";
        return DB::query($sql);
    }
 
    /**
     * 更新人员数据
     * @param <type> $key   关键字
     * @param <type> $data  需要更新的数据, 例如:$data = array('id' => 1, 'name' => 'Martin', 'birthday' => '');
     */
    public function update($id, $data) {
        if (empty($id) || !is_array($data)) {
            return FALSE;
        }
 
        $sql = "UPDATE person SET ";
        foreach ($data as $field => $value) {
            $sql .= "`" . $field . "` = '" . $value . "',";
        }
        $sql = substr($sql, 0, -1);
 
        $sql .= " WHERE id = " . $id;
 
        return DB::query($sql);
    }
 
    /**
     * 插入人员的数据
     * @param <type> $data 需要写入的数据, 例如:$data = array('name' => 'Martin', 'birthday' => '');
     */
    public function insert($data) {
        if (!is_array($data)) {
            return FALSE;
        }
 
        $sql = "INSERT INTO person ";
        $sql .= "(`" . implode("`,`", array_keys($data)) . "`)";
        $sql .= " VALUES('" . implode("','", array_values($data)) . "')";
 
        return DB::query($sql);
    }
 
}
 
class DB {
 
    /**
     * 这只是一个执行SQL的演示方法
     * @param string $sql   需要执行的SQL
     */
    public static function query($sql) {
        echo "执行SQL: ", $sql, " <br />";
    }
}
 
/**
 * 客户端调用
 */
class Client {
 
     /**
     * Main program.
     */
    public static function main() {
        $person = new PersonGateway();
 
        header("Content-type:text/html; charset=utf-8");
        $data = array('name' => 'Martin', 'birthday' => '2010-09-15');
        $person->insert($data);
 
        $id = 1;
        $data['id'] = $id;
        $person->update($id, $data);
 
        $person->findAll();
 
        $person->findByName('Martin');
    }
}
 
Client::main();
 
?>

如上所示代码仅为一个演示版本
然而这个演示版本有一些可以优化的地方,如:将更新和插入的SQL拼装过程可以提取出来等。

数据表接口是一个很简单的数据源模式,这在我们平常的工作中也有用到,有可能看起来与上面的例子相差较大,但是可能只是将某些方法进行了优化而已,究其本质是一样的。

一道经典的智商测试题 十只兔子

一道经典的智商测试题(十只兔子)
题目是一个童谣:
大兔子病了,
二兔子瞧,
三兔子买药,
四兔子熬,
五兔子死了,
六兔子抬,
七兔子挖坑,
八兔子埋,
九兔子坐在地上哭起来,
十兔子问它为什么哭?
九兔子说:
五兔子一去不回来!

五兔子是被杀的,这是一个有预谋的凶杀案,大家能推出哪只兔子是这个案件的主谋吗?

答案:?
我在百度百科答案基础上的另一种猜想:

这是一个有预谋的弑兄夺嫂情杀案。

http://zhidao.baidu.com/question/182305887.html?pn=0

1.首先,兔子也是有阶级的,大兔子病了,要治它的病,就必须不惜一切代价,甚至牺牲一只兔子做药引。
2.病的是大兔子,五兔子却突然死了,显然是被做成了药引。
3.”买药”其实是黑话,因为实际上只需要一些简单的草药,主要是药引,所以这个”买药”指的是去杀掉做药引的兔子,三兔子是一个杀手。
4.做药引的为什么是五兔?因为哪只兔子适合做药引是由医生决定的,二兔子就是医生。
5.可以推出,二兔子借刀杀兔搞死了五兔子,他们之间有什么过解呢?可能是情杀,因为一只母兔。
6.谁是母兔呢?想一下,女人爱哭的天性,所以九兔是母兔,九兔也知道了真相,所以才哭,因为她爱的是五兔。
7.”六兔子抬”,这明显是病句,一只兔子怎么抬?他显然是被抬,因为他死了,所以才会被抬。抬他的两只兔子随后一个挖坑,一个埋尸。没错,抬他来的就是七八两只兔子!
8.六兔子是被七八两只兔子杀的吗?不是,他是被杀手三兔子杀死的。三兔子本来不想杀他,五兔子和六兔子关系非常好,当时他们正好在一起,并联手抵抗,所以三兔子才把他们一起杀了。
大家会发现,每相临的两只兔子关系都是微妙的。1-2 大兔子像皇上,二兔子就是他身边进谗言的小人。3-4 三兔子是杀手,四兔子药师,他俩都是助纣为虐型的,四兔经常给皇帝做一些壮阳药什么的,把皇上搞生病了,又亲自熬兔子药引。5-6 一对好朋友,经常在一起吟诗作对,不惧怕恶势力,五兔很有才华,怪不得被九兔所爱又被二兔嫉妒呢,物以类聚,六兔也很有才,可惜都属于文人,两个人的武工加一起也没打过三兔。 7-8也是一对好朋友,但属于随风倒型的,为了保住命,什么事都肯做,本质不算坏,但经常被坏人指始做坏事。9-10在女人哭的时候,身边一定会有爱她的男人,而她的哭泣一定是为了她爱的男人。可惜,爱她的兔子和她爱的兔子不是一只兔子。很明显了吧,十兔暗恋九兔,关心她,看到她哭,他当然要去问原因。
9.最后一点分析了,也许是多余。事情是这样的,三兔和五六两兔打斗过程中,引来了七八两兔。当五六被杀死后,三兔已没有力气,况且七八平时都很听话,不会告密的。所以三兔就放过了七八两兔,并让他们把六兔抬走,埋了。七八一看,命保住了,反正事情也发生了,无法挽回,只好照办理。
后记1:回看第5条,情杀不是随便猜出来的,观全局,二兔位高权重,但即便这样,也有他得不到的东西,那就是真爱。所以他杀五兔的原因很可能是这个,而且五兔正直,应该平时就经常与他作对,所以才起了杀心。
后记2:其实五兔死得非常惨,因为二兔疯狂妒忌他,所以不想让他成为一个正常的男人。再说皇上吃了药师的药,荒淫无度,哪里最虚弱大家应该都知道吧,所谓吃什么补什么,其实五兔被做成药引的部位应该是……
推理的补充
(1)作为一个完整的故事,必然要有因果关系,这个故事有了果(即情杀,下面再谈),但没有因,所以显得不完整,就是大兔子为什么病了?无缘无故的病了便引发了以下的血案么?显然不是。
(2)从一个严密的逻辑上来看,这个故事中所有人物的出现(兔子)都是有联系的,且每一个按序列排下来的兔子之间都存在因果关系(动机),比如:大兔和二兔,二兔和三兔.三兔和四兔(这个上文已经大致说明了,我就不进一步讲了),但大家有没有觉得,10兔子的出现好象在这个逻辑中显得微不足道,即没有 10兔子这个故事也能顺理成章的结束,因此10兔子在这个逻辑中的动机显得苍白。
结论:
根据以上的推断,我们都忽视了这个故事的重点,就是10兔子,他为什么出现在这个故事中?难道仅仅为了引出9兔子的一句话么?错了,这是一个有预谋的凶杀案,而且,10兔子就是这个案件的主谋(不是2兔子),其他所有的兔子都是在他全盘计划中的一枚棋子,案发过程大致如下(补充上文):
(1)10兔子喜欢9兔子,9兔子不喜欢他
(2)5兔子和9兔子互相喜欢
(3)10兔子妒忌
(4)10兔子是大兔子身边最亲信的人,并且对其他兔子之间的关系了如指掌(也就是说,他很清楚大兔子如果病了接下来会发生些什么事)
(5)5兔子也是朝中权贵,10兔子没办法随便处置他。
(6)所以10兔子就让大兔子病了,接下来的一切就像上文说的那样发生了……
到这里是百度百科上的答案,可是还没分析完:

9兔子说的最后一句话:一去不回来,为什么是一去呢?因为他们是住在一起的,所以9兔子和5兔子是夫妻,而10兔子为什么会出现呢?因为5兔子是10兔子的哥哥,他们兄弟俩住一起,根据古代女子的再婚:哥哥死后嫂子嫁给小叔子,可见当5兔子死后,10兔子就可以娶9兔子了。

所以,贯穿整个这个故事的主线就是10兔子,他是这个故事的结尾也是这个故事的主因,这样这个逻辑才显得天衣无缝,故事的名字就是:弑兄夺嫂,借刀杀人!

以上纯属虚构,如有雷同,与我无关