设计模式:观察者模式介绍与应用场景

简短描述

在观察者模式中,有一个主题和几个观察者,主题状态改变之后会通知到所有的观察者。

现实中的观察者模式

观察者模式和现实世界很好对应。比如我和我的朋友们购买了今年一年的报纸,每次报社印刷了今天的报纸之后就会往我这里送。在这个系统里面,“报社“是一个主题,“我和我的朋友们”就是一个观察者,当“报社”生产报纸之后,“我和我的朋友们”都能收到这份报纸。

根据上面的描述,我们很容易写出一个观察者模式。首先定义一个报社作为主题,然后定义一些用户作为观察者。不过在此之前,我们先定义主题和观察者的接口,毕竟我们是面向接口编程。

定义一个主题接口

namespace ds\observer\contract;

/**
 * 主题接口
 */

interface Subject
{
    /**
     * 添加一个观察者
     * @param Observer $observer
     */
    public function add(Observer $observer);
    
    /**
     * 移除一个观察者
     * @param  Observer $observer
     * @return boolean
     */
    public function remove(Observer $observer);
    
    /**
     * 通知所有观察者
     * @param  mixed $data
     * @return boolean
     */
    public function notify($data);
}

定义一个观察者接口

namespace ds\observer\contract;

/**
 * 观察者
 */
interface Observer
{
    /**
     * 执行自己的逻辑
     * @param  mixed $data
     * @return boolean
     */
    public function execute($data);
}

定义报社,实现主题接口

namespace ds\observer;

/**
 * 报社主题
 */
class Newspaper implements contract\Subject
{
    protected $Observers;

    /**
     * 添加一个观察者
     * @param Observer $observer
     */
    public function add(contract\Observer $observer)
    {
        $hash = $this->hash($observer);
        $this->Observers[$hash] = $observer;
    }
    
    /**
     * 移除一个观察者
     * @param  Observer $observer
     */
    public function remove(contract\Observer $observer)
    {
        $hash = $this->hash($observer);
        unset($this->Observers[$hash]);
    }
    
    /**
     * 通知所有观察者
     * @param  mixed $data
     * @return boolean
     */
    public function notify($data)
    {
        foreach ($this->Observers as $observer) {
            $observer->execute($data);
        }
    }

    protected function hash($obj)
    {
        return spl_object_hash($obj);
    }
}

定义用户,实现观察者接口

namespace ds\observer;

/**
 * 用户
 */
class User implements contract\Observer
{
    public function __construct($name)
    {
        $this->name = $name;
    }

    /**
     * 执行观察者自身逻辑
     * @param  string $data
     * @return void
     */
    public function execute($data)
    {
        echo $this->name . "收到了" . $data . "\n";
    }

    public function attach(contract\Subject $subject)
    {
        $subject->add($this);
    }
}

执行主流程

到目前位置,我们创建了主题-报社、观察者-用户,他们分别实现了相应的接口,看起来一切准备就绪了。接着这些代码就可以跑起来了。

namespace ds\observer;

require __DIR__ . '/contract/Observer.php';
require __DIR__ . '/contract/Subject.php';
require __DIR__ . '/Newspaper.php';
require __DIR__ . '/User.php';

// 创建一个新的报社
$newspaper = new Newspaper();

// 创建一个新的用户cmhc
$cmhc = new User('cmhc');
// 让这个用户去订阅这个报纸
$cmhc->attach($newspaper);

// 再创建一个用户xiaoming
$xiaoming = new User('xiaoming');
// 让xiaoming也订阅这个报社
$xiaoming->attach($newspaper);

// 报社今天发布了一个观察者模式,通知一下订阅我的人
$newspaper->notify('《设计模式之观察者模式》');

如果执行上面的代码,你会得到如下结果:

cmhc收到了《设计模式之观察者模式》
xiaoming收到了《设计模式之观察者模式》

可能很多人都知道观察者模式,也知道观察者模式要怎么去实现,但是却找不到具体的业务场景去使用它。但实际上观察者模式的应用是十分广泛的。下面就介绍几个经常使用观察者模式的几个场景

支付场景

在支付场景下,用户购买一件商品,当支付成功之后三方会回调自身,在这个时候系统可能会有很多需要执行的逻辑(如:更新订单状态,发送邮件通知,赠送礼品…),这些逻辑之间并没有强耦合,因此天然适合使用观察者模式去实现这些功能,当有更多的操作时,只需要添加新的观察者就能实现,完美实现了对修改关闭,对扩展开放的开闭原则。

UGC场景

在一个UGC场景下,用户发布的内容往往会经过很多流程,大部分是先发往审核系统,当审核通过之后就会出现一系列的业务逻辑,比如更新内容状态,通知给所有的粉丝等等。

休眠后mac点击wifi图标卡死的解决方法

最近遇到一些问题,休眠后的mac点击wifi图标导致整个顶部的导航栏全部卡死,十分崩溃。

最开始分析是导航栏的问题,想着重启一下导航栏。

killall SystemUIServer

然而并不管用,导航栏是不卡死了,但是点击wifi图标依旧会卡死。那就重启一下网络吧。

ps -ef | grep airportd

然后sudo kill 掉就可以了。不过mac还有一个比较简单的killall命令

sudo killall airportd

使用expect之后无法使用rz和sz的解决方法

在机器太多的时候,我们会使用expect来自动化登录,然而使用expect之后就不能使用rz和sz了。

经过一番寻找之后,发现有一个解决方案,在脚本之前增加一个

export LC_CTYPE=en_US

注意,这个语句放到登录脚本里面就可以了,不要放到.bash_profile里面,如果放到bash_profile里面可能你当前的终端语言都变了,中文可能会乱码。

这个缺点是远程机器里面的中文可能会乱码了,如果有更好的解决方案,我会在这里更新。

SQLAlchemy介绍

SQLAlchemy是python下十分流行的orm(对象关系映射)框架。官方的介绍是这样的:

SQLAlchemy将数据库视为关系代数引擎,而不仅仅是表的集合。行不仅可以从表中选择,还可以选择连接其他的选择语句; 这些单元中的任一个可以组成更大的结构。SQLAlchemy的核心表达语言正是基于这个概念。

SQLAlchemy以其对象关系映射器(ORM)而闻名,它提供一个数据映射器模式的可选组件,其中可以通过多种方式将类映射到数据库,实际上对象模型和数据库模式从一开始就可以完整分离。

SQLAlchemy的对这些问题的总体思路来源于其它优秀的 SQL/ORM 工具,植根于所谓的完全不同complimentarity-导向的方法; 而不是隐藏SQL并将对象的关系细节隐藏在自动化的墙壁之后,所有进程都被完全暴露在一系列可组合的透明工具中。该库负责自动执行冗余任务,而开发人员仍然可以控制数据库的组织方式以及SQL的构建方式。

SQLAlchemy的主要目标是改变您对数据库和SQL的思考方式!

Sublime 自定义快捷键

sublime插件丰富,当我们安装了诸多插件之后,发现要使用其中的功能还得用鼠标去点,这岂不是太麻烦了,让我们来自定义快捷键吧!

写在前面

在写这篇文章之前,我也为自定义快捷键感到无从下手,而在网上搜索千篇一律的都是打开Preferences->key bindings user,添加一些东西进去,比如等等,这个command是什么玩意?

比如下面

{ "keys": ["ctrl+alt+down"], "command":"duplicate_line" },

等等,这个command是什么?我要去哪儿找?我安装了一个新的插件,能使用快捷键吗?等等一系列的疑问,从未有人解答过,可能一些文章都是抄袭拼凑吧。

如何查找Commands

比如我安装了一个php code sniffer,想要使用一个快捷键来对代码进行检测,然而这个command是什么?看来只能去查看官方文档。 (更多…)

中文分词词性对照表

汉语词性对照表[北大标准/中科院标准]

词性编码
词性名称
注 解

Ag

形语素 形容词性语素。形容词代码为 a,语素代码g前面置以A。

a

形容词 取英语形容词 adjective的第1个字母

ad

副形词 直接作状语的形容词。形容词代码 a和副词代码d并在一起。

an

名形词 具有名词功能的形容词。形容词代码 a和名词代码n并在一起。

b

区别词 取汉字“别”的声母。

c

连词 取英语连词 conjunction的第1个字母。
dg
副语素 副词性语素。副词代码为 d,语素代码g前面置以D。

d

副词 取 adverb的第2个字母,因其第1个字母已用于形容词。

e

叹词 取英语叹词 exclamation的第1个字母。

f

方位词 取汉字“方”

g

语素 绝大多数语素都能作为合成词的“词根”,取汉字“根”的声母。

h

前接成分 取英语 head的第1个字母。

i

成语 取英语成语 idiom的第1个字母。

j

简称略语 取汉字“简”的声母。

k

后接成分

l

习用语 习用语尚未成为成语,有点“临时性”,取“临”的声母。

m

数词 取英语 numeral的第3个字母,n,u已有他用。

Ng

名语素 名词性语素。名词代码为 n,语素代码g前面置以N。

n

名词 取英语名词 noun的第1个字母。

nr

人名 名词代码 n和“人(ren)”的声母并在一起。

ns

地名 名词代码 n和处所词代码s并在一起。

nt

机构团体 “团”的声母为 t,名词代码n和t并在一起。

nz

其他专名 “专”的声母的第 1个字母为z,名词代码n和z并在一起。

o

拟声词 取英语拟声词 onomatopoeia的第1个字母。

p

介词 取英语介词 prepositional的第1个字母。

q

量词 取英语 quantity的第1个字母。

r

代词 取英语代词 pronoun的第2个字母,因p已用于介词。

s

处所词 取英语 space的第1个字母。

tg

时语素 时间词性语素。时间词代码为 t,在语素的代码g前面置以T。

t

时间词 取英语 time的第1个字母。

u

助词 取英语助词 auxiliary

vg

动语素 动词性语素。动词代码为 v。在语素的代码g前面置以V。

v

动词 取英语动词 verb的第一个字母。

vd

副动词 直接作状语的动词。动词和副词的代码并在一起。

vn

名动词 指具有名词功能的动词。动词和名词的代码并在一起。

w

标点符号

x

非语素字 非语素字只是一个符号,字母 x通常用于代表未知数、符号。

y

语气词 取汉字“语”的声母。

z

状态词 取汉字“状”的声母的前一个字母

un

未知词 不可识别词及用户自定义词组。取英文Unkonwn首两个字母。(非北大标准,CSW分词中定义)

安装datastax php-driver for cassandra 的悲惨经历

由于业务可能要使用cassandra,需要安装一个php的扩展,安装过程可谓是曲折

首先直接pecl安装

pecl install cassandra

然而告诉我

checking for supported DataStax C/C++ driver version... gawk: cmd. line:1: fatal: cannot open file `/include/cassandra.h' for reading (No such file or directory)

呵呵呵呵呵呵呵,还得首先安装cpp的driver。

行吧,先安装cpp-driver,按照官网给出的步骤

git clone https://github.com/datastax/cpp-driver.git
mkdir cpp-driver/build
cd cpp-driver/build
cmake ..
make

结果就是缺少libuv啊,缺少cmake啊,其中的过程就比较曲折了,等我都把依赖工具安装完成之后,开心的编译,然而…

/home/huchao/Downloads/cpp-driver/src/timestamp_generator.cpp: In function ‘CassTimestampGen* cass_timestamp_gen_monotonic_new_with_settings(int64_t, int64_t)’:
/home/huchao/Downloads/cpp-driver/src/timestamp_generator.cpp:38: error: declaration of C function ‘CassTimestampGen* cass_timestamp_gen_monotonic_new_with_settings(int64_t, int64_t)’ conflicts with
/home/huchao/Downloads/cpp-driver/include/cassandra.h:9529: error: previous declaration ‘CassTimestampGen* cass_timestamp_gen_monotonic_new_with_settings(cass_int64_t, cass_int64_t)’ here
make[2]: *** [CMakeFiles/cpp-driver.dir/src/timestamp_generator.cpp.o] Error 1
make[1]: *** [CMakeFiles/cpp-driver.dir/all] Error 2

还能说啥

。。。

之后再检查一下环境

官网centos5/6/7都是可以的,本地centos6.5

官网gcc4.1.2+,本地4.4.7,这应该也没问题吧,想着还是和官网一样的环境吧,编译一个gcc4.1.2。

然后另一个痛苦的过程来了,结果又是出错。这个,真没办法了,就上网找找看有没有和我一样的问题,结果真找到了

原文地址:http://blog.csdn.net/firefoxbug/article/details/7519565

原文摘抄如下

源码下载:ftp://ftp.gnu.org/gnu/gcc/gcc-4.1.2/

解包:tar -xvf gcc-4.1.2.tar.bz2

进入目录:cd gcc-4.1.2

 

# ./configure –prefix=/usr/local/gcc-4.1.2&& make
 

接着就出现错误

WARNING: `makeinfo' is missing on your system. You should only need it if
you modified a `.texi' or `.texinfo' file, or any other file
indirectly affecting the aspect of the manual. The spurious
call might also be the consequence of using a buggy `make' (AIX,
DU, IRIX). You might want to install the `Texinfo' package or
the `GNU make' package. Grab either from any GNU archive site.
make[3]: *** [fastjar.info] 错误 1
make[3]:正在离开目录 `/home/ssm/gcc-obj/fastjar'
make[2]: *** [all] 错误 2
make[2]:正在离开目录 `/home/ssm/gcc-obj/fastjar'
make[1]: *** [all-fastjar] 错误 2
make[1]:正在离开目录 `/home/ssm/gcc-obj'
make: *** [all] 错误 2
这里有一个文章 http://blog.csdn.NET/galois_godel/article/details/6750331

下面是摘要:

(主要原因是GCC的版本过高)

1:全英文的这部分说的是你的系统中缺少相应版本的makeinfo软件。

因为gcc4.1以上的版本需要makeinfo的版本为4.2或更高。
所以输入命令行:
makeinfo –version           想查看makeinfo的版本。结果得到了以下信息:
The program ‘makeinfo’ is currently not installed. You can install it by typing:
yum install texinfo
按照提示输入命令,问题得到解决。

2:本机使用的Texinfo是4.11版本,

出现此错误的原因也在于configure文件中texinfo对该版本不支持,可以在解压gcc4.1.1文件夹中的configure文件里找到

以下语句

# For an installed makeinfo, we require it to be from texinfo 4.2 or
# higher, else we use the “missing” dummy.
if ${MAKEINFO} –version \
| egrep ‘texinfo[^0-9]*([1-3][0-9]|4\.[2-9]|[5-9])’ >/dev/null 2>&1; then
:
else
MAKEINFO=”$MISSING makeinfo”
fi
;;

其中4\.[2-9]|[5-9]表示的是支持4.2-4.9之间的几个版本,所以需要自己添加4\.[1-9][0-9]*,以支持4.11版本。即把’texinfo[^0-9]*([1-3][0-9]|4\.[2-9]|[5-9])’编辑成’texinfo[^0-9]*([1-3][0-9]|4\.[2-9]|4\.[1-9][0-9]*|[5-9])’后保存,编译通过。

安装:make install
这时候先查看gcc版本

#gcc -v

发现还是4.6版本的,于是就卸载4.6版本

#rpm -e gcc-c++
#rpm -e gcc 

然后建立链接

# ln -s /usr/local/gcc-4.1.2/bin/gcc /usr/bin/gcc2
# ln -s /usr/local/gcc-4.1.2/bin/g++ /usr/bin/g++2

 

我是一个线程

来自:码农翻身(微信号:coderising)

作者:IBM刘欣

我是一个线程,我一出生就被编了个号: 0x3704,然后被领到一个昏暗的屋子里, 这里我发现了很多和我一模一样的同伴。

我身边的同伴0x6900待的时间比较长, 他带着沧桑的口气对我说:

“我们线程的宿命就是处理包裹。把包裹处理完以后还得马上回到这里,否则可能永远回不来了。”

我一脸懵懂,包裹,什么包裹?

“不要着急,马上你就会明白了, 我们这里是不养闲人的。”

果然,没多久,屋子的门开了, 一个面貌凶恶的家伙吼道:

“0x3704 ,出来!”

我一出来就被塞了一个沉甸甸的包裹,上面还有附带着一个写满了操作步骤的纸。

“快去,把这个包裹处理了。”

“去哪儿处理?”

“跟着指示走, 先到就绪车间”

果然,地上有指示箭头,跟着它来到了一间明亮的大屋子,这里已经有不少线程了, 大家都很紧张,好像时刻准备着往前冲。 (更多…)

chkconfig给linux添加开机自启动服务,chkconfig命令详解

chkconfig命令主要用来更新(启动或停止)和查询系统服务的运行级信息。谨记chkconfig不是立即自动禁止或激活一个服务,它只是简单的改变了符号连接。

使用语法

chkconfig [--add][--del][--list][系统服务] 或 chkconfig [--level <等级代号>][系统服务][on/off/reset]

chkconfig 在没有参数运行时,会显示所有的服务在开机启动状态。如果加上服务名,那么就检查这个服务是否在当前运行级启动。如果是,返回true,否则返回false。如果在服务名后面指 定了on,off或者reset,那么chkconfig 会改变指定服务的启动信息。on和off分别指服务被启动和停止,reset指重置服务的启动信息,无论有问题的初始化脚本指定了什么。on和off开 关,系统默认只对运行级3,4,5有效,但是reset可以对所有运行级有效。

参数用法

--add  增加所指定的系统服务,让chkconfig指令得以管理它,并同时在系统启动的叙述文件内增加相关数据。
--del  删除所指定的系统服务,不再由chkconfig指令管理,并同时在系统启动的叙述文件内删除相关数据。
--level<等级代号>  指定读系统服务要在哪一个执行等级中开启或关毕。
等级0表示:表示关机
等级1表示:单用户模式
等级2表示:无网络连接的多用户命令行模式
等级3表示:有网络连接的多用户命令行模式
等级4表示:不可用
等级5表示:带图形界面的多用户模式
等级6表示:重新启动

(更多…)