一个很小的C++写的MVC的例子
#include<iostream>
#include<vector> //get namespace related stuff
using std::cin;
using std::cout;
using std::endl;
using std::flush;
using std::string;
using std::vector; //struct Observer, modeled after java.utils.Observer
struct Observer
/*
* AK: This could be a template (C++) or generic (Java 5),
* however the original Smalltalk MVC didn't do that.
*/
{
//update
virtual void update(void*)=;
}; //struct Observable, modeled after java.utils.Observable
struct Observable
{
//observers
vector<Observer*>observers; //addObserver
void addObserver(Observer*a){observers.push_back(a);} //notifyObservers
void notifyObservers()
{
for (vector<Observer*>::const_iterator observer_iterator=observers.begin();observer_iterator!=observers.end();observer_iterator++)
(*observer_iterator)->update(this);
} /*
AK: If you had a method which takes an extra "ARG" argument like this
notifyObservers(void* ARG), you can pass that arg to each Observer via
the call (*observer_iterator)->update(this,ARG); This can significantly increase your View's reusablity down the track.
I'll explain why below in the View.
*/ }; //struct Model, contains string-data and methods to set and get the data
struct Model:Observable
{
//data members title_caption, version_caption, credits_caption
string title_caption;
string version_caption;
string credits_caption; //data members title, version, credits
string title;
string version;
string credits; //constructor
Model() :
title_caption("Title: "),
version_caption("Version: "),
credits_caption("Credits: "),
title("Simple Model-View-Controller Implementation"),
version("0.2"),
credits("(put your name here)")
{ } //getCredits_Caption, getTitle_Caption, getVersion_Caption
string getCredits_Caption(){return credits_caption;}
string getTitle_Caption(){return title_caption;}
string getVersion_Caption(){return version_caption;} //getCredits, getTitle, getVersion
string getCredits(){return credits;}
string getTitle(){return title;}
string getVersion(){return version;} //setCredits, setTitle, setVersion
void setCredits(string a){credits=a;notifyObservers();}
void setTitle(string a){title=a;notifyObservers();}
void setVersion(string a){version=a;notifyObservers();}
/*
* AK notifyObservers(a) for credit, title and version.
* All as per discussion in View and Observer *
*/
}; /*
AK:
Great stuff ;-) This satisfies a major principle of the MVC
architecture, the separation of model and view. The model now has NO View material in it, this model can now be used in
other applications.
You can use it with command line apps (batch, testing, reports, ...),
web, gui, etc. Mind you "MVC with Passive Model" is a variation of MVC where the model
doesn't get even involved with the Observer pattern. In that case the Controller would trigger a model update *and it* could
also supply the latest info do the Views. This is a fairly common MVC
variation, especially with we apps.
*/ //struct TitleView, specialized Observer
struct TitleView:Observer
{
/*
* AK:
* I like to get a reference to the model via a constructor to avoid
* a static_cast in update and to avoid creating zombie objects.
*
* A zombie object is instantiated but is unusable because it
* is missing vital elements. Dangerous. Getting model via the
* constructor solves this problem. Model model;
// Cons.
TitleView (Model* m) .... RE-USABILITY.
Some views are better off working with the full Model, yet others are
better off being dumber. I like to have two kinds of Views. Those that work with full Model (A)
and those that only work with a limited more abstract data type (B). Type A.
Complex application specific views are better off getting the full
model, they can then just pick and choose what they need from the full
model without missing something all the time. Convenient. Type B.
These only require abstract or generic data types. Consider a PieChartView, it doesn't really need to know about the full
Model of a particular application, it can get by with just float
*values[] or vector<float>; By avoiding Model you can then reuse PieChartView in other applications
with different models. For this to be possible you must use the 2 argument version of
notifyObservers. See comments on Observer class. See my Java example NameView. That view only knows about a String, not
the full Model.
*/ //update
void update(void*a)
/*
*AK:void update(void*a, void*arg) is often better. As per discussion
above.
*/
{
cout<<static_cast<Model*>(a)->getTitle_Caption();
cout<<static_cast<Model*>(a)->getTitle();
cout<<endl;
}
}; //struct VersionView, specialized Observer
struct VersionView:Observer
{ //update
void update(void*a)
{
cout<<static_cast<Model*>(a)->getVersion_Caption();
cout<<static_cast<Model*>(a)->getVersion();
cout<<endl;
}
}; //struct CreditsView, specialized Observer
struct CreditsView:Observer
{ //update
void update(void*a)
{
cout<<static_cast<Model*>(a)->getCredits_Caption();
cout<<static_cast<Model*>(a)->getCredits();
cout<<endl;
}
}; //struct Views, pack all Observers together in yet another Observer
struct Views:Observer
{
//data members titleview, versionview, creditsview
TitleView titleview;
VersionView versionview;
CreditsView creditsview;
/*
* AK:
* Views are often hierarchical and composed of other Views. See
Composite pattern.
* vector<View*> views;
*
* Views often manage (create and own) a Controller.
*
* Views may include their own Controller code (Delegate).
*
*/
//setModel
void setModel(Observable&a)
{
a.addObserver(&titleview);
a.addObserver(&versionview);
a.addObserver(&creditsview);
a.addObserver(this);
} //update
void update(void*a)
{
cout<<"_____________________________";
cout<<"\nType t to edit Title, ";
cout<<"v to edit Version, ";
cout<<"c to edit Credits. ";
cout<<"Type q to quit./n>>";
}
}; //struct Controller, wait for keystroke and change Model
struct Controller
/*
* AK: Controller can also be an Observer.
*
* There is much to say about Controller but IMHO we should defer
* that to another version.
*/
{
//data member model
Model*model; //setModel
void setModel(Model&a){model=&a;} //MessageLoop
void MessageLoop()
{
char c=' ';
string s;
while(c!='q')
{
cin>>c;
cin.ignore(,'\n');
cin.clear();
switch(c)
{
case 'c':
case 't':
case 'v':
getline(cin,s);
break;
}
switch(c)
{
case 'c':model->setCredits(s);break;
case 't':model->setTitle(s);break;
case 'v':model->setVersion(s);break;
}
}
}
}; //struct Application, get Model, Views and Controller together
struct Application
{ //data member model
Model model; //data member views
Views views; //data member controller
Controller controller; //constructor
Application()
{
views.setModel(model);
controller.setModel(model);
model.notifyObservers();
} //run
void run(){controller.MessageLoop();}
}; //main
int main()
{
Application().run();
return ;
}
一个很小的C++写的MVC的例子的更多相关文章
- 【生产问题】记还原一个很小的BAK文件,但却花了很长时间,分析过程
[生产问题]还原一个很小的BAK文件,但却花了很长时间? 关键词:备份时事务日志太大会发生什么?还原时,事务日志太大会怎么办? 1.前提: [1.1]原库数据已经丢失,只有这个bak了 [1.2]ba ...
- 【mysql】一个很小但很影响速度的地方
如果要插入一大批数据,千万不要一条一条的execute, commit.而应该是先全部execute,最后统一commit!!! 千万注意,时间差距还是很大的!! 正确示范:快 ): sql = &q ...
- jquery学习心得:一个很好的css和js函数调用的例子
统一目录下的资源结构图: <html><head> <link rel="stylesheet" href="gallery.css&quo ...
- 手把手教你写一个RN小程序!
时间过得真快,眨眼已经快3年了! 1.我的第一个App 还记得我14年初写的第一个iOS小程序,当时是给别人写的一个单机的相册,也是我开发的第一个完整的app,虽然功能挺少,但是耐不住心中的激动啊,现 ...
- 有一个很大的整数list,需要求这个list中所有整数的和,写一个可以充分利用多核CPU的代码,来计算结果(转)
引用 前几天在网上看到一个淘宝的面试题:有一个很大的整数list,需要求这个list中所有整数的和,写一个可以充分利用多核CPU的代码,来计算结果.一:分析题目 从题中可以看到“很大的List”以及“ ...
- 很小的一个函数执行时间调试器Timer
对于函数的执行性能(这里主要考虑执行时间,所耗内存暂不考虑),这里写了一个简单的类Timer,用于量化函数执行所耗时间. 整体思路很简单,就是new Date()的时间差值.我仅仅了做了一层简单的封装 ...
- 「小程序JAVA实战」 小程序手写属于自己的第一个demo(六)
转自:https://idig8.com/2018/08/09/xiaochengxu-chuji-06/ 自己尝试的写一个小demo,用到自定义样式,自定义底部导航,页面之间的跳转等小功能.官方文档 ...
- 分享一个自己写的MVC+EF “增删改查” 无刷新分页程序
分享一个自己写的MVC+EF “增删改查” 无刷新分页程序 一.项目之前得添加几个组件artDialog.MVCPager.kindeditor-4.0.先上几个效果图. 1.首先建立一个数 ...
- MVC已经是现代Web开发中的一个很重要的部分,下面介绍一下Spring MVC的一些使用心得。
MVC已经是现代Web开发中的一个很重要的部分,下面介绍一下Spring MVC的一些使用心得. 之前的项目比较简单,多是用JSP .Servlet + JDBC 直接搞定,在项目中尝试用 Strut ...
随机推荐
- c++的if语句中的110为什么不等于110?
从上图可以看出,当表达式1.1*x被直接放进if的判断括号中时1.1*x不等于y,但是将1.1*x赋值给z时,z与y相等,这是为什么?(以下为不等价时的代码) #include<stdio.h& ...
- loj6063 Shadow
题目描述 题解: 显然凸多面体投下来一定是个凸多边形. 对于$30$分,直接投到$x-y$平面上即可. 对于$100$分,考虑搞出平面的一般式方程$ax+by+cz+d=0$. 给出平面上三个点$A, ...
- 【模板】插头dp
题目描述 题解: 插头$dp$中经典的回路问题. 首先了解一下插头. 一个格子,上下左右四条边对应四个插头.就像这样: 四个插头. 一个完整的哈密顿回路,经过的格子一定用且仅用了两个插头. 所以所有被 ...
- linux常用过滤日志命令
#过滤nginx访问日志awk '{print $1}' /var/log/nginx/access.log | sort | uniq -c | sort -nr -k1 | head -n 10 ...
- POJ 3258 River Hopscotch (二分法)
Description Every year the cows hold an event featuring a peculiar version of hopscotch that involve ...
- python020 Python3 OS 文件/目录方法
os 模块提供了非常丰富的方法用来处理文件和目录.常用的方法如下表所示: 序号 方法及描述 1 os.access(path, mode) 检验权限模式 2 os.chdir(path) 改变当前工作 ...
- XV6陷入,中断和驱动程序
陷入,中断和驱动程序 运行进程时,cpu 一直处于一个大循环中:取指,更新 PC,执行,取指…….但有些情况下用户程序需要进入内核,而不是执行下一条用户指令.这些情况包括设备信号的发出.用户程序的非法 ...
- COJ 1211 大整数开平方
手写求大整数开根号所得到的值,具体计算过程参考别人的资料,最后利用java的大整数得到答案 别人博客链接:http://www.cnblogs.com/Rinyo/archive/2012/12/16 ...
- 【链表】2017多校训练三 HDU 6058 Kanade's sum
acm.hdu.edu.cn/showproblem.php?pid=6058 [题意] 给定一个排列,计算 [思路] 计算排列A中每个数的贡献,即对于每个ai,计算有ni个区间满足ai是区间中的第k ...
- 如何打开Oracle的dmp文件
在工作中经常使用到别人提供过来的dmp文件,由于不知道备份时所用的用户名,这样就不能恢复. 通过打开DMP文件可以查看到备份时使用的用户名. 1.如果dmp文件比较小,用文本编辑器打开就可以了. 2. ...