简介
学习观察者模式前先了解一个概念,框架。目前各种框架层出不穷(MFC、spring等),那框架和应用之间的关系又是什么?这里的应用就是指我们开发的各种程序(office、qq…)。
举个恰当的例子,大约1970年之前吧,程序开发是结构化的。什么是结构化的?就是一个功能一个函数,小拜负责A函数、小特负责B函数、小奥负责C函数。每个函数有具体的功能,这在开发软件之前已经商定好了。这种方法就类似于修房子,小拜干砖瓦活,小特搞装修、小奥通水电。那些年,软件需求量不大,用户要求也少,毕竟刚学会走(提不出啥要求,开发个软件,让我咋用我就咋用
),大家各司其职,也美滴狠!
时间到了1990年,用户接受了软件这个好东西,有了自己的想法了(这就危险了,毕竟想法越多越...
)。软件前辈们发现,之前的结构化模式不太美了,客户隔三差五变需求,提要求。改装修就会影响到水电,甚至砖瓦活也得重折腾,小拜、小特、小奥就很辛苦!
于是,新的东西诞生了!没错,就是框架!鲁迅先生说过:“人的性情总是喜欢调和、折中的。礕如你说这屋子太暗,须在这里开一个窗,大家一定不允许的。但如果你主张拆掉屋顶,他们就会来调和,愿意开窗了。”
到了给软件提要求时可不是这样了,拆屋顶都是小需求,动辄要拿千斤顶把房子举高高呢!
太阳底下没有新鲜事。小许,一位从建筑工人转行到程序员的前辈崭露头角,估计是九几年房地产不景气,也或许是大家不买期房的账了,这都不是重点。重点是,他发现之前搞房地产都是先钢筋混凝土先搞框架,再是水电,最后装修。怎么新兴的软件行业,精装修完了,客户让把承重墙换个位置?
一天晚上,大约两三点钟,小许想起了之前之前在币贵园当董事的杨总。记得之前他们的墙体容易开裂,“框架‘’容易出问题,问问他或许能有点启发!
“出卖我的爱,背着我离开,知道真相的我眼泪流下来…”一段火辣的手机铃声后,电话通了。这个点杨总没睡觉,不是加班哦,是人在巴黎爬埃菲尔铁塔呢。寒暄过后,小许抛出了困惑:“你们房子的框架出了问题,或者是客户让你们改框架,你们是如何处理的呢?”。小杨顿了一下,问道:“你是给你自己问,还是给买了我们房子的人问?”。小许思索片刻答道:“给我自己问!”。
“主要处理办法有两步,首先,客户发现主体有问题,我们会想办法在装修上盖过去!实在不行的话,我们墙体也做的不厚啊,修修补补糊弄过去也就行了,这是负责的做法。实在不想管就直接不搭理这些业主就行了。”,小杨边笑边回答道,“阿印,你怎么老实的跟个百姓似的,哈哈哈”。
杨总也是艺高人胆大,但是这给许前辈带来了灵感!当下较火的软件当属人机交互程序,也就是有UI界面的。这类程序无非是些按钮、输入框、下拉框、界面显示…,如果能有个类似结构框架的东西,把软件主体搭建起来,甚至水电也预留管道通好。每次给具体客户做的时候就只需要搞搞装修了。当然了,这个软件的框架也要和杨总的币贵园一样,要做的“够薄”,要有足够的适应性来应对客户的更改需求!
于是乎,框架的概念呼之欲出。各类框架层出不穷,但是万变不离其宗。其核心都逃不开我们今天的主角:观察者模式!
正文
先上类图
再来代码
//MainForm.cpp
#include <iostream>
#include <string>
#include "IProgress.h"
#include "ProgressBar.h"
#include "MainForm.h"
#include "ConsoleNotifier.h"
#include "FileSplitter.h"
using namespace std;
// class MainForm 主窗体程序
//按钮点击后
//创建了一个控制台通知器
//创建了一个文件分割器
//addIProgress 方法完成订阅通知,通知按钮,通知控制台通知器
//也就是 分割器的进度 既要告知按钮,也要告知界面显示部分
void MainForm::Button1_Click() {
string filePath = "C:\\Observer_Pattern_Note.txt";
int number = 100;
ConsoleNotifier cn;
FileSplitter splitter(filePath, number);
//注意 添加订阅的方法 是由发出通知的类所实现的 。
splitter.addIProgress(this); // MainForm 订阅通知
splitter.addIProgress(&cn); // ConsoleNotifier 订阅通知
splitter.split();//分割器启动
splitter.removeIProgress(this);//取消订阅
}
void MainForm::DoProgress(float value)
{
progressBar->SetValue(value);
}
MainForm::MainForm()
{
progressBar = new ProgressBar();
}
MainForm::~MainForm()
{
if (progressBar != NULL)
{
delete progressBar;
}
}
//ProcessBar.cpp
#include "ProgressBar.h"
#include <iostream>
#include <string>
#include "publicFun.h"
ProgressBar::ProgressBar():m_fValue(0)
{
//构造函数
}
void ProgressBar::SetValue(float fVal)
{
m_fValue = fVal;
ConsoleSetCursorPos(1, 0);
std::cout << "1号订阅者(观察者)汇报:当前进度:";
for (size_t i = 0; i < m_fValue*20; i++)
{
std::cout << "█";
}
}
//FileSplitter.cpp
#include "FileSplitter.h"
#include <Windows.h>
void FileSplitter::addIProgress(IProgress* iprogress)
{
m_iprogressList.push_back(iprogress);
}
void FileSplitter::removeIProgress(IProgress* iprogress) {
m_iprogressList.remove(iprogress);
}
void FileSplitter::split()
{
//1.读取大文件
Sleep(500);
//2.分批次向小文件中写入
for (int i = 0; i < m_fileNumber; i++) {
//...
float progressValue = m_fileNumber;
progressValue = (i + 1) / progressValue;
onProgress(progressValue);//发送通知
}
}
void FileSplitter::onProgress(float value)
{
list<IProgress*>::iterator itor = m_iprogressList.begin();
while (itor != m_iprogressList.end())
{
(*itor)->DoProgress(value); //更新进度条
itor++;
}
}
//Console.cpp
#include "ConsoleNotifier.h"
#include "publicFun.h"
void ConsoleNotifier::DoProgress(float value)
{
ConsoleSetCursorPos(2+1, 0);//在第几行 输出信息
std::cout << "2号订阅者(观察者)汇报:当前进度" << value;
}
int main()
{
MainForm mf;
mf.Button1_Click();
cout << "end...\n";
}