以下关于GOF的一些例子命名不是很准确,但是大概意思差不多,懒得再去翻书了

 
模拟观察者模式
观察者与职责链模式应该是我们项目中用的最多的了
 
我在之前也写过一篇利用观察者模式对模块进行解耦,当时还是用纯虚函数
 
用纯虚函数来模拟接口是我们之前比较经常使用的方法
这样的缺点是  需要自己去编写接口的纯虚函数,接口的注册和反移除,接口的清理
后来发现了boost的signals库,当需要通知的时候只要负责发送信号就可以了,其他的程序只是负责connect和disconnect,signals库把我从自己编写接口管理代码中解放出来了
与观察者模式相同的是职责链模式,不同的是,职责链模式可以决定消息是否继续往下传递,而signals都会进行传递,所以如果需要职责链,可能还是需要自己去编写手动管理接口的代码
 
 
模拟中介者模式
GOF里面在对中介者模式进行介绍的时候说了设计模式中很重要的一点,就是将行为分散到各个对象中,这个也是我最近在项目代码里面所提倡的,这样的做法就是会降低可复用性
通俗点来讲就是当一个模块的子模块状态发生改变以后,如果通知其他模块或者父模块??
比如要制作图片显示的模块,当图片被放大缩小的时候,有一个文本框需要动态显示当前的比例,我们是怎么通知其他模块的呢??
 
在原来的代码中我们是这样的:
OnZoomIn()
{
parentWindow->NotifyZoomIn();
}
这样,当我们还需要通知另外一个模块A的时候,还需要依赖模块A,所以我们的画图板就依赖了parentWindow,moduleA
这个就是我们原来的编程方式,很奇怪的方式,明明画图板跟模块A和parentWindow没关系却还要去依赖他们
后来学聪明了,就改成这种方式:
     class IPainterNotify
{
virtual void ZoomIn() = ;
virtual ~IPainterNotify() =
{
}
};
OnZoomIn()
{
for(all_notify)
{
notify->ZoomIn();
}
}

这样做的麻烦之处就是我们需要自己去编写接口的管理代码,每一次都要自己定义一大堆的接口,然后自己去写register和unregister,并且经常一个类从其他模块块继承一堆interface,模块耦合很严重

后面看了QT的signal-slot机制,发现wxwidgets加上boost的signals也能做到,不过我认为boost的signals才是正道,像qt的signal需要moc支持,在编译前还需要去修改源文件,而boost的signals则是依赖function-bind机制,function和bind是用C++的模板进行实现的,属于C++自带支持
 当画图板放大或缩小以后,只负责发送信号,其他模块负责提供接口,然后创建的时候互相链接就可以了,这样,各个模块之间都不知道互相之间的存在
 这样就避免了GOF中间提到的面向对象会降低模块的可复用性,并且不需要自己编写接口管理,相对于书中的例子,用signals明显耦合度更低
 
 
利用function模拟command模式(命令模式)
GOF在用command模式的时候举了个例子,就是菜单栏,当我们点击菜单栏以后,要执行一系列的动作,比如openDocument,pastDocument
GOF的做法是定义一个Interface,然后将菜单的响应动作与对应的interface连接起来,这样编码很麻烦,因为我们需要
1.定义interface
2.继承interface
3.实现interface
4.链接interface
 
而且使得事件响应与interface产生了依赖,也使得其他模块对interface产生了依赖
 
我的做法是,定义一个function,然后将function与interface的事件响应bind起来,这样就不用上面那么多步骤了,我们要做的只是链接interface,然后点击菜单后,就直接调用function就可以了,而且两者并不互相依赖,
 
GOF还提到一个历史恢复的问题,比如画图板里面有一个剪切和粘贴功能,将一个图片粘贴后,发现不需要,需要恢复,GOF是再定义一个恢复的接口,这样,每个的command除了有excute的接口,还有一个revert的接口,编码很麻烦,因为在我们的实际项目中,如果需要状态恢复,可不是一个revert接口就够的,还需要一堆的数据,为了绑定这些数据,我们需要继承command的interface,然后传入一堆数据,然后revert的时候根据这些数据进行操作
 
后面我用python的closure后,想起来可以用function模拟这个操作
 
 
利用shared_ptr与function模拟memento和command模式的状态保存和恢复
与command的revert操作类似的还有memento,不过如果按照GOF上面的做法,我们又要定义一个基类,然后从这里面继承一堆子类,用function则不用那么麻烦,因为function可以绑定很多的参数
比如在画图板里面我们需要保存一个点的状态
 

class Point:public boost::enable_shared_from_this<Point>,public IClosure
{
public:
  Point( int x,int y )
  {
    m_x = x;
    m_y = y;
  }
  virtual FUNC_CLOSURE SaveState()
  {
    auto func =
      boost::bind( &Point::SetPoint,this->shared_from_this(),m_x,m_y );
    return func;
  }
  void SetPoint( int x,int y )
  {
    m_x = x;
    m_y = y;
  }
  protected:
  int m_x;
  int m_y;
};
 

这样,当我们需要状态保存的时候,不管是Line,Circle,还是Point,调用SaveState即可,如果按照GOF的comment或者memento,我们可能需要定义一堆的LineState或者CircleState和PointState来支持不同的类型保存和恢复,不过付出的代价就是调试困难,毕竟function里面比较难看到里面的数据

看的不是很懂的模式:visitor模式

我也看得不是很懂这个模式,感觉没什么用,如果把那个accept接口换成function,比直接在基类定义一大堆的A,B,C来的好得多,只需要统一提供一个function就可以了

设计模式的一些杂谈与反思---functionn和signals的更多相关文章

  1. MMO之禅(三)职业能力

    MMO之禅(三)职业能力 --技术九层阶梯 Zephyr 201304 有了精神,我们还需要实际的行动. 到底需要什么能力?自我分析,窃以为为有九层,无所谓高低,因为每一层都需要不断地砥砺,编程,本身 ...

  2. UnitOneSummary

    目录 一.程序结构分析 第一次作业 第二次作业 第三次作业 二.Test & Bugs 三.设计模式 四.总结与反思 一.程序结构分析 第一次作业 思路: 1.输入预处理: 去除空格和\t 替 ...

  3. QT5每日一学(三) QT登陆对话框

    一.使用设计模式创建界面 1.新建Qt Widgets Application,项目名称为login,类名和基类保持MainWindow和QMainWindow不变. 2.完成项目创建后,向项目中添加 ...

  4. iOS设计模式反思之单例模式的进化

    什么是单例模式? 单例模式想一个大独裁者,他规定在他的国度里面,所有数据的访问和请求都得经过他,甚至你要调用相关的函数也得经过它.学术一点就是,单例模式,为某一类 需求和数据提供了统一的程序接口.主要 ...

  5. Android设计模式源码解析之桥接模式

    模式介绍 模式的定义 将抽象部分与实现部分分离,使它们都可以独立的变化. 模式的使用场景 如果一个系统需要在构件的抽象化角色和具体化角色之间添加更多的灵活性,避免在两个层次之间建立静态的联系. 设计要 ...

  6. Java设计模式学习资源汇总

    本文记录了Java设计模式学习书籍.教程资源.此分享会持续更新: 1. 设计模式书籍 在豆瓣上搜索了一把,发现设计模式贯穿了人类生活的方方面面.还是回到Java与程序设计来吧. 打算先归类,再浏览,从 ...

  7. JavaWeb网上商城的反思

    不知道从什么时候起,我爱上了写博客,对之前学得的只是进行反思.写了几天课程设计,代码量量8.9千左右. 然后下面文字是我在博客上复制过来的,说得很详细 MVC(Model View Controlle ...

  8. java_设计模式_观察者模式_Observer Pattern(2016-07-27)

    看了好几篇文章,最终还是觉得<Head First 设计模式>举得例子比较符合观察者模式. 观察者模式概述: 观察者模式有时被称作发布/订阅模式,它定义了一种一对多的依赖关系,让多个观察者 ...

  9. 从SonarQube谈设计模式

    SonarQube SonarQube是用来检测代码质量的,但类似工具的推广常常遇到阻碍. 成型项目或僵尸项目可以理解,项目优化需要投入的人力成本和时间成本太大,而且最主要的是无法保证改动过程中不引入 ...

随机推荐

  1. Python 新手常犯错误(第二部分)

    转发自:http://blog.jobbole.com/43826/ 在之前几个月里,我教一些不了解Python的孩子来慢慢熟悉这门语言.渐渐地,我发现了一些几乎所有Python初学者都会犯的错误,所 ...

  2. ZOJ 1007 Numerical Summation of a Series

    原题链接 题目大意:x的取值从0.000到2.000,输出每个x对应的y(x)的值 解法:参考了这篇日志http://www.cnblogs.com/godhand/archive/2010/04/2 ...

  3. php脚本时 linux命令获取服务器IP

    exec("netstat -anp | grep smtp",$sendList);   //php脚本获取服务器邮件进程数 exec("netstat -anp |g ...

  4. android的消息处理有三个核心类:Looper,Handler和Message。

    android的消息处理机制(图+源码分析)——Looper,Handler,Message   作为 一名android程序员,我学习android的一大乐趣是可以通过源码学习google大牛们的设 ...

  5. 课堂所讲整理:Set和Map

    Set相关知识: package org.hanqi.array; import java.util.*; public class Test2 { public static void main(S ...

  6. 由登录服务器时ulimit配置报错,也谈下ulimit配置

    最近在登录开发机时,有报错如下: -bash: cannot modify limit: Operation not permitted 一定是哪个地方有ulimit设置,想想看,用户登录或用户su命 ...

  7. 深入理解javascript的闭包

    闭包(closure)是Javascript语言的一个难点,也是它的特色,很多高级应用都要依靠闭包实现. 一.变量的作用域 要理解闭包,首先必须理解Javascript特殊的变量作用域. 变量的作用域 ...

  8. Flash pixel Bender学习笔记

    pixel Bender是指用来创建,编译,测试和导出pixel shader,用于各种flash产品的一个IDE. Pixel Bender是Adobe推出的一个高性能的图像视频处理技术.它能跨平台 ...

  9. AWR分析。(shared_pool,sga_size大小设置)

    Execute to Parse 指标反映了执行解析比 其公式为 1-(parse/execute) , 目标为100% 及接近于只 执行而不解析 在oracle中解析往往是执行的先提工作,但是通过游 ...

  10. 通知---iOS

    #import <Foundation/Foundation.h> #define CHILD_WEAK_NOTIFC @"childe_week" @interfac ...