结构导向,物件导向的编程思路

        ”Object Oriented Programming “ 大陆通用翻译是”面向对象“,台湾翻译则是”物件导向“。在刚接触OOP时,我的老师曾饶有兴致的跟我讲:我觉得"物件导向"的翻译更合适一点。当时,有点疑惑。可能是老师思考的层次比较高吧。现在OOP干了快两年了。再次回味这个翻译。我确是感觉老师说"物件导向"这个翻译更合适点。(本人不是想讨论茴香豆的茴有几种写法。而是想表达一种对OOP的感受。至于叫什么无关大雅。)以下是我工作的经验总结,希望与大家分享讨论。

     从下棋说起:

     两人对弈(图略)

(本人结构化经验浅薄,说的不对望指教)

     结构化的思路:以具体事务为出发点开始分析,“下棋”是一个具有特定行为或称为结构化的具有特定结构的事务集合,就像“洗衣服”,这两件事咋看起来是毫无关联的。并具有不同的特性。在编写结构化的程序时,我们需要根据具体的事务,编制不同”实现“的程序。以“核心的结构”为中心,或叫”树根“,自根往”树枝“再往

”叶“的方向分析,编写而去,比如:我们先写一个下棋的主函数

,参数是棋盘,下棋人甲,下棋人乙,这是树根,再往下,我们编写联系函数,再编写具体类型的数据数据(下棋人甲,下棋人乙,棋盘)。

     程序运行时:从根下棋函数开始,调用各个联系函数,联系函数调用具体数据。以此来运行。整个编写是一个由根到叶的过程。具体数据是存活在整个结构体上。没有结构,数据就无法存活。我再啰嗦一句:你可以把叶子换成其它的叶子,但如果动了树根,叶子就很难再存活下去了。回到刚才那个话题,下棋人,和洗衣服的人,都是人,他们应该是具有一定共同数据特征的,但,你可以脱离下棋的结构,把下棋人这个叶子取下来,拿到洗衣服这个程序结构中运行吗?似乎不是那么容易吧。(本文只讨论编程思路不讨论其它效率之类的问题)。

     物件导向思路:我并不知道在读我这个文章的同仁会怎么样考虑分解两人对弈这个模型,我是这样看的。我第一感觉就会把这个模型划分成不同的对象,下棋人,棋盘,规则,等等,分解出不同的对象同时分解对象的行为特征,内部数据类型,以及对外的接口,比如:下棋人要与棋盘有接口,规则和棋盘,下棋人有接口,下棋人和下棋人有接口。根据分析的数据类型,先建立一个抽象的实现模型。就是先写对象出来。把行为,数据都抽象出来。至于具体的实现,那就是再下一步的事情了。抽象的具体实现。也就是具体设计上一步写的每个方法,每个属性。把实现填进去。从这里分析,我感觉,用OOP的思想,是先设计数据,也就是叶子,把叶子设计好后。再设计枝干,最后是树根,你的整个设计思路是以“数据对象”这个对象来导向的。

      整个程序运行可以理解为是一堆数据对象之间的运作。当然,树枝,树根,也是一种数据对象。最后程序的运行状态的设计,就变成了一种组装工作,你怎么组装,这些对象就会怎么运作。在<thiking in C++> 里面有一个观点:我自己总结的。OOP让你在一定程度上不在依赖于硬件甚至是软件提供给你的数据类型的束缚,让你更自由的面对你自己碰到的具体事务来设计你的程序。总结不好。见谅。

   结构和物件导向的设计和实现剥离:不管是一种静态的编译还是动态的编译,最后还是由CPU以具有特定次序的线程结构来实现。OOP就是在一定程序上让你摆脱实现上的设计。我感觉,在设计时不要去考虑实现和效率问题,比如:是用 stringbuilder  还是用 “string ”这样的问题。应该尽量可能的让现在数据满足你的实现。而不是让你的实现去迁就数据和平台。

   关于.net的技术使用的个人想法:对我而言,.net的很多技术就是螺丝刀,一个钳子,你知道它的原理,知道它是使用范围,在需要的时候拿过来用就可以了。就拿“泛型”来说,如果你真想从数学到软件实现,到.net平台实现上搞明白。其难度,我个人感觉不亚于正则表达式。很多时候,学习.net的技术就象爬到一个图形数据结构的节点上的蚂蚁,你刚站到一个点上就会发现你前面后面上面下面全是未知的点。如果你成为了那只蚂蚁:你就会发现一个事实,你是在用.net写OOP,而不是用OOP的思维方式写.net程序。

    

posted @ 2009-08-17 10:57 发条橙子 阅读(260) 评论(3) 编辑

                                     .net真的不用管内存吗?

         上周拜读了<你必须知道的.net> ,获益良多,现在只看完了一章,和中间IL描述的章节,很精彩,自己总结一下第一章的一个观点(原话已经不记得的了):

所有对象存活,运作的平台就是CLR(Common language runtime),这句话我琢磨了很久,加上最近自己写的代码中出现的一些有趣的现象,让我对.net有了一些有趣的想法。拿来和大家分享下,以证谬误,求得真知。好,闲话不说了。先拿出自己碰到写程序时碰到的一个小插曲。和大家聊聊。

         先聊一下List<T>

         MSDN上的解释Represents a strongly typed list of objects that can be accessed by index. Provides methods to search, sort, and manipulate lists.        

         我的理解:List<T>存储具有相同数据信息类型的列表,这个对象提供对这个列表的增删改查的功能接口。

 

         请大家看一下我碰到的一个对List<T>操作时碰到的有趣的问题,我把它贴出来,我想看到这篇文章的人有很多已经碰到过这个问题:

        

          


        稍作说明:Error1 编译错误,Error2 ,Error3 运行错误。话说回来,这个编译器还是很强大的。至于为什么第一个是编译错误,第二,三是运行时错误,我觉得这也是一个有趣的问题,如果那个大虾还是小虾有见解的话,叫上我一起讨论下。在语义分析阶段,不能发现第二个和第三个错误吗?

        我们先不管软硬件问题,先看逻辑分析:

         List<T> 列表的意义,和我们去超市买东西都会拿到这个东西,里面有时间,日期,价格,商品,等等,每一个信息类型基本都是一样的。记录我们的购买信息,我们假设拿到了这个列表,我们从第一行遍历看起,第一个,第二个,第三个。。。。。。第n个。突然兴奋的发现。超市的机器发生了错误。把原本1.00元的产品,读成了0.01元。我的天!走狗屎运啦。我们兴奋的拿笔自己修改这个选项。回家可以兴奋的向你女朋友邀功。今天省了0.9毛哦。

        我们看这个过程,遍历,修改其中的一项。逻辑上成立吗?一点问题都没有, 信息传输正确吗?当然。我们记录了我们修改的信息。这次我们对信息的修改完全正确无误。并用遍历,修改的逻辑完成了一次完美的操作。

       那为什么把这个工作交给.net,它就干不了?

       以下分析纯粹是个人理解,没有经过事实的佐证。如果那位有正解,在对本人想法嗤之以鼻的同时,万望贴出自己的想法。

       我想从机器读我们写的上面的高级指令开始分析

       编译它,形成IL代码,这个IL 其中,蕴含了什么信息。此次,限于本人时间和水平有限,请那位说明一下 。如果读到此贴的大虾。写过了解C#编译有什么特点,请贴出,本人除了知道语法,词法,语意原理,大概是什么流程结构外。没有动手实践过,所以此步完全靠原理分析。略过

       中间IL

       (请那位有空补上)

       最后的执行猜测

       内存中数据与指令的猜测。

       

 

 

 

 稍作说明:左边为数据堆栈就是List<T>,右边为对数据进行操作的指令就是add(),delete(),move()....最后形成的指令集合。下面单独拿出一个块获取数据堆状态,这个图是一个数据逻辑图,我自己猜测的。不是汇编指令形成的物理结构图。不讨论寻址,指针级别的内容。

     回到最初,为什么?foreach()之中不可以delete,remove,modify

     返回头我们想想,如果它支持在foreach的时候改,增,删 的话又要做些什么工作呢?

     比如要删一个。

     程序大概要做几件事情:第一 :记录数据堆删之前的状态,第二做数据处理,copy历史记录,第三:执行操作,第四:将新的数据堆返回给原地址或压根就改个读的首地址得了。如果,其它对象引用了这堆数据操作就更复杂啦。这几步只是我个人的一个理解模板,如果真要深究,什么地址,算法,压栈,出栈什么的,程序要做的事情就更多了。

     回到我们发现这个问题的起点。以及OO的理解,有趣的问题就会接总而来,如果,你写程序的时候,模拟我上面讲的那个修改账单的过程,用OO思想又怎么样设计呢? 把人做一个对象,把账单做一个对象?我想如果是一个非程序员,让他或她用面向对象的思想分析一下。至少有一半的人会这么分解这个对象图。那如果我们也这么分解。有没有这么问题?这中间是不是少了有价值的分解。如果那样分解的话,软件平台,机器能不能直接理解我们的程序意图,支持不支持呢?

    想起我上一次发的那个帖子,从设计,数学,指令,甚至从哲学上来看OO.OO 实在是一个强大又非常难控制的思想。 我们是不是需要在学习了解精美的设计模式之外,去理解程序,甚至数学的本质,那样是不是能让我们更有效的去掌控这个平台的威力。

    另外提一下:如果用for(int index = 0; index < myList.count; index++) 这种方式去执行上面那短程序,结果有会不一样。

    

   

 

 

 

 

posted @ 2009-06-18 12:29 发条橙子 阅读(1018) 评论(24) 编辑
                                          OO的设计模型,数学模型,物理模型
            第一次看到OO这个概念是在一本C++的书里面。里面举了个动物的例子。讲禽类,哺乳类,昆虫等等动物的继承关系,多态,等等概念。想起大学时候读的C语言里面的一张程序逻辑图。感觉这个OO实在是太神奇了。再后来接触到.net 。开始基于.net平台,用C#语言编写程序。一开始感觉相当好,文件操作 。用一个System.File 搞定。要扩充功能的话。自己自定义一个类,把System.File的功能拿过来就是。很舒服哦。这种感觉持续了两个月,等做到项目的中期,代码越来越多。结构越来月复杂。开始变的沮丧起来。原有功能保持不变,同时,要新增新的功能还要保持原有功能正常运转。我的天啊。我开始做起意大利面了。用更复杂的方法解决越来越多的问题。我开始反思这个OO了。OO到底是个什么概念。从设计到现在的意大利面。OO到底干了什么,我又干了什么。

          设计阶段

          用OO设计是一件很舒服的事,举例:两个人下棋                
          设计一个下棋的场景:拿生活中的例子看很容易看出至少三个对象,棋盘,下棋的人两个人如果再抽象点,就两个对象,下棋的人和棋盘。对这三个对象做一个分析,属性字段,值,方法,接口等等,是不是可以动手写代码了。好舒服。
          和结构性设计比起来,简直太舒服了。Class player ,Class player,Class Chessboard……里面要填什么功能的话,加方法,加接口,就算你的对象面向扩展,面向修改全开放。都没关系。就算你不懂i/o,不懂cpu,没关系,.net 有现成的类库。拿来使就是了。好了,我们大功告成了。

         伪代码
         Public  Class  Player        : Status:  name,ID    Function:   Do(),Show(),UserInterface();

         Public  Class Chessboard :Status: Color , Schema  Function : Run(); HandleError();

 

           就这么简单吗?
          如果我们就这么写,就又会发现很多的问题,棋盘规则 需要建一个对象吗?用户接口 需要建一个对象吗?还是当一个属性,用户是用抽象的类描述还是用实体类,棋盘呢?用form做用户接口吗?fom程序又怎么设计?等等。。。。。
          等我们满头大汗的硬着头皮写完了。第二天,经理发话了。我们需要在这个设计中加一张凳子。那还不简单,再建一个凳子类,Class  Stool.好。凳子给谁使用呢?放那呢?Stool怎么显示呢?是不是又要把棋盘的显示再抄过来,改几行代码。如果,显示又要换成浏览器呢?是不是又要考虑改动其它的代码?
          等再过两天.经理又说了:我们要加个空调。而且要有一个用户的接口,我们这个空调还要有收电费的功能。
          我的天啊。直接崩溃了。当你看着自己写的上万行甚至几万行恶心的代码。想死的心都有了。如果您耐心的读到这,肯定有些朋友会说:唉。你去读读设计模式吧。你的设计有问题,那么请问:有没有一种设计模式能在一开始就解决后面的扩展问题?就算你经验再丰富,设计水平再高。你就能保证你的模式能面对一个一个神奇的需求?只是加个接口加个属性或是价格对象就能解决问题?

          怎么办?

          这就是我的亲身经历。我开始反问自己。到底什么是对象。对象就是你写的那一长串不加注释就很难读懂的字符串?对象就是你脑子里面描述的一个抽象概念?对象是什么?到现在为止,我也没有找到一个合适的概念去理解它。只能从几个侧面去想想。

          从设计上来讲:
对象设计的确很容易,我以前参与过一个网页游戏的设计,代码编写。设计师给我的类图就一张比我上面描述的图详细不了一点点的图。代码已经写了上万行了,我的天。我足足用一个星期只能看懂一部分代码,参与不到一个星期,游戏设计者和程序员已经开始互相抱怨了。怎么老改啊?这么简单的功能不能实现吗?等等。一个小人儿,加个棋盘这就是对象设计吗?

从我目前的经验来说,我认为在需求分析,功能分析等等的最初阶段,就压根儿不用考虑计算机的问题,这种工作最好让市场人员来做。用一个一个的对象把客户的要求描述出来,比如说上面的棋盘和棋手,(在这我只是描述我的观点与线程设计回溯设计无关),客户想干嘛,想得到什么,客户是什么类型,。。。这些信息组合起来。得到一张最原始的需求图。同时对更改留下一部分的接口空间。这个图与计算机无关。

 

          从数学模型来讲:
图已经设计好了,那拿到这个图之后怎么办呢?我们一分析,三层架构?用户接口就出来了?不。我认为这里有一个最核心的设计。数学模型。这个阶段最好也不要考虑计算机的问题。
为什么?因为从客户需求,只是一种需求,对需求而言,计算机只是一种工具,计算机只能做一件事,就是计算。而且计算机本身其实就是数学家设计出来的。用冯诺依曼的思想来讲。它只做一件事,就是连续的执行程序。计算。就算我们的软件再天花乱坠。计算机就只有一种功能,软件也是同步计算实现各种需要的。所以,在这个阶段。我们需要干一件事。讲客户需求的类图,转换为数学模型类型类图。这些对象的关系是什么,对象有哪些,对象有什么方法。在这个阶段。对象就是数学意义上的对象。
讲这个需求用数学模型模拟出来。形成完成的数学结构,类似于(多形数据类型《严蔚敏》)的理解。

比如
数据:Data  D
数据间的关系:Relation R
数据方法:Function F
< D,R,F>

拿下棋的例子来说:我们需要用数学模型讲。棋手,棋盘,棋子,下棋的动作,棋盘面,甚至颜色,这些数据元素用结构严整的数学模型描述起来。建立一个健康的数学模型

 

             从物理模型来讲:
数学模型图与物理模型设计应该是同步完成的。就像编译时的语法,词法分析过程一样。
(不知道有没有这样的程序,可以帮我们自己建立数学模型。:))
物理模型才是程序员最综的工作。
拿到数学模型,
<D,R,F>
使用专业技能用计算机模拟操作。把操作步骤存储在计算机内。供客户使用。.net平台只是一个平台,让我们设计完成这些工作的一个稳定良好的平台。你用C 语言来面向对象设计,也是一样。当然肯定不好用啦。它的设计是结构性的。用来控制计算机的。毕竟我们手头上的硬件设计还是面向结构的。

         另外我的感觉是:

        面向对象的设计和代码编写,对程序员的要求更高了,它需要程序员掌握很多的设计,数学,硬件知识,我见很多人说,程序员离底层原来越远了,我实不以为然,不管是现在的面向对象还是将来面向服务啊。或什么的。要求程序员对机器的掌控能力更强了。机器是死的,软件是活的。拿现在的例子来说。对象这个数据类型设计容易,还是原来的只有int ,double.。。。设计容易?你可以很容易掌控int 在内存几个字节,在那.那,一个对象呢?用对象这个数据类型来处理对象容易,还是1+1 =2 容易?接触底层的意思不是说。一天到晚的敲汇编。就是接触底层了。如果,那一天,计算机硬件不用二进制了呢?程序不用键盘写了呢?cpu不用电平或脉冲信号了呢?是不是我们所学的就没有用了?计算机也只是工具而已。






posted @ 2009-06-17 12:12 发条橙子 阅读(2197) 评论(19) 编辑