广播订阅模式介绍
打开收音机选择不同频率的节目时,就像是订阅某个电台的节目。广播节目的电台(广播者)并不需要知道谁在收听他们的电台节目,他们只需广播就行。同样对收听节目的人(订阅者)来说,也不关心谁广播的这些节目,只需要打开收音机并调频到这个频率,当有节目时就可以收到。
广播订阅模式优点
- 解耦
- 扩展
- 清晰
- 灵活
- 测试
广播订阅模式缺点
- 不保证消息是否投递成功
- 不保证消息是否处理成功
- 安全问题
- 消息膨胀
广播订阅模式总结
可以来构建一个松耦合的系统,需要在系统安全性及扩展性上做更多复杂的设计及实践。
广播订阅模式javascript样例
var makePubSub = function () {
var callbacks = {},
publish = function (){
//Turn arguments object into real array
var args = Array.prototype.slice.call(arguments, 0);
//Extract the event name which is the first entry
var ev = args.shift();
//Return if callbacks object doesn't contain
//any entry for event
var list, i, l;
if(!callbacks[ev]) { return this; }
list = callbacks[ev];
//Invoke the callbacks, passing in the rest of parameters
for (i=0, l=list.length; i<l; i=i+1){
list[i].apply(this, args);
}
return this;
},
subscribe = function (ev, callback){
//Check if ev is already registered
// If it isn't create an array entry for it
if(!callbacks[ev]){
callbacks[ev] = [];
}
callbacks[ev].push(callback);
return this;
};
return {pub: publish, sub: subscribe};
};
test = makePubSub()
test.sub('alert', function(){alert('hello');})
test.pub('alert')
广播订阅模式php样例
<?php
date_default_timezone_set("Asia/Shanghai");
/**
* 日志函数
* @param $message 日志内容
* @param string $tag 日志标题
* @return string
*/
function log_message($message = array(), $tag = 'debug')
{
if (empty($message)) $message = "No Message";
$message = (array) $message;
$message = (count($message) == 1 && !is_array($message[0])) ? $message[0] : json_encode($message, JSON_UNESCAPED_UNICODE);
echo sprintf("%s - %s -> %s\n", strtoupper($tag), date("Y-m-d H:i:s"), $message);
}
interface PubSubInterface
{
public function receive($topic, $message);
}
class PubSub {
private $_subcribes = [];
public function subscribe($topic = 'normal', $subscriber)
{
if (!isset($this->_subcribes[$topic]))
{
$this->_subcribes[$topic][] = [];
}
if (is_object($subscriber)) $this->_subcribes[$topic][] = $subscriber;
}
public function publish($topic = 'normal')
{
if (!empty($this->_subcribes) && isset($this->_subcribes[$topic]))
{
foreach ($this->_subcribes[$topic] as $object)
{
if (is_object($object))
{
call_user_func_array([$object, 'receive'], [$topic, $this->_getTopicData($topic)]);
}
}
}
}
public function _getTopicData($topic)
{
$config = ['email' => '今天加班 :(', 'salary' => '今天发薪水 :)'];
return isset($config[$topic]) ? $config[$topic] : 'No Message';
}
public function getTopics() {
return array_keys($this->_subcribes);
}
}
class Work implements PubSubInterface
{
public function receive($topic, $message)
{
log_message(' 新消息 '.$message, $topic);
}
}
class Family implements PubSubInterface
{
public function receive($topic, $message)
{
log_message(' 新消息 '.$message, $topic);
}
}
/* usage */
$work = new Work();
$family = new Family();
$ps = new PubSub();
$ps->subscribe('email', $work);
$ps->subscribe('salary', $work);
$ps->subscribe('email', $family);
$ps->publish('email');
$ps->publish('salary');