标题是模仿在实验室坐我旁边座位的博士的qq签名档来的,原文是“功夫在诗外”,没有用Google去追究其意义。抽取科研活动的空闲,写下这篇文字,随笔一下近来对技术的若干感悟。 这几天正在用C#写一个数字病理切片的浏览程序。此前对着Visio 2007断断续续发呆了两天多,折腾出一些流程图和一个客户端的UML图,发给Boss审阅。Boss说目前倒是不用设计得这么复杂,暂时没有分布式环境的需求。我依然坚持自己的观点认为基础性的架构设计应该做得比较充分,考虑到未来可能发生的一些变化,使用了工厂、桥接器、中介者等模式,以及为状态模式预留了接口,将客户端与后台服务层的通信单独抽离为一个接口,这样无论是现阶段原型任务的本地读取还是未来的Web调用,所需要改变的可能仅仅是一个配置文件而已,连源代码都无需再次编译。 Boss是一个非常不错的家伙,在海外待了不短年头,我们讨论和交流过不少问题。虽说是师生关系,但对于一个工作上技术上的问题始终能保持在比较平等的位置上进行交谈。我很喜欢在与人共事时“对事不对人”的做法,唯有这样才能让你的Team或者Partner能够诚实地与你交流工作的进展状况,从而能稳步地将任务往前头推进。不过说是容易的,真正想做到这样的程度并非易事,至少不是太多人能坦诚地说出自己在工作进度上的不乐观。 与Boss交流这个项目的时候,终于是说服他使用.NET作为我们的基础框架,C#作为编程语言,这不仅仅是因为我喜欢它,熟悉它,更多是从项目的实际需要来考虑的。这个系统是一个分布式应用系统,Java和C#就是专门来对付这类情况的,选用C++看起来没有什么理由,MFC更是无稽了。而对于桌面应用软件的开发,C#又比Java要来的有优势,而且开发速度快,GUI不算太丑,也能满足我们短期内开发出原型的需求。说起各种语言,长期以来总是在各个技术社区看到相关所谓的语言对比与论战的帖子,包括比较有名气的CSDN,博客园等,而且不时出现在首页头条上,哭笑不得。 语言实在是没有什么好争论乃至相互鄙夷的,正如同C++的老爸说的,世界上有两种编程语言,一种是没有人用的,一种是天天被人骂的。我的想法就是,研究古英语总不能拿德文来折腾,与火星人打交道自然要用火星语。COBOL都多老了,现在仍然活跃在Mainframe上,而Mainframe的汇编甚至还在大规模使用。有的语言是拿来解决机器的问题的,所以与硬件更有亲和度;有的语言是用来解决现实世界的应用问题,所以更倾向于人的思维,而且在可读性上更好,学习曲线更平滑。 C#是一门好语言,尽管与已有十多年历史的Java比起来它只是个换牙年龄的儿童,但是也同样由于是晚辈,充分吸取了先人之长而避诸短处,焕发着勃勃活气。如果说.NET 1.x与C# 1.0给人以学Java步的感觉的话,那到了.NET 2.0与C# 2.0引入泛型(Generics)并对CLR、FCL进行大规模重写,.NET 3.0加入了充满大统一论调的WF(Windows Workflow Foundation)、WCF(Windows Communication Foundation)、WPF(Windows Presentation Foundation),.NET 3.5与C# 3.0新增了类型推断、Lambda表达式、LINQ之后,C#在短短的年头里得到了飞速的进化。 简单的,举我前不久写过的一个小文章里头的例子,用C# 3.0写一个接收用户的控制台输入计算Fibonacci数列元素的代码段: Func<int, int> fib = null; fib = (n => n > 1 ? fib(n – 1) + fib(n – 2) : n); var i = int.Parse(Console.ReadLine()); Console.WriteLine(String.Format("Element {0} in a Fibonacci sequence [...]
Archive for the ‘计算机与 Internet’ Category
功夫在代码外 Leave a comment
Have Fun with Microsoft Popfly Leave a comment
Knowing that live ID is opening for registration, I can’t wait to get one with the @live.cn suffix. With this id, users can enjoy various kinds of services from Microsoft. Popfly is one of the most exciting things. With this stuff, one can create beautiful mashups and webpages without writing any code. Before having fun [...]
随手写几种常用排序算法练练手 【C#】 1 comment
今天开始看MIT的《算法导论》,用C#随手写了常用的几种排序算法作为复习练习,贴出来混篇文章 首先写一个泛型的对象数据交换的方法供调用 /// <summary> /// 交换 /// </summary> /// <typeparam name="T">参数类型参数</typeparam> /// <param name="o1">对象1</param> /// <param name="o2">对象2</param> private static void Swap<T>(ref T o1,ref T o2) { T temp; temp = o1; o1 = o2; o2 = temp; } 插入排序 /// <summary> /// 插入排序 /// </summary> /// <param name="array">待排序数组</param> /// <param name="order">排序方式</param> public static [...]
最近写的求凸包的作业,使用Graham’s Scan 1 comment
// 根据设定的数目和区域生成随机点集void CPolyCalcDoc::PointsGenerate(CArray<CPoint,CPoint>& pointArray, long pointAmount, CPoint pointLeftTop, CPoint pointRightBottom){ pointArray.RemoveAll(); this->m_drawResult=0; int x=pointRightBottom.x-pointLeftTop.x; int y=pointLeftTop.y-pointRightBottom.y; // 未设定点集范围的情况 if(x==0||y==0) { CRect rect; GetClientRect(::AfxGetMainWnd()->m_hWnd,&rect); x=rect.right; y=rect.bottom; } for(int i=0;i<pointAmount;i++) { pointArray.Add(CPoint(rand()%x+pointLeftTop.x,rand()%y+pointLeftTop.y)); }} // 使用Graham’s Scan算法计算最小凸壳点集void CPolyCalcDoc::GrahamScan(CArray<CPoint,CPoint>& pointArray,CArray<CPoint,CPoint>& polygon){ polygon.RemoveAll(); CArray<CPoint,CPoint> originArray; originArray.Append(pointArray); // 寻找扫描基点,y<max> int count=originArray.GetCount(); int baseIndex=0; baseP=originArray.GetAt(0); for(int i=1;i<count;i++) { if(pointArray.GetAt(i).y>baseP.y) [...]
CxImage获取像素点RGB值 Leave a comment
位图的坐标原来是定义在左下角的,这个问题困扰了我半个下午(代码执行结果的谬误) 依然是MFC的代码,写在MouseMove的事件Handler中 void CFormTestView::OnMouseMove(UINT nFlags, CPoint point) { // TODO: Add your message handler code here and/or call default CFormTestDoc* pDoc=GetDocument(); CString rInfo,gInfo,bInfo; RGBQUAD col_image; long height=pDoc->image.GetHeight(); // 坐标变换:height-point.y,这样才变换到位图的坐标系 col_image=pDoc->image.GetPixelColor(point.x,height-point.y,FALSE); rInfo.Format("%d",col_image.rgbRed); gInfo.Format("%d",col_image.rgbGreen); bInfo.Format("%d",col_image.rgbBlue); // 把获取的信息写在状态栏中 CString str; CMainFrame* pFrame=(CMainFrame*)AfxGetApp()->m_pMainWnd; CStatusBar* pStatus=&pFrame->m_wndStatusBar; if(pStatus) { str.Format("x=%d,y=%d,r=%d,g=%d,b=%d", point.x,point.y,col_image.rgbRed,col_image.rgbGreen,col_image.rgbBlue); pStatus->SetPaneText(1,str); } [...]
CxImage实现多帧TIFF的帧循环 Leave a comment
发现CxImage是根据程序的请求,每次只载入一帧,和我上次写的CLR下的TIFF类那种在内存中维持所有帧的方式不同。事实上我在设计CLR下的TIFF类的时候也考虑过到底采用哪一种方式更合理一些 MFC的代码(目前还没有实现用C#的调用,总是找不到入口点): void CFormTestView::OnFrameLoop(){ // TODO: Add your command handler code here CFormTestDoc* pDoc=GetDocument(); // 这里最好断言一下 // 图像的总帧数 long frameCount=pDoc->image.GetNumFrames(); // 实际载入的帧 long curFrameIndex=pDoc->image.GetFrame(); // 设定新帧 pDoc->image.SetFrame((++curFrameIndex)%frameCount); // 重新载入 // 这里是参考的作者文档中的一句话得到的方法 // Sets the image number that the next Decode() / Load() call will load pDoc->image.Load(pDoc->filePathName); // 重新设定显示的位图 HBITMAP m_bitmap=NULL; [...]
配置好了CxImage库 Leave a comment
我觉得这个配置方法应该能简化,不过现在暂时不考虑这个,有功能真就万幸了。 CodeProject上作者提供的文档,乃至诸多国内技术Blog翻译修改的文档都有些不详细的地方,没办法了,只有自己来。 我下载的是CxImage源码包,在折腾我自己的工程之前已经将它编译ok了(一大堆lib),然后把它们和我自己的工程(CxTest)放在一个文件夹下面,包括CxImage,j2k,jasper,jbig,jpeg,png,tiff,zlib这几个工程,然后将它们添加到我自己的Workspace ‘CxTest’ 接下来是设置参数了,小麻烦,好在文档写得还算清楚了,以下照抄 Project Settings |- C/C++ | |- Code Generation | | |- Use run-time library : Multithreaded DLL (must be the same for | | | all the linked libraries) | | |- Struct member alignment : must be the same for all the linked | | | libraries | |- Precompiled headers : [...]
Stanley B. Lippman:编程是一门艺术吗? 1 comment
发布日期: 2006-10-23 | 更新日期: 2006-10-23 Stanley B. Lippman 仅仅使用软件的人们 通常意识不到编写软件有多么困难。噢,设计部分和最初开发部分都 很有趣。最困难的部分是使其正确运行(且运行速度足够快)。对于程序员而言,这就好 比一餐开始时是美味的双层牛奶巧克力咖啡干酪饼,而结束时却是菠菜奶油沙司。 之所以说编程仍是一门艺术而不是一门科学或工程学科,是因为我们还不能将其分解成多 个组成步骤,而后机械地进行。一旦我们在此方面获得成功,在某种程度上就会出现一种 新的可能性:在编程时采用以人为本的设计语言 (PODL) 编写程序,通过编程来证明程序 的正确性以及分析和支持语义查询。然而到那时,编程依然是一门艺术,也就是其中含有 那么多传统智慧。 但是,如同许多传统智慧一样,此类比经不起进一步推敲。事实上,编制程序(我干这行 已经有 20 多年了)根本一点都不像艺术 — 至少不像写小说(我干这一行也已经有 20 多年了)那样的艺术。让我用两个片段(一个程序片段和一个散文片段)来说明我的观点 吧。 第一个片段是一个用于分析 Visual C++® 7.1 的词法分析程序的一部分。该片段如下 所示: if ( index >= TokenID::lastKeyword() ) { string token = tokenString( index ); if (( isdigit( token[ 0 ] )) [...]