OBSERVER(观察者)
适用性:
1.当一个抽象模型有两个方面,其中一个方面依赖于另一个方面。将这二者封装在独立的对象中以是他们可以各自独立地改变和复用。
2.当对一个对象的改变需要同时改变其他对象,而不知道具体有多少对象有待改变。
3.当一个对象必须通知其他对象,而他有不能假定其他对象是谁。
思考:
考虑MVC架构的一个GUI场景,当一个模型对象改变,需要在多个View中及时的更新,而模型并不关心那个View需要获取自己的数据。通过向模型对象注册一个或者多个观察者,每当模型发生变化的时候,就通知注册的那些观察者:模型更新了。这是观察员模式的典型应用。有时候,我们可能并不希望直接在模型中实现注册和发布变更的能力,而是将这部分功能分离出去,这时,可以建立一个单一职责的发布者类,发布者负责接收订阅和发布更新,而模型一旦发生变化,只需要通知发布者即可。也可以有Control层来协调模型的变化和通知发布者的事宜。
对于适用性的第一点,不理解应该是个什么样的组织形式。从我的猜测来看,这一点可能比较适合smalltalk而不是C++。
从字面上理解, 第三点和第二点的区别只是在于被观察对象和观察员之间逻辑关系的区别。第二种情况似乎是被观察对象和观察员之间共同构成一个更大的高内聚的逻辑模块。而第三种情况强调的仅仅是对象间需要发生消息传递。
STATE(状态)
适用性:
1.一个对象的行为取决于它的状态,并且它必须在运行时刻根据状态改变行为。
2.一个操作中含有庞大的多分支的条件语句,且这些分支依赖于该对象的状态。State模式将每一个条件分支放入一个独立的类中。
思考:
对于第一种情形,书中举了个TCP连接的例子,把连接过程和读取数据过程当作两个不同的状态。由State成员控制状态的转换,并且切换实际的工作单元。当然,这是一个巧妙的实现方式。不过,就TCP连接这件事情本身来说,封装实现过程不如抽象实现过程。参考ACE的实现方法,是提供了一个Connector对象,并且运用工厂方法,连接成功生成Stream对象。这个抽象过程被众多的网络库所采纳,asio也采用这个抽象,据说asio要进boost了,真是个好消息。
另外书中关于TCP的例子,我觉得更象是从switch演变过来的,这正是第二点的一个补充:即使是少量的分支,也是可以运用STATE模式的。
在OO领域,switch一直以来是为人诟病的:扩展极不灵活,代码的远程耦合。case 条件的设置和检查是分离的,但是确是强耦合的。为此,很多人建议使用表驱动的方式,这个表驱动其实只是一个跳转表而已,好处是逼迫程序员必须将每个case的检查分离到独立的过程中去,不足是跳转表仍然需要维护。如果把每个case的处理过程组织成class,在C++中,借助局部静态对象初始化技术,则有可能将跳转表的维护半自动化,并且不再需要集中维护跳转表。再考虑switch的工作过程:首先,我们要在某处设置case条件,然后最终落到swicth中去。既然我们需要设置case条件,那么,另一个办法是我们直接设置相应case条件的处理代码,最后,在本来应该switch的地方调用我们设置的代码就是了,这样就彻底解决了switch。虽然,我们并不容易设置这样一段代码。但是,一般来说,还是比较容易的,最简单的就是借助于虚函数。为处理代码提供统一的接口,在选择条件的地方,选择合适的对象即可。另一个不错的办法则是使用functor。
解决了switch,再来考虑设置条件的地方。如果选择条件是一个复杂过程呢?我们连这个选择过程也封装起来,这样一个运作方式就是state模式了。一个典型的复杂的选择过程是状态机。