引子:
在讨论架构之前,我们先上道菜,青椒土豆肉丝,这道小菜味道还是不错的,自私点了,不考虑您是否喜欢,今天就上它了。
准备原材料:食用油、青椒、土豆、肉丝、大葱、香醋、鸡精和食盐。当然根据需要您可以再加入其他辅料。把青椒、土豆、肉片都切成丝,大葱切好,OK,一切准备就绪,开火,往锅里加油,等油热后,放切好的葱片,闻到葱香,放肉丝,稍微加些酱油,爆炒,接着放土豆丝和青椒丝,等八成熟,撒些鸡精和食用盐,出锅。
细心的读者可能发现,刚开始的时候我好像并没有准备酱油,是的,我确实没准备酱油,坦白的讲,有时候当锅里的油热的时候,我突然发现葱忘记洗了,更谈不上切成葱片了,此时我会匆匆忙忙的去洗,去切,甚至有时候慌里慌张的把手给切破。
通过我们做上面的一道菜,我们总结了以下几点:
总结1:巧妇难为无米之炊,我们要想做好这道菜,需要原材料;
总结2:这些原材料以时间为轴心他们彼此之间是有顺序关系的;
总结3:可能在某一步骤里,我们突然想添加些事先并没准备好的原材料;
总结4:一旦形成热油锅,似乎你要在这么短的时间内完成这些动作,做过饭的朋友更能体会到这句话。
言归正传,以软件的思想去考虑上面的业务(事情),原材料,你可以理解为类库;顺序关系,你可以通过事件来描述;事先并没准备好的原材料,你可以通过接口(抽象类、虚函数等),让用户重载去实现;到这里你会发现,一旦打开“煤气”,去“引爆”预先设计的事件、接口,就好比多米诺骨牌一样一个接一个的传递下去,在某一时刻,它会检查是否放了“葱片”、是否放了“肉丝”,不好,“食用油”你就没放,还炒什么菜,扔出异常……
是的,上面就是框架,要想设计一个好的框架,看来我们首先要知道“青椒土豆丝”的做法,它大概需要哪些“原材料”,以及这些“顺序关系”该如何通过具体的语言去实现;当然了,要炒出“不同的菜”,具体的原材料和顺序关系又是不同的。下面通过分析几个大家比较熟悉的框架来更详细的说明。
MFC框架:
MFC中的框架思想采用了MVC的思想,其中CWinApp是全局型的,整个程序的引爆也是其在“搞鬼”,在其内部有指向文档模版的指针,而模板又攘括了视图、视图的管理者(就是那个frame)和文档类,顺序关系是靠消息泵来推动。通过下面的调用关系可以看到各个类的“相互依存”(说明:下面的表摘自网络)
从该对象 | 如何访问其他对象 |
全局函数 | 调用全局函数AfxGetApp可以得到CWinApp应用类指针 |
应用 | AfxGetApp()->m_pMainWnd为框架窗口指针;用CWinApp::GetFirstDocTemplatePostion、CWinApp::GetNextDocTemplate来遍历所有文档模板 |
文档模板 | 调用CDocTemplate::GetFirstDocPosition、CDocTemplate::GetNextDoc来遍历所有对应文档 |
文档 | 调用CDocument::GetFirstViewPosition,CDocument::GetNextView来遍历所有和文档关联的视图;调用CDocument:: GetDocTemplate 获取文档模板指针 |
视图 | 调用CView::GetDocument 得到对应的文档指针; 调用CView::GetParentFrame 获取框架窗口 |
文档框架窗口 | 调用CFrameWnd::GetActiveView 获取当前得到当前活动视图指针; 调用CFrameWnd::GetActiveDocument 获取附加到当前视图的文档指针 |
MDI 框架窗口 | 调用CMDIFrameWnd::MDIGetActive 获取当前活动的MDI子窗口(CMDIChildWnd) |
您可以试着联想“炒菜”的过程去思考上面的这张表,如果您真的理解了,我相信您会觉得他们之间没有什么区别(不过坦白来讲真的理解并没有那么容易),好吧,你可能又发出疑问?如果去做“填空题”?在MFC里是通过处理消息来实现。那么为什么没有采用虚函数及多态来实现?这个问题问的很好,不过我没打算在这里进行说明,你可以在侯杰的《深入浅出MFC》里找到答案。(我不是有意来推这本书,实在没看到其他更好的)。可能你从来没接触过MFC,那就不要去思考了,下面举另外一个例子。
asp.net:
asp.net的webForm以其容易上手而著称,如果你深入的理解了其页面生命周期后,你会发现这好像又是在“炒菜”,而我们要做的只是在不同的“炒菜步骤”内去定制我们的一些小创意,可能在Page_PreInit里、在Page_Init里、在Page_Load里或其它事件里,无论如何,您逃不过如来佛的手掌心,你要做的工作,就是在这些事件里去定制,换句话说,你搞不出来“宫保鸡丁”,想搞个“宫保鸡丁”该怎么办?asp.net MVC 粉墨登场……自己可以分析下,这里就偷懒省略了。
从炒菜到实例分析,现在我们基本上对软件架构有了一个大概的认识:
认识1:框架架构是有边界的,不光如此,你必须有全局的概念才能去设计框架。所谓边界是针对不同的业务,比如MFC是针对传统的桌面程序,当遇到WEB时,似乎就不怎么灵光了,不然微软不会花费那么多功夫去推.NET。
认识2:框架的实现是组件的相互关联(通过接口,事件等),如果你手里有些基本的类库,不要告诉我是框架。
认识3:设计框架不是为了好玩(其实它本身并不好玩),因为你要为“两个人”负责:业务和使用框架的人。建立在你框架上的应用必须能解决你实际的业务问题,同时要考虑怎么样让开发人员能“懒惰”下来,比如就是做做填空题。
认识4:设计框架要有一个好的框架思想,和具体语言无关,但你必须明白,不同的语言,甚至相同的语言去实现的方式又不相同,比如MFC采用了宏来实现消息机制,而asp.net内采用虚函数等来实现多态。
认识5:你要时刻明白,接下来可能炒的菜就是“宫保鸡丁”,也就是说你要知道自己在干什么,要熟悉自己的“业务”,比如当你设计MFC框架时,你要考虑一个传统的桌面程序要解决的大部分问题会是什么?比如打印,比如进程通信,比如文件操作,比如音视频,数据库操作,ole,等等。同样的,当你来设计ASP.NET时,因为这道菜是针对HTTP的,这个时候你如果连HTTP是什么都不知道,我想你炒不好这道菜。
OK,我想这篇文章该结束了,因为我们的“菜已炒好”,如果你认真仔细的看到这里,估计已经浪费了你近五分钟的时间,希望能给你带来点思考,比如:架构师就是来“炒菜”,可能吧,也可能我的观点并不完全正确。不过我欢迎聆听每个朋友对架构的理解。谢谢。