用新浪微博登录

只需一步,快速搞定

 找回密码
 立即注册

用新浪微博登录

只需一步,快速搞定

查看: 2506|回复: 5
打印 上一主题 下一主题

新手编程导论(九)

[复制链接]

该用户从未签到

667

主题

2111

帖子

5570

积分

LV 11.会员

MS爱好者!!!!

积分
5570

社区居民偶尔光临工蜂最爱沙发在线达人社区平民做个有钱人略有小成常驻会员忠实会员

跳转到指定楼层
楼主
发表于 2011-10-22 18:26:29 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式 |          
第8章 抽象之设计和领域逻辑
8.1 大设计
范意上的设计是广泛的,不仅限于计算机的,也不限于软工抽象,软件的设计哲学是可以用来解释一切的,因为它是真正的哲学,而真正的哲学并不仅适用软件开发(软工和计算机是二个完全不同的抽象,虽然没有人提出过计算机抽象到底是什么,软工抽象到底里面有哪些抽象存在,我们仅能站在某个或某些维度上给出一个描述性的概念而不是有限集,这也就够了,如果能站在一个大全的维度上说明到软工的全部抽象,虽然这是不可能的,但我们还是给得出的这个结果取个名字,叫范式,范式在意义上是大全而的抽象,然而人类的范式总表现为某些维度上的产物(只是我们在一本无论多么长的书里都写不完而已,如果有那么一种生命力和那么一本书存在,我们也坚信任何一个道理都不可能写完)。
设计并不仅仅面向于创新,有时是形式的重组,而不是内容的创新,应用形式的改观,设计出的产品,要源端是面向人的,因此要提供足够简单的使用和访问形式,在目标端是要达到足够丰富的应用逻辑(比如XML统一文档交换,但可由node,root这些形式导致足够丰富的深层功能,深层这里是指上层),因此越复杂越大而全越好(但是如果没有足够人力,我们应考虑设计出别人想不到的商机),应用形式和应用逻辑作为设计中应主要考虑到的问题,有很多人想到用一种形式来统一既存的东西,比如在jvm搭建Windows和其它一切软件,然而这是多么无聊的事啊?
明白了原理跟实践,细节与思想之间的关系,我们就会有选择性地去学习细节,,一定要研究细节,因为细节是重要的,你得用这种技术细节实现某个东西,不一定要研究细节,还是因为你要不要用到它,然而思想是重要的,明白了这个思想,你就明白有些知识是技术细节,有些思想却是根本,当然,没到考虑思想的水平,技术细节永远也还是重要的,不要企图去钻研一切细节,因为很无聊,除非你是在满足自己,一生学习细节,这又是多少无聊的事
明白了抽象,我们明白一个东西,应做个明确这个东西的抽象所属,即它所在的人类范式.
在设计软件时,我们主要用UML工具,但是这东西是静态语言用的

8.1 什么是设计
我们必须明白,设计这个词是一个表示人类活动的词,比如有建筑设计,艺术设计,,而程序设计只是一种。它可以解读为用程序设计语言提供的基本语法和高级语法,以及独立于程序设计语言但跟语言有关的那些手段(比如Corba,设计模式),来进行对方案域到目标应用域的一个逻辑映射(一种能产生最终产品但并不以产生最终产品为终止条件的人类活动过程,它包括选择语言的考虑,应用设计,模型抽象,维护各个部分的整个综合过程,也即设计等于软工)。故涉及到不止程序设计语言一个方面。下面我们将就这些方面一一进行解说。
因为程序设计是人的活动,所以它首先是一种对人类活动本身的设计。设计模型的目的正是在于规范程序设计的各个过程。使开发过程可控化,这就是程序设计模型要解决的问题(XP编程啊,瀑布模型啊)。
再次,设计需要对代码逻辑的控制,因为是由人来写代码而且也是由人来维护代码的,所以选择一种能切合人类层次又靠近语言支持的方式是必要的,过程式使人类能以发号施令的方式写计算机逻辑。面向对象单方面站在人类抽象的角度将计算机逻辑封装为一个一个的对象。并不需要考虑对计算机的实现过程(当然在每个class内部也可以有过程式),相对面向过程来说,面向对象是更抽象的。当然,这些都是大的代码逻辑控制手段,和高级语法机制,小的可以小到“流程控制,循环”这样的课题。
在语言选择方面,如果是通用编译型语言,因为类型是语言表达客观事物或客观逻辑事物的机制(使之成为语言的数据使语言成为一个DSL),所以代码逻辑的抽象首先是一种类型抽象的过程,C++中有OC(面向类化),模板范型这样的对类型进行抽象的机制,如果是通用脚本解释型语言,它将类型动态化,这样就能更好地表达领域词汇,DSL抽象。相比通用编译型语言来说,这二者都存在设计的抽象和实现(因为都存在类型),但显然脚本语言更靠近实现,,这二者的唯一的区别在于,编译型语言用了严格类型的抽象来表达DSL逻辑,而脚本型语言采用了活动类型的方式来抽象DSL逻辑。
程序设计还是一种对应用的抽象过程,因为任何软件的编制在于解决目标问题,面向一个目标领域,无论是架构师还是程序员方面,都需要面对程序设计要解决的问题和领域进行抽象,,提供一个科学组织的抽象框架以更好利用复用或更下一步的抽象,软件产品的用户有三,最终用户,最终脚本用户,程序员用户。其中,2,3是能有机会进入到程序逻辑内部的用户。如果是写代码的那个人来维护程序,实际上就是下一步的抽象,下一步的抽象和复用不过一个词说法的二个方面。
然而,虽然抽象过程并不需要预先考虑软件复用能力,但是科学组织了的,松偶合,紧实现的抽象过程显然可以为整个设计中的所有阶段带来好处。
综上所述,无论如何,设计的最终目的是使软件产品具有更强大的生命力,对其内要做到科学抽象和组织,对其外要做到利用复用,易于重构。
什么是重构呢,重构并非重写,重构是面向为已有系统增加新功能或完善已有功能的需求下,在原有系统已经存在的情况下,变更其设计方式(注意设计这个词),修补式地加进一些新的设计元素或去掉一些旧的设计元素(故往往用到设计模式,因为设计模式可以很好解决此类问题,所以在介绍设计模式的一本书里,总是会有这样的问题和需求发生在先,然而才导出一个个的设计模式),重构往往是解决代码维护问题的一个重要方面,当然,正如上面提到的,软件产品在最初被设计和产生时也要考虑到一个科学设计的过程,这样才有利于后来产生新需求和新问题的重构过程。
这里首先有一个实现与抽象的区别所在(人们往往把设计和实现对立而模糊了对实现的理解,其实,抽象和实现才是一对对立体,找准了这个才能正确地理解实现,就像对脚本语言的理解,如果你一开始知道它是系统编程语言的对立体,那么你就不会产生脚本语言是不是一定是解释语言这样的疑问,因为它一开始是非系统编程语言,其使用解释或编译是它第二个要解决的问题所在),但设计和实现无法分界,这首先是因为语言没能为它们提供一个有效区分的机制(Delphi 的单元文件pas中有接口和实现这样的关键字,C++默认将h文件和cpp文件分开,然而这都不是严格的抽象与实现分开的机制和行之有效的方法,这根本是因为这二者根本就是具体问题具体分析的事,无法在形式上进行区别,但提供h,cpp这样的机制也并非错误无效的方法---请参照选读中的“形式主义”),OC可用于设计中的抽象,也可以用于在先前设计抽象基础上进行的下一层抽象(实现)。
那么是不是可以将抽象分层呢,一部分是DSL类,一部分是字串这样的计算机实现类,将前部分看成设计,后一部分看成实现,,但实际上这样也是不行的。因为无法精确给每一种这样的抽象分层,而且即使分层,也是有很大局限性的。
比如在库的设计和利用库进行实现这二个过程中,都可以写函数(以过程范式编码),显然地,库的设计是高度面向复用的,而实现是一种函数调用,然而为什么库的设计中的函数才是设计,而实现中包括了函数调用的函数体就不是设计呢?他们同样是有函数原型的接口的啊。这就说明了语言本身并不能严格化这个区别。能严格化的就是具体问题中的具体区别方法。
这就说明,存在接口的地方就存在设计(因为可供再被可复用,而设计的一个意思就是为二层用户提供复用逻辑考虑的过程,比如接口,我们在比较大的层次举个例子吧,比如用C实现的工具库和抽象库)。我们应该严格在源程序中标志出哪些接口是作为最终工具使用的接口,哪些是能再供抽象使用的接口。
因为抽象最终要形成源程序,要在源程序中反应出来,而源程序是由自己或别人查看的,所以说抽象对设计是至关重要的,因为抽象是择其事物一方面或某维度进行抽象,所以设计不必大而全,那些“理想”靠近现实事物模型的抽象反而不是最好的抽象(比如严格用OO设计一个游戏的图形世界,把每一个树叶都封装为对象,还把导演,这样的概念抽象出来),因为这样的抽象往往太大了,或不必要带了太多错误的臆想。抽象只能是现实事物的一个或某些方面的变形。甚至带有逻辑模型抽象,而不全是实体抽象。

8.2 编程能力,代码控制能力,复用与接口,轮子发明与使用
你应该知道,真正的编程能力不是使用轮子的能力(即不是复用能力),而是将现实问题用编程语言来解决的能力(这就需要你具备设计能力,即很强的代码控制能力,能把现实问题抽象为代码而不仅仅满足于使用别人现成的库)虽然复用能力与设计能力都貌似语言能力,从语言的眼光来看,复用能力是属于设计能力的,但实际上他们还有很大不同的要求有不同的语言能力,有些人具备在不懂STL原理的基础上使用STL的能力,但它们就是不能用STL来实现一个STL。。这就是上述二种能力的根本区别的证明。
(往往我们把复用能力当成编码实践能力,把设计能力当成广义的编程能力)。
有时难以理解的绝对不是代码本身(语言的语法和语句有限),难理解的代码是其中体现出来的设计元素和应用元素..也就是所谓的算法和设计,,有时是设计模式,有时是现实问题模型的相关抽象(其实算法和数据结构也是计算机开发中历史形成的抽象,,即某个“现实问题”,但一般将它们独立出来)。
要知道,程序的编制者跟程序的使用者有时是不一样的,这集中体现在C++的模板的复用上,C++的模板是用来书写高抽象库的好工具,然而类型的泛化意味着通用,因为像STL一样的东西意味着它能并适合于提供某种抽象上的规范(接口),,我们使用STL就不必处处屈就通用了。我们只需要“使用”,(我们实际上也不必提供太多的轮子方面的东西因为我们正是使用轮子,因此只需开发出使用这些规范的实践,实例),就跟游戏引擎和游戏的区别一样(面向通用的库或面向实现特化的库都有)。。因此这二者涉及到的模板编程技术是有高有低的。会复用并不一定会写。当然,理解stl库的实现过程中使用到的模板理念显然可以帮助我们复用这些规范(接口)进行实例化(使用接口)的过程。
实际上,数据结构,设计模式,现实问题这三个东西跟任何一门程序设计语言都没有关系,因为任何一门冯氏模型决定下的开发语言都满足这些东西,,而且计算机界的一切软硬基础都是算法加数据结构的集中体现(再往人类的软工一点,就有设计模式了),我们编程往往涉及三个能力
1, 语言语法的,比如流程控制,数组,IO,字串,
2, 数据结构和算法的。
3, 设计模式的
4, 现实问题的。
用某种语言来编程,体现的代码控制能力只有1是必要的,然而具备了1并不意味着你就能定出某种数据结构,或设计模式,,或抽象出某个现实问题,,因为那根本是另一些领域需要你掌握的东西(而不仅仅是语言能力)。所以你汇编码能力并不意味你有编程解决现实问题的能力。你有编码能力所以一定有复用能力,但你不一定有实现这些轮子的能力(以及阅读这些代码时认识到这些轮子设计的能力,这样你阅读代码的能力和眼光也会受到限制,只限于简单的复用能力,因为复用能力只要求你拥有接口复用能力,,真正的逻辑不只是接口间的简单复用,而是接口间复合形成什么样的抽象以及如何逻辑上形成这样抽象,这就不仅仅是接口复合作用了)。
所以真正的编程能力在于2,3,4,加1编码能力,,所组成的综合编程能力;

8.3 OO,模板,设计模式与设计
设计即逻辑的逻辑,而且是面向人的控制逻辑的抽象即设计的第四种意思是让抽象以人.需要的方式进行组织,即人影响抽象的能力,
实际上设计无所不在,从你写第一行控制流程代码开始,你就在设计了,只不过是隐式的,机器并不会流程控制,是语言赋于你能以人类看得明白的流程设计逻辑向机器发令的。如果说流程控制设计是细小的,那么OO是一种显式化的设计,当你用OO来写代码时你就在设计,虽然你写的是实现,设计与实现间无明显分界,,,你照样是在设计,因为你用到了OO的三重思想,继承,泛化,封装,,这就是控制逻辑的逻辑,,是设计因素。。一句话,设计无所在不在,即使在C那样的紧实现的语言中也存在设计。。
所以存在三种设计方式在C++中,OO,模板和LOKI。
模板的能力在于抽象类型,所以设计的一种意思是类型控制和抽象能力(动态类型更侧重实现谈化设计所以它首先去掉强类型,而提供弱类型或无类型或动态类型),模板只能只做类型控制,然而LOKI可以做到控制逻辑级。这就是单纯的模板用于设计和LOKI用于设计时的区别。。
在抽象类型作为设计手段的方法上,OO和模板是差不多的,然而不同的是模板是“泛化”类型OO是纯粹只用“类型化”来实现设计(对即逻辑的抽象逻辑,我们知道,实现中也离不开设计,设计库的设计就更离不开设计了),,所以OO的设计手段不足,而设计模式是一种新的设计理念,语言并不直接支持,,C++用STL作为语言的数据抽象,,用LOKI作为语言的设计能力(OO,模板相比来说是小规模的设计手段)。
注意,OO的类型化绝对不能说成对象化,OO定义成面对对象是极其错误的译法,,OO是用于设计的,,所以O这个字眼只能是“类型化”的“类型”,而不能译成对象,,因为对象是实现里面,不是OO设计的原义所在。
设计的唯一特征是站在高阶的泛,这就成为区别实现与设计的根本,而不是大小问题的逻辑包含互饰关系(因为这样的话,设计与实现只有模糊分界),而泛成为区别这二者清楚的界限。
为什么template仅有type as type一项就足于跟OO匹敌呢,因为类型就是语言的一切,提供关于类型的机制就是一门语言的设计能力的一切。。
动态类型语言也有类型,,不过它的类型不需要一个设计期的type来确定指定而已,,其本质也是某类型的某个value.
而动态类型没有type,所以没有对数据的泛化,也即无法抽象数据,也就无法抽象代码和控制(设计里的)逻辑,所以无法设计(设计的一种意思是类型控制和抽象能力,,动态类型语言不存在对类型的抽象,所以至少这种意思的设计在动态类型语言是不存在,因为动态类型是DSL语言不是通用语言无需考虑类型及类型抽象上的设计)。它只能在线控制逻辑的运作。
所以动态类型语言是实现语言。。应该称动态类型语言为在线类型语言。模板是离线类型语言。
我们知道设计是复用导向的,最终用户(领域内用户,脚本用户)和程序员用户(本语言内的复用,语言非通用的)是二级不同的面向级,前者用动态实现语言即脚本语言,而后者用静态语言为宜。
解决可复用银弹问题的根本可以改造开发模型,,也可以将设计逻辑尽量多地沿伸到实现,而且是脚本用户级。因为此时没有编程工作,只有配置工作,银弹问题根本不存在

8.4 设计能力和程序员能力模型
设计能力第一个是结合了数据抽象和代码抽象以及语言映射能力到现实问题的解法的能力,第二个是构架架构的能力(提出一种规范一种抽象模型,就像Java规范和七层模型一样,相比第一种设计能力来说,这是高级的能力)。
设计还有一个方面是面向复用的工程设计。就是开发库的设计意义所在,
理解设计对理解C++新思维那样书里的观点有效。
冯氏模型的局限和优点同时体现在数据结构和设计模式上,它使人无论如何都要最小在这二种子抽象上工作,,优点是,统一了开发抽象,,这也使软件逻辑变得统一。这对软工是尤为重要的。
程序员的能力模型,语言30%,数据结构50%,对现实事实的抽象理解能力10%,,设计模式能力10%。。 ==100%。
真正的编程能力是设计能力!!对思维模型的学习!!而非对细节,对平台编程!!事物的OO解只是事物解空间中的一种而已!!

8.4 自上而下设计和自下而上设计
基本概念
抽象在软件开发中的重要性是不言而喻的。如果一个系统有了正确的抽象,那么这个系统就更容易理解,更容易维护,开发起来也更为高效,最为重要的是也更容易把事情作对。Grady Booch甚至认为抽象是应对软件复杂性最为有效的手段。在面临一个复杂的系统时,往往只要再提升一层抽象层次(当然要是正确的抽象),那么该系统就会立即变得清晰、简单,理解、开发、维护起来也更为容易一些。不过,值得注意的是,虽然有了一个正确的抽象后,可以大大降低理解、开发和维护的难度,但是要想得到一个正确、合适的抽象却是非常困难的。
提起代码自动生成,可能大多数人立即会想到这样一种情形:只要获取了系统的需求,那么就会自动地从这些需求生成系统的代码。这种想法固然很好,但是在目前的科学发展水平(这种技术不单是软件技术的问题,它还和人思维的生物基础有密切关系)下却还无法实现。需求和能够自动转化为代码的精确的形式化规范之间有一个巨大的鸿沟,目前这项转换工作还只能由人来独立地完成。因此,这种技术在目前来说只能是一个神话。我们在本文中所指的代码自动生成是针对比较局限的领域而言的,即需求已经被正确的理解并由人转化为解决方案领域中的抽象模型。代码自动生成并不是为了替代人去完成系统的软件开发的,它只是一种支援抽象的工具而已。
回复

使用道具 举报

该用户从未签到

667

主题

2111

帖子

5570

积分

LV 11.会员

MS爱好者!!!!

积分
5570

社区居民偶尔光临工蜂最爱沙发在线达人社区平民做个有钱人略有小成常驻会员忠实会员

沙发
 楼主| 发表于 2011-10-22 18:30:01 | 只看该作者
领域特定语言(DSL)
其实,大家在每天的软件开发中都在不经意的使用着这项工具。当我们在使用面向对象语言进行软件开发时,其实我们是在一种抽象的层面上进行工作。有了这层抽象,我们所编写的软件就会更有表现力,更为简洁。比如:当我们写下下面的代码行时:class Cat extends Animal。我们想表达的是Cat is a Animal,面向对象语言为我们提供了强有力的支持。而这个抽象的实现细节则由编译器来完成,我们无需关心。这样我们就能够在一个更高、更直接、更易于理解抽象的层面进行开发和交流,同时也大大降低了出现错误的机会。当我们使用支持泛型或者AOP的语言进行软件开发时,其实我们是在另外一种抽象层面上工作。比如:当我们写下如下代码时:
template
T Add(T, T)
我们想表达的是求两个类型为T的变量之和,而不管T到底是什么具体类型。想想看,如果语言不支持这种表达规范,我们要写多少个雷同的Add方法。有了这种表达规范,我们就可以直接、简洁地表达出我们的意图,而具体的转换工作就有编译器代劳了。还有,如果我们在支持AOP的环境中进行软件开发,那么我们只要使用该环境提供的AOP语言规范定义出我们希望的横切关系(其实就是一种抽象),剩余代码的编写和插入工作就由该环境帮我们自动完成了。虽然编译器或者开发环境在底层生成的实际上也是大量重复的代码,但是这些代码的抽象规范却只有一份,而人们开发、维护、沟通所基于的正是这唯一的一份抽象规范,底层的重复实现细节对开发者来说是不可见的,并且是自动和抽象规范保持一致的。可以说,在开发者的头脑中,是没有重复的。从而有力的支持了“once and only once”和DRY原则。试想,如果语言种没有提供这种描述规范,那么我们要编写多少晦涩、难懂、重复的代码才能描绘我们想要表达的概念。
上面提到的抽象是一些比较通用的机制,因此一般都是语言内置支持的。也正是其通用性使其有效性范围受到了限制。一般来说,上面的一些抽象机制是仅仅针对开发者群体而言的,并且使用这些抽象机制进行的表达也是由编译器来自动生成底层执行代码的。但是,还有一种抽象表达更为重要,它的作用是在开发者和客户之间进行沟通、交流。说它重要是因为它和所要开发的系统是否能够真正满足客户需要密切相关。这种抽象表达更贴近具体的问题领域,因此也称为领域相关语言(Domain-Specific Language(DSL))。比如,如果我们开发的是一个金融系统,那么如果我们能够使用一套金融术语及其关系来刻画金融领域中的一些业务逻辑,那么不但表达起来会简洁、直接得多,更重要的是客户也更容易理解,和客户沟通起来也更为容易。再如,如果我们要开发一个科学计算系统,那么如果我们拥有了一套描述科学计算领域的词汇,那么在表达该系统时不但会容易、自然很多,而且也更加高效。有了这套DSL之后,剩下的工作就是要自己实现一个编译/解释器,来把DSL自动生成为目标语言。由于这个DSL一般都局限于某个特定领域,因此其编译/解释器实现起来也不会有多大困难。
敏锐的读者一定会发现,我们在前面列举的支持面向对象(OO)、泛型(GP)或者面向方面(AOP)的语言,其实也是DSL的一种。只不过它们所针对的是更为通用的,和软件要面临的实际问题领域无关的领域。它们的作用是为了提高一些通用问题描述的抽象层次,并且也为构建更贴近问题领域的抽象提供了基础。
自上而下 还是 自下而上?
写到这里我突然想起一个非常有趣的问题,那就是大家常常争论的自上而下开发和自下而上开发。一般认为,自上而下的开发方法更具目的性一些,也更为自然一些。其实自上而下的方法是有很大风险的,一是往往很多预先的设想很可能本身就是错的,一是这些预先设想落实到底层时要么无法实现,要么无法很好地适配。其结果就是生成一个具有大量冗余、丑陋粘合层代码的系统。而采用DSL思想的自下而上方法则具有很多你可能没有想到的好处。你可以先实现一些DSL中的单个单词,然后再实现一些更大的单元,并试着把这些元素组合为更大的领域逻辑,按照这种方法实现起来的系统往往更加简洁、清楚、干净,甚至更加易于重用。一般来说,如果你想采用DSL的开发方式,动态语言大有用武之地(Python、Ruby都是不错的选择,在www.martinfowler.com/bliki中,Martin Fowler对动态语言和DSL的关系进行了深入、有趣的描述)。
自下而上的做法实际上是在改变、扩充开发语言,使其适合于所面临的问题领域。当你进行软件系统的开发时,你不仅仅只是把你所构思的程序直接映射到实现语言,同时你还不断对语言进行增强,使其更加贴近你所构思的程序,并且表达起来能够更加简单、更加直接。比如:你会想语言中如果有了这个操作符,表达起来就更加清楚、简洁了,那么你就去构建它。这样,语言和程序就会一同演化,直到二者能够形成一种完美的匹配关系。最后,你的程序看起来就会像是用专门为它设计的语言开发的。而当语言和程序能够很好地相互适合时,所编写的代码也就会更清晰、更少、更有效。
值得注意的是,自下而上设计相对于自上而下设计来说,并不意味着用不同的顺序来编写同样的程序。当采用自下而上设计时,常常会得到一个和自上而下设计不同的程序。所得到的不会是一个单一的单片机(monolithic)程序,而是一个具有更多抽象操作符的更“大”的语言和一个用该语言编写的更“小”的程序。此外,这个语言的抽象操作符也很容易在其他的类似的程序中得以重用,所编写程序也更加易读、更加易于理解。
还有一点值得提出,那就是自下而上的开发方法可以尽快地得到来自代码的反馈,可以及时进行重构。我们大家可能都已经知道,设计模式一般是重构的目标,这里我想特别指出的是:DSL往往也是很好的重构目标。
抽象、库和DSL
C++之父Bjarne Stroustrup经常强调的“用库来扩充语言,用库来进行思考”( http://www.artima.com/intv/elegance.html有近期对Bjarne Stroustrup的采访,他再次强调了这个问题),其实就是在强调DSL以及自下向上开发的重要性。库就是DSL的一种形式,Bjarne Stroustrup所列举的科学计算库的例子就是科学计算领域的DSL。构建库的过程其实就是在朝着更加贴近问题领域抽象的方向迈进。明白了这一点,我们就不难理解Bjarne Stroustrup一直强调的泛型在构建一个优雅、高效库的方面的重要性了,因为泛型为构建这种抽象提供了一个坚实的基础。
不仅C++如此,其他一些语言(比如:Java)也拥有众多的库。这些库在我们进行软件开发时,为我们提供了强大的支持。不过,这些库往往都只实现了它所针对领域的一些通用基础性的问题。因此,在某些特定问题上,可能无法直接地使用这些库来进行表达。此时,你就应该考虑建立一个特定于自己问题的特定库了。

结论
作为开发者的我们,该如何做呢?正如本文开始所说的,抽象固然很好,但是要找出适合于自己手边问题的抽象是一件很困难的事。它应该是一个不断从代码编写中得到反馈,然后再修正,接着再编写代码的循环反馈的过程,这也是我为何认为自下而上开发更为有效的原因。我们不应该局限于仅仅会使用某一种工具,某一种开发环境,而应该多想想这些工具、开发环境背后蕴涵的思想。我们应该注重于培养自己发掘抽象的能力,这方面能力的培养既需要很好的和客户沟通的能力,同时还需要有坚实、高超的软件能力。
此外,近期热的不能再热的技术MDA,其核心思想其实就是DSL,不过我对于其试图使用一种语言来刻画所有领域模型的做法并不看好。与其使用它,倒不如逐步演化出一个特定于自己问题领域的Mini DSL和一个DSL编译/解释器,并基于这个DSL来进行开发,这样或许更为直接一些,更为轻便一些,更为清晰一些、更为有效一些,更加具有针对性一些,也更为经济一些

8.5 大中型软件和复用与逻辑达成
我们知道一个库的发布总是带一个samples目录,然而那是小例子,,大中型程序是怎么开发出来的呢,,你该如何着手写一个大型的程序呢?一般来说是找轮子和写实现。
如果开发中存在造轮子的工作,那么很多逻辑都在这里面,,就拿开发游戏引擎来说吧,引擎部分总是要考虑进很多逻辑,有时是复用别人的库,有时是很多预考虑的逻辑,有时是设计模式方面的逻辑,考虑OGRE就知道了。
就复用逻辑(比如一个使用了OGRE的游戏的实际代码)来说,,它往往是OGRE中的samples演示小程序,如果是一个用yake写成的大型游戏,那么起码可能还存在造其它轮子的过程(比如你还用到数据结构,而不想用STL,那么你需要自己设计—这是在造轮子了,或直接复用GLIBC),,逻辑间的大量复合,和与其它维度上逻辑的结合(比如不仅是图形方面的,还有网络方面的代码等),就会构成一个大型软件了。
然而幸好有一个YAKE的程序考虑进了几乎你能用到的很多库,,当然如果你想用其它的库替代,或者加进其它的库逻辑,或者自己在复用中会想到自己开发自己的库逻辑,也是完全可行的。但是我们一般不改造YAKE(因为如果它不提供SRC我们就无法改造,其它很多库都是这样的)。而是拔插使用其内组件库。。
所以大中型软件的形成,,有的是库逻辑和实现逻辑,即设计能力,,有的是复用逻辑。。即编码能力。。因此那些说程序员是简单的复用员的人是可笑的,,因为一个程序员在编程中总会涉及到设计能力(即那么比如设计一种数据结构库的能力)。。。
所以什么是设计能力就出来了,它泛指一种真正的编程能力,即将现实问题映射为语言逻辑的能力,(找轮子是作设计的一个步骤,),那么设计能力要求你有什么样的能力呢,,当然,现实问题的模型你是要清楚的,而且语言逻辑也是你要清楚的,复用的库你要从语言的观点去搞清每一个接口的真正意思(无论用什么语言,,数据结构,设计模式和语言本身这三者的逻辑是不变的,,其它的就是具体问题映射到语言的能力了),在整个设计过程中(映射中),,你必须清楚每一个步骤,,因为软件设计真的不像拼零件(强烈鄙视这种用在小打小闹模式上的接口拼起来的软件上),,大型的软件接口太多,,你必须熟悉每一个功能模块,,和预见每一个功能接口。。这种细节的无限性决定了软件的复杂性和设计实现时的清楚性,,否则就是编译不过,不成软件。。那意味着项目失败
架构师的能力就是设计能力,,,程序员的能力就是编码能力(然而在每个小问题上每个小模块上也存在设计,所以程序员也是一个设计师,不过他不直接面对复杂的大系统而已)

8.6 通用设计与专门设计
像C++,C这样的语言都是被设计为通用的,要通用,因此往往基于某种靠近计算机底层的离散形式,而DSL实现特定领域事情的语言,(相对C++,C来说)不强大,不深入底层,不能控制计算机干任何通用事情,因此往往基于高层模型,,
因此,C++,C这样的语言必须要涉及到汇编原理里面的东东,而DSL可以以任何高层的形式被体现,比如不需要编译的UML图都是,POWERPOINT代码都是DSL,根本不需要编译器这样的图灵完备装备
这就是脚本语言比不上编译语言这样的语言对计算机编程方面的功能强大.因为脚本语言的虚拟机往往是高级机器,根本不像我们的硬件机器那么底级,图灵模型对应我们的硬件机器和架构,而虚拟机往往跟硬件架构差别过大,因此脚本语言和系统语言是为二个不同的机器设计他们干的事,,,,而一般虚拟机作了高级逻辑,比如GC等,而X86不可能在硬件架构级就用了GC,如果CPU芯片可以用硬件加速的方法直接支持语言的垃圾回收机制就好了,这要求语言跟CPU一一对应,,而且OS也提供了大局方面的GC(并不仅仅针对某个语言,比如WINDOWS的操作系统级的资源释放)
C跟C++到底有什么区别呢,我觉得第一个加号是一种理念上的叠加,第二个加才是语言要素上的改变,C跟计算机离散和底层接近,解决的问题是如何实现,专注于计算机对问题的实现,因为C语言就是机器的观点
C++跟人接近,解决的是如何更好地复用,关注于问题本身,脱离了实现逻辑如平台逻辑,人们如何更好地写代码服务工业化,OO就是人类的观点,C是实现域扩展,C++则完成了一个从实现域到问题域的一个维度变换而已,
C和C++解决问题时,,站在二个根本不同的维度而已.

8.7 具象与抽象
抽象源于一个简单的事实,把事物从逻辑上分开,这样就会解偶它们之间的联系。
抽象要适中,不能抽象得太像了,为程序员复用的相对低阶接口变成了为脚本程序员的高阶接口。
复用由二次开发的程序员决定(这个事实决定了你将向它们提供什么大层次上的功能比如ogre的复合模式,大的逻辑或小的接口),所以复用是程序员面向的,纯dp的设计方案要求二次开发的程序员也要了解DP。
对api的调用在此设计的最下层,由二次复用者提供。(即数据由它们提供,代码逻辑由我设计)
其实你可以将复用抬高到场景这样的层次(这就是领域逻辑,当然设计也可不深入到这么高的境界,这就是代码模式,设计模式和现实模式之间的整合设计所在),这是由复用面向决定的即需求决定的。而不仅仅是单方面的设计。
首先来对游戏进行划分。

8.7 架构与应用
因为功能是逻辑叠成的产物,越到底层,它对高层的逻辑依赖应尽量少,因为高层往往是应用逻辑,而底层往往是功能逻辑和业务逻辑(高层和低层通过一个隔离层意义上的逻辑来达到功能上的完成但又不致于增加这二个层次上的复杂性,使得在这二个层上的工作可以分别完成),因此底层核心架构应尽量简小精短(比如linux的core,但其中的应用可以无边无际),但是简小的同时却要提供最大程序上,或全部程序上的可扩展性,这样在完成了整个core后,后面的功能慢慢趋向应用时,就可以不致于改变到core,也即这个core可适应一切小,中,型的平台,不必做重复工作.或者即使需要被改变时,涉及到这个core的修改量也尽量小.
对底层的逻辑应尽量提供迂回用的接口,迂回即抽象,增加了迂回即增加了另种一种维度上的抽象可能性,而维度永远无穷无尽,因此抽象以任何一种姿态被创建都可以是一种新的抽象,我们用代码的形式表达我们所需要的功能,即用计算机能处理代码的本质维度摸拟人的思想功用的维度,这就是"原语设计"的概念所在
逻辑的抽象粒度永远有它关于具体的复杂性,我们不能定义一个具体的逻辑块,指明它为core或者还是应属于core,但是正如这句话说过的,问题有它自身的复杂性,因此我们应具体问题具体分析
这是哲学所指明的,哲学不是人的东西(虽然它是人发现的),?
底层完成了(底层往往是一些首先要解决的逻辑或者在设计意义上具有优先产生其它事物的概念体),其上的应用可以无边无际,但应用应尽量追求形式简单,一个合理的架构和其上发展的应用对于人来说应越来越简单,,,这才是合理的,我们不能掌握的复杂度应尽量隔离.因此我选用没有历史复杂性的open jdk,gnu c,拥护开源的linux
回复 支持 反对

使用道具 举报

该用户从未签到

667

主题

2111

帖子

5570

积分

LV 11.会员

MS爱好者!!!!

积分
5570

社区居民偶尔光临工蜂最爱沙发在线达人社区平民做个有钱人略有小成常驻会员忠实会员

板凳
 楼主| 发表于 2011-10-22 18:32:10 | 只看该作者
8.8 应用与设计
应用越来越接近人了,比如web2.0,3.0的出现,这是指软件产品的应用,实际上在软件被作为产品被产生出来时也作了靠近人的调整,编程领域的三个东西,问题域,方案域,人都在相互影响,这种影响产生了一些技术,导致了一些编程的变革,并最终与人们的观念结合,比如OO,比如设计模式,这也将导致架构变成软件的功能性"实现"要考虑的,在某个维度上加深了复杂度,然而却在另外一些维度上提供了简单的形式和更有效的应用
互联网的最初灵感来自对学术自由和开放的向往,而现在它已成为由企业和运营商控制的商业平台。企业应用与网络的发展密不可分,这二者相互发展,成为影响软件工程界的二大主力
多维这个字眼本身就提倡从多个方面(可见多维就是多方面,当我站在某个维度为我自己说话时,我将同时失去另外其它的维度)
某些东西越来越统一和规范了,这加大了学习的门槛,比如xml出现,就统一了文档交互的格式,并导致了很多逻辑知识,产生了一些新的逻辑,需要被学习,但这是合理的,因为形式更加简单了统一了,并改变了一些应用的形式,比如软件分发delopy的统一形式等,
另外一趋势,应用越来越分布了和趋向web,这实际上是很多年前某些大公司的战略,总有那么一群人(有些人研究应用形成架构,有些人研究编程低层形成架构和思想),先知先觉地认识到一些东西,比如.net的出现,网上的资源服务器越来越变成一般应用服务器,富客户端的flex,silverlight等等,只是它们是慢慢被民间所识所学习.
一切技术都是面向被应用,因此人无论如何都是主导.将反过来最终影响技术的被利用形式而隐藏了低层实现,一些离最终应用跨度太大的低层实现不必知道其原理,靠近人的一端要提供尽量简单的形式,比如xml,比如oo,面向机器的一端永远有它的实现.

8.9 与软件有关的哲学 联系
范意上的设计是广泛的,不仅限于计算机的,也不限于软工抽象(软工和计算机是二个完全不同的抽象,虽然没有人提出过计算机抽象到底是什么,软工抽象到底里面有哪些抽象存在,我们仅能站在某个或某些维度上给出一个描述性的概念而不是有限集,如果能站在一个大全的维度上说明到软工的全部抽象,虽然这是不可能的,但我们还是给得出的这个结果取个名字,叫范式,范式总是某些维度上的产物而不是大全的维度产生,学习计算机的很多哲学思维可以解决其它域的哲学),设计并不仅仅面向于创新,有时是形式的重组,而不是内容的创新,应用形式的改观,设计出的产品,要源端是面向人的,因此要提供足够简单的使用和访问形式,在目标端是要达到足够丰富的应用逻辑(比如XML统一文档交换,但可由node,root这些形式导致足够丰富的深层功能,深层这里是指上层),因此越复杂越大而全越好(但是如果没有足够人力,我们应考虑设计出别人想不到的商机),应用形式和应用逻辑作为设计中应主要考虑到的问题,
在设计软件时,我们主要用UML工具,但是这东西是静态语言用的
.
8.10 与软工有关的哲学 唯物主义
没有绝对科学的东西科学,维度给了我们一切答案,永远有更偏更僻的维度存在,因此拿唯物主义来说,如果它仅仅是表达那么一种"理"(它仅仅只需要说明这点),而没有宣扬它是正确的(实际上唯物论本身站在另外一些唯度上看就是片面的,而片面就是一定程序上的不正确),那么唯物论在这个维度上就算是做到科学了
唯物主义表明事物是不以人的意志为转移的,但是这里面的最基础的一个说法都不科学,什么是事物?哲学都没有从一种形式上去说明这个问题(就像字典内对"强间"应如何定义呢,法律范式内应如何对这个词进行界定呢)
当然我们讨论问题时并不需要把所有涉及到的逻辑都拿来解释一通,但是作为哲学维度的"事物"是应该被深入和专门界定的,而且"事物"这个字眼本身就是不严格的,而对象对象中的OO中的O,在计算机内存中,它是一个运行单元,在表达出的思想所指时,它又是不可形式化的.(在内存中总是那种形式,然而却可以产生不同的逻辑,这就是形式与逻辑的关系)
如果我们曾把生命中一段时间用于考虑这些哲学知识,那么我们就会与常人"分裂",正如写小说的人如果想说出与众不同的小说故事到达到无人深入之境,就必定要付出和得到一些灵魂,,产生排拆他人的想法,但是要知道,世俗的维度是我们生活所在的维度集,我们如果能认识到这种客观性,并尊重它,那么我们就不会分裂,
人只能是简单的,人只能是一个行者,在有生之年接受有限的知识,进行自认为或世俗认为正确的观点和作法并行动.而不可能永远是一个哲学者,没有人有足够的生命力来最终解释自己,得到的解释也只能在一个维度上成立而在另外一个维度显得可笑,,选择需要学习的人类知识去学,不要做一个大而全的学习者,在利用所得知识进行设计自己的应用时,应根据经济学所指,做别人没有的东西,才会显得有优势,你不必在任何一个方面都出色,但一定要在一个方面最出色(实践要达到"别无它,唯手熟而这样的境界"),这就是你的资源优势,可以转化为经济优势
逻辑
很多逻辑的意思都是不可言传的或者难以言传的,所以要看别人的代码时,除非别人在类文件形式的逻辑,组件形式逻辑的命名上直接让你明白很多信息,?否则你就不能有效地明白作者写这些程序时的想法,所以读人家的程序是难的,因此虽然你是面向源程序形式,但你其实是在求索别人的思想,更要命的是,你明白了这个类文件是什么意思,你还不能很有效地告诉别人这个类写了什么东西,,体现了什么逻辑,这是感觉是窒息的
软件的本质就是一种逻辑的叠成物,,某某牛人说过,一切问题和功能的达成都是逻辑!!软件的眼光里,一切皆逻辑,,在这个软工年代,最终的产品是多人合作代码的产物,因此相互之间能明白对方的源程序里到底能提供什么功能是重要的,,在以前的程序="数据结构+算法"的年代,程序员之间很容易在这方面获得沟通,而在现在这个软工年代,程序=数据结构+算法+架构"的年代,你还得明白人家程序逻辑是如何组织的,哪些是功能级的实现,哪些是架构级思想级的东西(这些东西为了以后的可扩展而存在,虽然一定维度上也可以称为功能级的实现),,
所以逻辑该如何命名,,我们只能满足于用特定的,固定的形式去描述性地表达它们,比如用类文件的名字,组件的名字,,设计模式的中间用词,等等.

8.11 真正的设计模式
我讨厌在讲授一些思想的时候提供大量的代码,因为我觉得接受思想的过程应该是一种快乐的如同阅读一本小说的过程,而不是花大量脑力研究某个细节的过程
而且这个世界,往往知识都只是相互转载,国内没有多少人会像那些欧美大师特立独立发明一些新的思想和论述,而我愿意写出我的一些思想与你们共享
每一个设计模式中都出现了一些角色,然而使用某个设计模式的个体(Client)不属于设计模式的某个角色,而只是使用这个设计模式的客户,,设计模式的目的就是为客户提供一个好的对现有对象的访问方法,设计模式是一种高于任何成码的思想和经验模式,因此不能直接用某个工具建模下来,在使用设计模式的过程中,,,总会产生一些新的抽象(而且有时不只一层抽象),,这些抽象隔离和解偶了客户(Client)与现有代码之间的关系,,,在它们中间作为中间抽象出现,而所谓抽象,,往往都以一个类的方式存在,(因为JAVA中一个类默认只承担一项责任或实现一个对象数据描述,因此一个抽象往往就是一个类,当然,抽象有时以方法的形式存在,某个设计模式也会以方法的形式存在,比如工厂“方法”模式,一般来说,设计模式都会形成某几个抽象类,对应该设计模式中的几个角色Actor),,
设计模式终归是一种迂回的方法(因为增加了抽象所以代码变得有点难于理解而且类层次增加这变得运行时变慢了一点),,然而这种方法成全了一种好处,,那就是:它部分或完全都解偶了使用者与现有代码之间(实际上设计模式可用在开发的各个阶段)的关系,,,这使得以后的对软件的维护工作和修改需求变得易管理和易实现,使软件不致于由于当初设计上的欠缺而变得难于修改而濒于死去.

8.12 设计模式与数据结构
对于设计模式,一般有下面几种理解: 重构时的设计模式。修补式的设计模式(client角色浓重) 大设计时的设计模式。全新式的设计模式(可以没有client角色在某一套模式中)
其实。不妨把设计模式称为抽象模式更好(我们知道抽象问题领域是设计中的一个重要步骤),,因为它更多地跟着眼于解决具体事物有关(就跟数据结构一样,不是跟具体语言有关,不是属于某种代码结构。)正如数据结构是择“数据”这个维度来抽象对现实事物映射到计算机解法的做法一样,设计模式是择“模式中的各个角色和关系”来映射对现实事物的模型,从而求得一个现实问题到计算机的解法一样(就目前所提出的一些设计模式来看,他们都是抽象现实事物模型的初步组件,一般有倾向于用面向对象语言来实现的趋势比如四人帮那书)。数据结构和设计模式都不会跟某种语言和语言机制有关,跟“面向对象”这样的代码抽象有本质上的差别,是实现模式,实现结构,而不是代码结构。着眼于如何解决和抽象问题,而不是如何抽象代码以进行更好能被复用这样的软工目的(当然,这二者是不分家的)。
我在《OO为什么不是银弹-过度抽象的利与弊》中谈到,OO并不是银弹,银弹是那些能统一人类思想,形成契约文化,经验的东西(比如我们写小说的那些套路),而不是简单的class这种面向复用的小技俩。 设计模式正是上述所谓“契约文化,经验”之类的初步体现(不可否认,我们所看到的设计模式跟具体现实事物还是有很大距离的),等到有一天,所有的问题都用设计模式来抽象的时候,成千上万的设计模式会被提出来。人们会倾向于用大大小小的设计模式来解决问题。那么设计模式就会到达它的颠峰。
然而对于程序员来说不利的是,数据结构已经被很好地映射到C语言中,而设计模式几乎在C语言中找不到它的影子。这正是它不成熟的地方。也许有一天会有一套“设计模式”专用语言出现。

8.12 设计模式之基础
研究数据结构我们目的从来不是那些底层的东西,,而是抽象的比如优先队列,多重集等。
四人帮的那本书是基于面向对象来谈设计模式的,因此它先提出一些面向对象的知识,比如一个类的class和type(interface)的区别,提倡对接口编程而不是对class定义即实现编程,提倡对象的组合而不是继承。而且它稍后提到的诸多设计模式中,都有对象,职责,请求,之说,这些都是OO里面的知识。。
不要小看了这里的对象组合它实际上是对接口编程的小化说法

8.12 真正的开闭原则
我们应该对扩展开放,的同时(注意这三个字),,,保证对修改的关闭(一个工程,应该在设计时就要考虑到将来修改的需要,而且要保证未来修改时能尽量降低工作量,对于一个真正的工程级的规模,人力管理工程应该尽量简化),
几乎没有接确过设计模式的人(除了完全外行和真正的编程高手外)看到这句话都会感到疑惑,而且会产生一个很普遍的疑问:不修改何来扩展?
高手与低手的差别就在于这里,高手往往看重的思想(即设计能力,,,识别架构和建立构架的能力,但是因为计算机能理解的设计只能是多范型设计,因此高手着重的这种思想往往也是受计算机实现的限制的设计),而低手考虑问题的第一切入点就是源码本身,因此产生“不修改源码何来功能扩展”的疑问也就很自然了
而其实,在高手的眼里,只要定义一些抽象,产生一些迂回就可以解决问题了,这些迂回(实际上就是产生一些高层逻辑,这些逻辑就是具体某个设计模式中的某些角色Acotr)可以让我们clients通过这些高层迂回避免直接接确到低层的实现(虽然我们client无论如何最终是要进入到具体实现的,但我们可以不直接而间接迂回地进入啊!!这些低层的实现就是现有代码了,是实现部分(可能是某个你要使用到的第三方库代码),我们经常要对实现部分修改,或者说对现有代码的修改,而要求要有最少的工作量,而一个没有定义抽象或者没有定义好合理抽象的工程要涉及到很多修改工作),而这,,真真实实就是解偶的意义所在。。
我们再来说这些逻辑,其实这些逻辑都可以称为中间逻辑,,然而这些逻辑的地位又是不同的,,有与具体实现接近的那一端的逻辑,,这些逻辑也是高层逻辑,,但是把与接近client使用者的逻辑看作为相对更高层的逻辑。。
说个故事吧!
《西游记》大闹天空时,要求当天庭大官,太白金星向玉皇献记说让孙悟空当弼马温,太白金星的智慧就体现了开闭原则,一方面,在孙悟空方面,太白向孙悟空说明玉皇已同意他上天(对扩展开放),,另一方面实际上只是给了他一个放马的差,实际上按天庭规则(系统原有结构)孙悟空是不能上天的(),然而迫于孙悟空的力量(修改的需要),太白只是稍微迂回了弯子(增加了一层抽象),就暂时平息了玉皇(玉皇本人不知道如何扩展这个需求,因为这是与天规相背的)和孙悟空二边.

8.13 真正的通米特原则
之所以不称通米特原则为通米特法则是因为在设计模式领域内实在不存在一个法则之说,
通米特法则也称为最小知识原则,一个事物对另外一个事物知道得越少,那么它本身就越安全(这可以联系武侠小说里小人物碰巧目睹了对杀手杀人的整个过程,那么这个小人物就会有杀身之祸,),
这里的安全是指对修改关闭
实际上无论对象组合还是继承都会造成类与类之间的引用,都会造成不可复用的问题,然而,相比继承来说,组合可以极大地减少这种复用的偶合程序,而继承压根就是不可分离的,因为本质上组合是一种Has-A的关系(组合对象与被组合对象),而继承关系是一种Is-A的关系(基类与继承类,或称父类与子类,注意这二个概念还是有点区别的,一般说到父与子关系时就是指父对象与子对象,而说到基类与继承类时往往描述类与类之间关系的用词~~)
还有一种关系是Link-A的关系,这种情况下的不可复用性按情况下来定,,Is-A的准确意思是什么呢(这里的意思指语义)?如B is a A,,那么“B是一个A”,,可能是一个A,但是不一定必定是一个A.而且如果B是一个A,,那么反过来就不能成立(子类化,虽然站在类型转换的场合下可以但是现实生活中这样理解不通)
一个代码的修改量应只取决于它最低层的实现,如果某个低层引用了过多高层逻辑接口的实现,那么这只能说明,对这个实现的解偶还没有规划到家,理想的情况是,应该只让这个实现的修改不触动到任何间接使用它的高层逻辑!!(因为自顶向下的引用对于顶来说,如果底部被修改顶部是不用作任何改变的,而如果是自底向顶引用,那么当底发生改变时,一定要涉及到顶部也要改变,,而这就是不恰当的高层抽象,违背了好莱坞原则和通米特原则)
回复 支持 反对

使用道具 举报

该用户从未签到

667

主题

2111

帖子

5570

积分

LV 11.会员

MS爱好者!!!!

积分
5570

社区居民偶尔光临工蜂最爱沙发在线达人社区平民做个有钱人略有小成常驻会员忠实会员

地板
 楼主| 发表于 2011-10-22 18:34:01 | 只看该作者
8.14 真正的好莱钨原则
好莱坞原则(不要给我打电话,我会打电话给你们)强调高层对低层的主动作用,即低层应该只管好自己的工作(具体实现),而高层自有它自己的工作(这就是管理低层的逻辑们,或者说从client到具体实现的一系列中间逻辑),在不需要到某个低层的时候,高层并不会调用到这个具体低层,低层永远不需要向高层作出表示,,说它需要被调用,,(即在所有的处于使用者与现有代码的中间的,用于隔离和解偶二者的,那些中间逻辑中,低层逻辑永远不要涉入高层的实现,而只要高层通过某个逻辑去涉入低层的实现,也即低层应不要调用高层,只有高层才会去调用低层,这才是合理的,我们应尽量避免向上调用和相互调用).

8.15 真正的策略模式
Open和close一点也不矛盾,当它用在同一个架构上,open指出这个架构的可扩展性,而close指出这个构架的内敛性,open是相对高层来说的,,而colse是相对内部实现来说的,,,一个构架应对高层open,而对内部实现close,,,
策略模式将可变的行为集封装起来,这符合OO封装“可变部分”的原则,可变部分就是实现,我们修改一个软件直接修改的就是实现,而非抽象(实际上也不应该也没有必要对抽象进行修改,如果你的工程存在对抽象的修改,那就只能说明,当初在定义抽象的时候压根定义的抽象就是不合理的抽象,真正合理的抽象将使用者客户和现有代码极大地解偶,这使得以后的修改工作只需在低端实现进行而无须触动高端).

8.16 真正的观察者模式
好莱坞原则指出,类之间应尽量避免低层(实现)向高层(抽象,逻辑)的引用,
观察者模式中,观察者,被观察者,一个被观察者管理诸多对象(观察者),这些观察者通过
.
8.17 真正的装饰模式
装饰模式就像是一个用类来修饰类的机制(这就添加了新的职责到被修饰的类,,这里说的修饰本质是什么呢?就是类的组合,让一个类被修饰者成为修饰者的一个实例变量),,,这要求修饰类(可能是多个)和被修饰的类有一致的接口(也即它们同共都曾实现implent了某个接口,或者继承了某个有接口作用的抽象类extend,,这样一来,就可以在动态运行时用一方代替另一方,然而客户并不会知晓其发生过内部的替换)
装饰模式可以让很多具有对等地位而且拥有共同接口的类进行有穷互饰,这样可叠合多个类进行某个共同的接口作用,并获得最终的修饰过的这个成员作用
.
8.18 真正的单例模式
某些只能够拥有一个实例的类对象必须通过某些方法来保证它在程序运行期只有一个单例,而且,更重要的,,必须提供一个全局域访问入口,这个入口必须是类层的,,
通过这个全局域访问点,你可以直接调用类的某个机
因为它的产生实例的构造函数是私有的,只能从类的内部去产生和获取这个实例,换言之,你不可以通过继承或组合的方法去获得一个实例,而且这个方法往往被定义为fina,,也就是C++语言中的CONST,即子类不能覆盖它,
因此,可以用类方法(也即静态方法),这种方法下,从继承
.
8.19 真正的迭代器模式
如果你知道什么叫递归和递推,那么迭代器本身这个概念你是很容易理解的,迭代器跟集合(集合就是通俗意义上的对象集合,虽然存在很多不同质的集合,比如用数据结构表达的对象集,或者用函数索引的hash集,但是只要是集合,它的内在总有一些对象及对象逻辑,对象逻辑就是操作这些对象的根据,比如遍历算法,而至于本象本身,可以是无意义的对象,或者同性质的内存节点,或者离散的东东,然而上面说了,这些集合内部必有一种方法作为逻辑可用来遍历他们各自内部的对象,)的关系就是:无论是什么集合,它都可以把一种抽象抽象归纳出来,就是遍历它们各自内部对象的算法
所以,对抽象的提取,往往是找相同的部分,把这些相同的部分提到高层,而用这处抽象来封装可变的部分(这里指各个集合内置的不同的遍历算法),这样就形成了一个所有集合能共享的遍历接口(当然这个接口并不为集合所用,集合自有它们自己的遍历算法,而是为client所用,不同的client都能面向和共享一个共同的,使者这些集合来进行遍历集合的算法,而不必管这些集合自身具体是如何遍历它们自身的元素的)
.
8.20 真正的工厂模式
工厂模式用来实例化对象,,,可被形象理解为一个封装了专门用来产生对象的某种逻辑(这种逻辑可以是一个方法的形式存在-这就是工厂方法模式,也可以是一个类的形式存在-这就是简单工厂模式),因为大凡产生对象的过程都是低层的(调用New方法实际创建实例对象,属于实现),它压根就不应该跟高层(这里的高层指的是需要引用那些实例或间接引用到那些实例的抽象或更高层抽象,由于一个类只能负责一种责任,一个抽象只能被作为一个类,因此当有多个抽象存在时,有必要将它们按职责分成不同的抽象层次,形成不同的层次类放在一起.
这个道理就像:我们生产出一系列的东西(我们当然可以把这个产生过程直接放置到某个未来应用中-这个未来应用要使用到产生过程中产生的对象,这样一来所谓的“某个具体未来应用”就会跟产生对象过程直接挂钩,因此我们把产生对象的过程独立出来,归纳它为专门的产生对象实例的过程,而应用这些对象的一些应用--虽然不知道未来会有多少应用会存在,而这个“不知道”的说法,本身就反应了它符合未来的扩展性--放置到另外一层去),然而会有其它一系列
.
8.21 真正的门面模式
门面模式也称为外观模式,它提供一个易使用的接口作为它的外观,只是为了使现有代码client和要使用到的对象集(往往是多个具有不同行为不同接口的对象)通过这个接口(制造出的目标接口)能被更简单地使用而已,也即打包某些对象行为(并透露出一个基于高层应用逻辑上的接口),常跟适配器模式放在一起被讨论,因为它们都是为了提供接口而存在的,,适配器模式是转换接口为了“能够被使用”,而门面模式是简化接口为了“更好地被使用”(让被适配对象被client被使用,通过一个目标接口-注意这后半部分的说法才最最重要的)
.
8.22 真正的命令模式
将命令本身封装起来作为一个对象,让它的调用者(注意这个调用者不是客户Client,Client是模式之外的使用者,而是命令模式中的一员Actor,是这个命令模式抽象层中的一层)和命令对象通过对象组合的方法

8.23 真正的模板方法模式
模板方法用一套模式作为定义方法和行为的大致框架(注意是大致,而不是全部,这个机制就允许挂钩,和一些需要它的继承子类实现的抽象方法),这跟策略有一点相似之处,因为他们都封装了作为可变部分的行为,然而它们之间还是有差别的,
然而,模板方法使用继承模式,而不对象组合模式,模板方法因为是一个抽象方法,因此如果有子类继承它,那么这个子类必须要实现这个抽象方法

8.24 真正的适配器模式
Adapter,不是接口的意思,它更准确的意义应该是适配,真正的“接口”在不同的应用场景下有不同的意义,现例举如下:
1,Java的一种机制,这种interface语法是一套抽象机制,如果实现
2,接口类,这些接口类往往是抽象类,
3,二进制复用的接口,比如COM,也就是构件接口
4,接口方法,某个class非private的方法(无论是抽象的还是带有实现的都可以称得上是一个接口,一般是指抽象的成员方法)API都可以是一种接口
5,逻辑模型,通俗意义上的“抽取归纳”某个接口,或者说是高层入口,通过这个高层入口,所有的
以上只是为了不跟OO中的接口相混淆,所以强行把适配器模式说成是适配,,其实适配就是适配二个拥有不同接口对象的接口对象(也即这个产生的目标对象“接口对象”也是一个接口,)

8.25 业务与逻辑分开
业务就是你做软工的设计阶段时,所要明确的"逻辑本身",界面就是"表现此逻辑的应用形式"(面向用户的一端),也即逻辑是"我们要搞清的问题"(面向低层的一端),要解决和面向的问题领域,这个所谓的"问题"是严格的,它决定了我们在编码要体现什么样什么维度上的功能.因此在设计中,"搞清你要实现的问题"永远是重要的
另外一个概念是数据,数据处理逻辑要做成独立于界面和逻辑的,此时要提出一个架构,进行新旧系统的分合与整离,让应用统一于某种低层逻辑或界面形式,或由这种架构创建新的应用.
现在的网页,即使它用到xml做数据源,也是不完全的"业务与界面分开",我们应保证"如果一个页面被刷新,那么那些不与数据相关的界面元素根本无须变动",这就是彻底的分开
这种理念可以让网页反映速度提高很多倍,,应用的多元化绝对是可以被统一的,只要你能提出一种合理的架构,架构的提出不仅是一种IT观念改革(对某个抽象有了新的认识),而且是一种极大创新的活动(人们可以由此发展出很多改变了形式的应用).
多少人明白domain这个词的意义呢,如果泛化起来,会是什么意义,任何问题求本溯源就是一个世界,一个领
域)其实domain这个词是在原语领域描述事物分类的,每个事物都有一个name,受某个domain类name来管理,因此,以什么粒度以什么元meta来分类事物并命名以产生一个命名机制呢,就是domain name这个词的由来,(元是老子提出来的,古人希望把世界的本质用元这个形式形式化下来)
Java的源程序文件夹也是这样,你难得找到一种命名为你的所有大大小小的逻辑命名并人为区别,所以sun找了一个domainname形式,,分类学与命名学是对软工尤为有意义的,,只有sun意识到了它

8.26 架构不是功能的要求,但却是工程的要求
所有的术语都可以被重新定义,,游戏是什么,,其实火星人可能也在玩一种叫"游戏"的东西,,我们的BBS论坛也可以和魔兽世界一样被归为网络游戏,,,这就是重新看待一个领域的抽象,,给一个术语重新格定它的含义的范围,如果性质相同或相似,,就整合它们,再发展形成一个架构,将它们发展成此架构下的分支实现,,比如facebook,它以技术的形式统一了很多web2.0的应用,,,这就是说,应用这个东西,,是可以以技术的形式被统一的,,,从架构web2.0的眼光来看,,blog,视频点插,,,诸多web2.0应用,,都可以被看作为web2.0,,,
这种分离与整合现象其实在IT界每天都在发生,,以上facebook是个例子,还有adobe的Java developer ide? ecillpe??,Java?平台开发库将内存流,网络,本地文件都看成"流",,这就是对一个术语重新进行定义,格定它的范围,,而这是合理的,,因为我们对一个术语的定义本来就是历史现象,当历史发展了,,一个术语要么被增加新的内容(量变),要么被完全演变,,成为一个新的术语(独立发展成一个新东西,虽然原来的那个术语也有效)
?我们所看到的概念,,如果重新被设计,,会产生很多新的抽象(在另外的维度上甚至会产生更多抽象,只不过我们是人,有限的生命不能允许我们同时或异时站在多个维度去想东西),,和由此而生很多应用,,这就是sun所玩的游戏,,比如它提出一个"xml",,实际上xml的最高境界就是"文档互换的标准",,由于xml的成功流行,这由于它是符合应用的,它就成了标准,实际上如果随着历史发展,xml就会过时(Jnos出现了),,xml只不过是人类知识的临时品,,,总会有它的代替品出现,xml相对"文档交互的标准"这个说法是个实现,而"文档交互标准"这个说法是个思想,一种思想反映在IT界,可以用代码实现(细节级的),,也可以用构架来形成一个观念上的应用规范,,比如XML规范,,这种思想一定要理解,
火星人也把他们玩的一种东西称为"游戏",,任何到现在为止我们能耳听目见的东西,,其实都不像我们想象的一样简单,,当你学习西红柿的单词时,如果你不能了解到它其实是一种外来词,,这种现象,,这种对一个术语的"历史抽象",,那么你就不能有效地学习它,只能说片面了解了它,,而这对学习是不利的?

8.27 你需不需要一个库
IT开发中,,只有属于底层开发的,,,一般才称为开发,,发明轮子,,,而复用成风的今天,JAVA这样的语言体现的是一种高级逻辑配置式的开发,当然也算开发,,所谓库,是一种面向通用和复用的中间逻辑,,接口逻辑,而非终极的应用逻辑本身,,,库面向应用复用提供接口,而应用逻辑面向应用本身.语言的功能和可复用性,,一个很重要的方面是除了语言自带库之外,还有没有第三方为它开发大量的开源库
所以,如果你不是专门为了通用的目的考虑,就根本不需要开发一个库
回复 支持 反对

使用道具 举报

该用户从未签到

667

主题

2111

帖子

5570

积分

LV 11.会员

MS爱好者!!!!

积分
5570

社区居民偶尔光临工蜂最爱沙发在线达人社区平民做个有钱人略有小成常驻会员忠实会员

5#
 楼主| 发表于 2011-10-22 18:35:40 | 只看该作者
8.28 可复用与可移殖的区别
在相关书籍中,存在很多相似但其实有很大区别的概念,比如可移殖与可复用,接口与实现,接口与抽象,下面试区别之。
在一个大型软件系统中,抽象是分层次的,,粗略地来说,有的抽象是系统平台相关的抽象,有的是对于目标问题领域的抽象。注意这个区别只是粗略的绝不是精确的(所以也可说是无层次的)。
设计中经常将实现和抽象分开并各自集中,如果抽象中过多地混入了细节考虑(即有硬编码和实现出入的地方),那么它必将在以后的扩展过程中产生麻烦,因为对于一个庞大的软件,其内部逻辑复杂,牵一发而动全身,语言给于实现和抽象形式上的划分方法只有头文件和CPP文件这样的初级方法。实现和抽象的分离从来都高度掌握在源程序的作者手中,我们知道,抽象不全是为目标领域作抽象,有一部分抽象是为接口作抽象,也就是为可复用的有效形式作抽象,即接口是抽象的一个部分,是抽象的简单形态,,其目的是为了给使用它的客户提供一个复用(或实现)的原型和规范,比如库,函数API,这里的客户是程序员用户用户。(但是像虚函数那样的语言内接口,又不完全是为了面向人的复用,而是为了面向程序内逻辑客户的实现。这个客户跟据这个接口产生出一个关于这个接口的model),如果不是库,则不需要提供接口设计,而实现是未端抽象(这就要求设计者具有良好的对系统的可复用考虑的设计能力)。更多的关于接口与实现的区别在文尾有述。
在一个复杂的软件系统中,可移殖逻辑主要集中在那些与系统编程相关的逻辑中,而不是对于问题的领域设计逻辑(虽然如果对问题的领域设计,,抽象得不得体的话,这样同样会导致不可复用问题,但决不会产生不可移殖问题)。比如对某语言密切有关的字串逻辑的依赖,对某平台密切有关的某个socket..鉴于对不可移殖问题的考虑,,我们往往将它与领域逻辑分开。所以可移殖问题只是可复用问题的一部分,二者绝不是同一意思。
所以,应该怎么样做呢?这样才能同时达到可复用,又最大程度地可移殖。(当然,只能是最大程度地这样。)
编程涉及平台支持和目标领域问题。一个用编程语言写就的,用OS运行的,“软件系统”中,必将大量存在这样的“平台编程逻辑实现”,相比之下领域逻辑少得多,(我们将由领域逻辑主导实现逻辑。)。
一种方法就是广为谈到的“抽象与实现分开”,我们需要将各个“实现”按文件物理地分开放置(此文件将会是引用的未端,不被“设计”直接作为头文件引用,而是作为最终可用可弃的实现未端,由它引用目标领域逻辑)。当然这个过程中,我们应注意模块化(所有的编程范式都是模块化的),然而正如上述所说,模块化不能复合,不能高下相互引用,比如“设计”引用“实现”
。(因为设计中有自上而下和自下而下,故也不存在各个模块之间平等不相互引用的情况)但是如果不考虑最终软件系统的实现的话,光就设计来说,确实也存在各个设计模块之间平等绝不相互引用的情况存在。
除了上述不可复用问题来源于不可移殖之外,还存在以下几点不可复用问题产生的源头:
解决不可复用问题的方法是增加迂回(一层抽象接口),将实现逼回底层,这个动作出现在二个过程中1,对于目标领域的抽象过程中,2,对于重构时的过程中。
然而,所谓的迂回,其实也是系统中的抽象,,也会对可复用产生障碍,一定意义来说,系统中抽象层次过多,,或数量过大,都会直接对可复用性产生麻烦,这为了解决不可复用问题而设计的另一层抽象正加大了某种程度上的不可复用性。所以是一种以毒攻毒的方法。解决问题的方法正是产生问题方法的来源。
不幸的是,语言机制也会造成不可复用,比如模块就没有函数来得可复用性强,然而复用从来都是相对的,存在一个比较时所采用的最小考虑单元,仅在C++语言内部而言,模块是可复用性很高的,在所有语言面前,函数接口和过程式开发无疑是复用性最大的。。这就是linux之父跟别人争吵的源头所在。这也就是说,C++的抽象性能反而带来了不好的地方,越抽象的东西越会阻碍可复用性。
当然,最后,抽象的方法不同,产生的抽象结果不一,由此产生的不可复用问题是最严重的。因为复用者一需要理解你的设计抽象,,在理解了之后,才能进行复用。如果你的抽象过于复杂,复用者不会有太多兴趣。
编程能力就是学会如何面向可复用考虑去进行抽象。当我们设计自己的系统时,为了提高它的最大可复用性,我们将它设计为与语言无关,与OS无关,与复用的库无关。这种工作是相当难的。设计中的目标问题抽象永远是自己的。那么如何将这些如上的“实现”逼到未端呢?
首先,要想做到与语言无关,就要用那些最初步的语法机制和开发范式,比如函数过程式。三种控制结构(事实证明它们可以产生一切逻辑)。或者自己开发一套自己的语言,在自己的语言领域之内作“固步自封的复用”。但我们知道,这(当其它语言不存在)实际刚好阻碍了其它语言对其的复用。
其次,要做到与OS无关,当OS不存在吧,不要引用OS的任何东西,,,照样是在自己的语言的基础上发展自己的GUI库,等(这实际上也是很多语言提出可移殖理念最初的出发点),一系统的系统平台相关的库。
要做到与可复用库无关,只有自己开发功能相当的库了。即一切轮子自造,包括语言。然而你可以改造语言,却不能改造英语编程语言,那是一个未知领域,你更不可能在冯氏模型之外发展这样的语言,你不能改造PC模型,也不要指望改造OS,更不要指望改造电脑的能源为光脑。
所以,一切好自为之吧。既然轮子的创造是一个无底洞,,何不直接就复用别人的库呢,用大家都用的语言呢?更重要的,作大家都在做的领域设计方案。这样别人才能理解你的设计。
接口是实现的原型,,一般谈到实现,就是一个复杂系统中的终极未端逻辑,意指其不必为复用留有余地(因为复用就是利用接口作进一步的抽象,复用跟接口密切相关,所以实现也指不必为接口设计作余地),一般谈到接口,意指为下一步的抽象提供统一的原型和形式,即为如何复用提供设计,

8.28 再谈可复用
可复用问题的由来一是实现的不能可复用(还记得在C语言中写上大量的预处理代理来实现跨平台逻辑吗?),二是架构逻辑的不可复用,,,,实现指的就是跟计算机离散相关的平台逻辑,,架构就是人为为程序的可扩展性加上的设计逻辑,,大多数是OO之后的东西,,我觉得提出二门语言,一门C,一门类RUBY的脚本语言来进行程序的编写,,,,在底层用C,在高层用OO脚本,这样的办法很好...因为你在低层不需要架构,,而只要在高层考虑架构问题.,,这样一来,可复用性就是二个阶段的事,前一阶段只管实现,不考虑设计,,这种过程是承接性的,只要先实现了,才能被设计得架构上更科学.

8.29 真正的可复用
可复用到底追求一种什么样的效果,又能最终达到什么样的效果?运行期的效率或重构期的不可复用和窄扩问题(这是二个并非绝对统一的东西),一切都可归究到设计期的问题。
编程界的可复用主要是面向对象和构件复用和设计模式和设计复用,库也是语言内部的可复用(就跟你拥有库的源文件一样.因为有头文件也是一样的,因为你还至少清楚库的构架,这也就跟理解并应用一个库只需了解其API就行了但不需要了解其SRC级的实现一个道理.ode的头文件集却是一个例外),COM的复用就是纯粹的二进制的复用,因为有真正的接口的隔离作用(此时你根本不知道库的构架),在库定义的接口中,你必须透过接口才能深入接口更下面的逻辑(可能是另一个库的实现),因此接口一方面提供了方便性,另一方面也增加了屏蔽性,这是一对矛盾,接口的定义是为了引入某种架构或桥接二种架构使其配合工作,而这种机制在提供了方便性的同时也增加了理解和使用该接口的复杂性和运行时空的代价。
用OO来表达世界的观点,,,物体可以组成世界(所有其它的东西,比如物体之间的关系也是另一种意义的物件),,,因此编程抽象了OO,那么编程就可以用来用计算机模拟世界,这种思想是成立的。
库的组合=功能的组合(类库设计是一种跟语言同级的设计),当然这种逻辑在使用同一种语言下是成立的(不同语言时也可以用Swig等技术来改造或Bind),然而库作为中间逻辑的封装者(库让你跳过库的实现即中间逻辑这些细节而直接面向大逻辑大架构编程,只要引用它们就可以在自己的程序中实现它们),可以一直细化接近最终实现,诚然单逻辑的一个类也可以被封装为一个库但是往往不样做,一个库封装了一套互饰的中间逻辑的有机组合,,这里的中间二字是相对最后的应用逻辑来说的,往往把最终的应用逻辑称为实现,这就是一种实现逻辑了而不再是中间逻辑了(这就是说库可以是一种内含高抽象的架构逻辑或具体的工具函数的实现逻辑,或基于其它库之上的架构逻辑或实现逻辑),库可以直接深入到实现细节,但是我们要控制这种过程,一方面是中间逻辑与最终应用逻辑不可精确定界,另一方面是因为设计与封装是个无底洞,不必做这种深入,第三方面是有其它的库可以plug进来然后在这些“轮子”上实现(库应只提供BaseGeneric这个库构架(此时库本身是一组架构逻辑而非实现集)和对一些其它外来支持库的引入接口(一般接口需实现,逻辑需继承,此时其它库可按需进行plug in 或者out),这就是库引用库,这种情况下有一些未端的实现是不应该加入中间封装的,比较好的作法是用一个库定义架构和基本工具函数集,以及对其它未端工具库的接口逻辑(此时先前定义的那个库就是主库,其它的库是可选的辅库,比如Yake的实现就是这样),实现就是最后一节提到的几个Demo(作为基础的逻辑已经被库封装起来,其它的就是实现了)
像Yake,它提供了一个Base core和很多构架上的接口逻辑,每个接口逻辑都实现了一个对外来库的引用,Base core是工具函数集(也有一些接口逻辑),这是Yake的主体部分,而接口逻辑(Yake也在这里实现了一些工具函数库比如)和对其它库的引用逻辑(也是一些Adapter)才是Yake的重要部分(Yake包括它的base和对其它库的引入逻辑这二大部分,当然还有它的一些工具实现,这样算起来Yake有三大部分).
接口是可复用中一个很重要的概念。

8.30 你能理解XP编程吗
大设计是一种动用一切资源,从整个思想领域去设计计算机应用的过短,,这完全是一种预设计,编码过程变成了纯粹的被设计预见的集成的一个过程,,这种设计往往首先从思想出发,,完全不考虑计算机实现,语言机制对应用的限制或表达能力,,,提出一种标准和理想模型,把思维过程出现的任何一个过程都作为设计的一部分,设计过程中任何动作都不跟计算机和程序语言相关,,最后仅留一点余地作为编码,在编码时考虑其跟计算机实现和语言机制实现的结合,编码的地位很低很终端。。
XP编程出来的时候,,人们大呼设计已死,,因为这种边设计边编码(在编码中形成设计)的方法大大忽略了设计超越“编码”的“预”,,设计变成了跟编码并行的过程。。
实际上,该如何处理设计呢??比如设计游戏。。
我们知道设计是无底的,这种无底性决定了我们应有限地把思维中出现的理想设计和想法体现到计算机逻辑和语言机制能表达的逻辑中,,,而且应尽早地这样做,,任何应用领的逻辑都要最终被转化成计算机逻辑和语言逻辑。。也即,我们不必做超级设计和完美设计。。
游戏是什么呢?如何设计一个游戏呢,,游戏这个字眼可以无限被放大(应用领域可以无限深化),WEB论坛可以是文字游戏,3D游戏也是游戏,,网游也是游戏,,是不是要在你的设计中体现这所有的元素呢(一个具体的设计总是针对某个应用域寻求它在计算机和语言域的对应,如果你知道算法和数据结构你就深刻理解这个说法了,我们总是向语言和OS中寻找某种可能适应我们问题的数据结构,即使再通用的逻辑,比如库的设计,我们也不应),并用一种“设计模式”中的模式来组织这所有的元素呢,,不能,,而且不应该。。你不可能在有生之年把它们(设计中出现的需要组织的逻辑们)的地位作一个组织或你自认为合理的排列。。
你可能会说我不直接提供这些无素的实现,,不直接在设计中体现这些,我只需预见它们,,并在设计中为他们预留接口,,但这样也是不行的
那么最后出来了,,什么是XP编程
预设计,大设计是一种“一次性设计”,企图把应用设计中的大大小小所有过程整合到一个大设计中,,,这样的代价当实际编程开始时如果遇到不能前进的错误会损失很大,而且设计本身花费精力也不少
而XP编程先是提出一个不够完美的框架(针对某个应用,有应用本身和它产生大大小小的其它应用问题,这不够完美的框架是针对整个应用本身来说的),或者不提出思想模型,,,它并不试图分析整个应用,,以及对它们的设计(因为它相信设计不可能是一种大而全的,只能具体问题具体分析设计,人们不应把所有可预见或在后来出现的问题整合到同一个设计中),,并不着手预见可能出现的问题和对它们的大大小小的设计过程,当具体应用问题中的大大小小问题出现时,就着手一个即时设计(比如设计游戏时,这是个具体的大的应用问题,针对游戏本身可提出一个不够完美的框架,,当在他下面遇到有很多小问题,,比如网游时间同步,,我就看语言中提供了什么线程和语言机制,或者如上面说的数据结构或算法,来进行一个小设计)
这就是XP编程的全部意义所在。。
回复 支持 反对

使用道具 举报

该用户从未签到

667

主题

2111

帖子

5570

积分

LV 11.会员

MS爱好者!!!!

积分
5570

社区居民偶尔光临工蜂最爱沙发在线达人社区平民做个有钱人略有小成常驻会员忠实会员

6#
 楼主| 发表于 2011-10-22 18:37:51 | 只看该作者
8.31 构件与接口,软工
UML,IDL,MDA,COM.CORBA,WEBSERVEICE,XML软工新潮流
关于接口,也发展出一种语言叫IDL,,语言跟应用的关系是什么呢??因为语言可以接上计算机处理跟人们的应用需要之间的接口,,所以语言和编写语言下的程序成为扩展计算机也扩展自己的手段,,甚至还有DSL为了解决特定问题而产生的一种语言,语言的实现即编译器,语言规范等,,
而MDA是不同的概念,MDA是给定一个领域的描述,,然后写出一个依赖于接口的xml格式的web services.
这直接促成了构件的产生,,,在SOA中,因为要集成新老系统,当构件作为一种比对象还要大的软工逻辑粒度时,,它们共同需要都需要接口,,但是构件
不要小看了这个构件??它几乎可以是一场软工变革,跟OO有相平之处


编程与范型(设计)
初始OO,我不过认为那是一种编程语言支持的工具,,真正懂得它时,我发现我走入另一个迷惑,一个更深的迷惑,,如果OO是一种思想,,,所以我要怎么用语言去联系它?

8.32 设计方法论
“在原语空间内进行设计”前应该是现实世界问题域,在“产生最终类文件”后应该是编程域的OO解(或其它范型解),即设计的FrontEnd面向的是用户,设计的BackEnd面向的最终是计算机,这中间的“原语空间设计”,“多范型表达设计”,“ROSE工具实作范型”都是“设计演化”,即设计是一种从用户到机器的抽象过程(它包括前面提到的三个主要过程,原语设计是从上到下,泛型设计是从下到上,明白这个道理有什么用呢?这至少可以解释为什么好的架构可以扩展出足够丰富的未端实现,因为从架构设计到功能实现是互通的,这二者不是矛盾的相反是统一的,明白这个道理还有什么用呢,这也可以解释为什么Yake的BaseGeneric不是包含架构逻辑的Generic,而是一组与平台native本地有关的DLL引入逻辑,数学函数,Logging机制什么的,这是因为需要先提供这样一些实现,才能独立平台,而这是Yake首先要解决的问题,因此只能把这层逻辑放到最低层再慢慢发展其它抽象,另外,YAKE使用的库中,比如OGRE和ODE就用到了数学函数(并非所有的问题都能靠提供架构和中间抽象来达成并解决,因为有些问题不是要不要封装和不封装的问题,而是能不能实现的问题(能不能用OO来表达跟能不能在算法等级实现是二个不同领域的问题,一个是软件的设计,一个是算法,前面提到了这二者之间的区别),比如一种算法,什么是架构什么是实现,这里是一个很好的区分例子),底层必须先解决并提供这些抽象,以我来看,Yake真正的主体不是BaseGeneric,它是基础而不是主体,它的主体是对其它库的引入逻辑,这才是Yake的架构逻辑,因此说,架构逻辑有时仅仅是被体现,而没有并封装成DLL,也即,架构是否被体现与它是不是要被封装成为一个库是没有必然关系的,哪些没有表现为库的中间逻辑也可以是架构逻辑,明白这个还有什么用呢?原语设计是不受限的面向用户的设计,然而当进入多范型设计时慢慢转入用计算机的观点来看待设计,因此像Yake这种与平台息息相关的表现逻辑必须在底层就解决平台抽象和数学抽象,而LogicGeneric就根本不用考虑这些,因此多范型设计相比原语设计来说,它是从下到上的),而实现是一种从机器到用户的过程(实际上我在这过多强调设计与实现的差别是不对的,因为这二者无法精确定界,然而如果所有中间逻辑都被封装为库,这二者差别就很明显, 库作为中间逻辑可以参与进来以缩小这二个过程差距,把应用架构称为设计,把中间逻辑封装为库(架构也可以表现为库),实际上在这里,中间逻辑与最终实现才是对立的说法的二方,设计与编码才是另外二个对立物(设计就是原语设计而编码就是多范型设计),
设计演化(从问题到类),,实现演化(从类到问题),,前者是从人到机器,后者是从机器到人


逻辑互饰构成的逻辑的巨集组合,就是一个越来越接近应用总逻辑的大逻辑,(上下互饰就是谁更接近应用逻辑的道理,至于最终应用逻辑前面的逻辑,都可称为相对的中间逻辑)
然而设计与中间逻辑不是没有关系,把库外的未端逻辑称为实现,在这种说法下,基于库之上的实现跟设计共享同一些中间逻辑,库使这二者有机结合不产生缝隙,当然作为泛义的库是缩小任何二个架构之间差距的机制),其实在“ROSE工具实作范型”之后还存在一个“设计载体与设计方法”,即UML图,或卡片啊(设计载体),设计方法主要是“找事物的共同点与不同点(就是多范型设计那本书的作者提到的)”,还有就是UML教学中出现的“给出一个句子,找出主语谓语等”(其实这些方法归纳开来就是做列举题和判断题,列举出一些细节,再判断它应属于那个接口中,这在第四部分“确定GameGeneric应提供什么样的高阶接口”那一节有清析的讲解)
实际上我的思想和说法比他们还要超前和规范一点,原语设计三种思想(抽象,原语,组合)就包括上述的说法(找事物的不变点就是指抽象出事物的本质,这是设计过程中一个很重要的能力)
在观察者模式中,

8.33 真正的interface
正如对象的索引才是真正的对象一样(C++中提倡使用引用优于指针),对接口编程才是真正的编程工作,一个程序员大部分情况下只是一个接口粘合者(因为我们不需要重新发明轮子,发明轮子-中间逻辑的工作才是真正的对实现进行编程),发布时我们也是发布接口库和其说明文档,大多数情况下,我们都是利用第三方代码库编程(这是语言之外的接口,程序员也在语言内部编制函数等接口)
接口设计是一个编程工作中常常要考虑到的问题,要考虑提供这个接口的实现会在什么地方会用到(因此它跟需求分析密切相关),以此来设计接口的参数信息,一个接口不单单是一个函数,虽然函数的声明部分在大部分意义下作为接口的意义,,,,
所以delphi的单元中有实现和接口这二个字,,,接口的集大成者是COM,所以borland以它的IDE很好地支持接口而著名
这是语言之外的,
设计一个面向需要程序设计语言永远是不可行的,需要永远是可变的,程序设计语言只能遵守一个固有模式而提出,有固有模式去表达和创立新东西(面向对象就很不错),编程是人的动作,人力对工程(一个大软件就是一个工程)的控制应该尽量简化,
特别是要掌握对象(或称工件与产品)与接口-组件(对象接口与组件接口是不一样的)概念所在,前者是语言内部的,后者是语言外部的
在内部
纯数据对象称为死对象,(可用但无用)纯实现对象称为工具对象,不可用
在外部
纯接口对象称为抽象对象,(可用但无用)纯实现对象称为工具对象,不可用
面向接口,(一个一个的接口,函数称为函数接口)接口归接口,实现归实现,实现不是函数
软件就是包装器,就是一大堆接口的有机组合,不提供继承机制
一个类型的数据可以独立构成一个数据结构
对数据结构的描述包括它的类型,它的结构,它的存取规则
软件设计是一种什么样的过程?
软件就是对象组合,这些对象通过他们的接口按一定逻辑组合成可工作实体
在语言内部的继承是对象,在语言外部的继承是组件
对象的概念,包括函数对象,变量对象,数据也是对象(作为一个元出现在一个特定的数据结构里),因此数据结构也是对象,操作实现也是对象,实现称为处理器,数据或实现的组合也可称为对象,注意,对象的组合只能是被称为对象组合,只有那些能在一起工作的对象组合(compent view)才能称为软件,这里引入工作逻辑的概念(就是ROSE中的logic view)
在内部
纯数据对象称为死对象,(可用但无用)纯实现对象称为工具对象,不可用
在外部
纯接口对象称为抽象对象,(可用但无用)纯实现对象称为工具对象,不能由它派生出实例
面向接口,(一个一个的接口,函数称为函数接口)接口归接口,实现归实现,实现不是函数
软件就是包装器,就是一大堆接口的有机组合,不提供继承机制
一个类型的数据可以独立构成一个数据结构
对数据结构的描述包括它的类型,它的结构,它的存取规则
数据是对象,逻辑也是对象,操作也是对象,一切皆对象的概念,在机器内部一切皆比特,在用户眼中,一切皆对象,因此数据库的数据二字是有通用意义的,,,因此会有面向对象的数据库
至此只是软件内部,那么在软件外部有develpoment view
数据组合接口形成一个数据结构
对象和(包括接口和实现)构成一个组件DLL或LIB,一组对象和一组接口就是一个DLL(称为一个产品),需要一个调用协义接口
.
8.34 真正的对接口进行编程
不存在一个“对接口编程”的真实过程(虽然这是一种过程定义),我们只是说,要为”实现”定义一系列使用它的接口(这样实现才能更好地被使用和被修改),,这种行为才是对接口编程行为,而接口本身是什么还是没有说哈哈
一个为未来扩展而写出的工程中,大部分代码只是框架(抽象的思想模型,也就是为了扩展需要--也是为了使用需要,而定义的一层又一层的抽象),真正的实现部分(调用API啊,用某个算法啊,某个完全具体工作的实体对象,或某个完成某个业务过程的会话对象)很分散,而且分散得很有规律性(因为被抽象接口经过了再组织,所以变得有规律地分散),,这样的分散机制就像把真正的实现逼到最尾端,而最高层往往是使用这些尾端要如何被使用的应用逻辑--被抽象成了一个或某些使用的统一接口形式,而且是高级逻辑,(即接口实际上是关于如何使用这些实现的隔离层,,中间层)
这样抽象也称为为客户调用(或使用)的协议定义
很多时候,在一个工程中,所有的实现都可以由一个Demo直接写出来(写成CONSOLE形式,也可以是一些对象集上面说了),然而,真正形成产品时,我们需要再组织这些实现,让它们最终形成的产品出现(因为一个真正的产品,必须要考虑到未来修改的需要啊)这往往是一个比写实现还要难的过程,因为我们在写“如何使用这些实现,如何把这些实现分散封装到未端”的接口逻辑,而这个逻辑,往往有时比写实现本身还要难!!

8.35 实践方法之极限编程
极限方法只是敏捷开发中的一种,,,软工指明软件开发不只是软件本身,,而是软件跟人的关系,,因此这出现了设计与编码,,,设计与编码是软工的二大主体,,,,好了,,实践方法的出现就是为了解决这二者之间的矛盾
?开放的标准使我们的规范保持中立,所有人都可以接受,而不受某一个开发商的控制,而开源可以使我们得到大家都接受的一个实现,而不受某个开发商的控制,这两者的结合非常有力。这个实现你可以不使用它
开发中的分布要求,产生了二个复杂度,1网络开发,2软件要独立于平台和硬件架构,,这就是WEB的特征
.
8.36 设计模式复用与框架复用
设计模式是可复用策略,,是思想级的,,但不是不可以用代码来表现(编程即换维重现,即将思想级的东西转变为语言级的东西),,软件设计的终极目标就是符合软工,扩展软件的可扩展能力和生命力,,设计模式就是服务这个的,,设计模式因此有一些原则,比如LOC,控制反转原则,不重复自身原则,,这就是设计模式对于软工,所要达到的目的,常见的设计模式有哪些呢?,比如MVC,工厂方法,工厂,单件等,,MVC可以说是一种框架,,也可以说是一种设计模式,,因为MVC是设计模式的组合,,它被作为一种框架时,比如 strcut,spring,也是成立的,,可以说现在的一些WEB开发框架比如STRUCT,SPRING,ROR都是设计模式的实作品,而设计模式是一种思想,,设计模式这种思想,这种设计目标和设计手段,,被体现在代码上,,就是用了设计模式的软件,,或用了设计模式的可复用框架,,比如设计模式表现为一种补丁时, 什么时候表现为补丁?就是老总说,某某公司要求我们开发一个软件,但是这个公司提供了一个库,要让我们现有的代码,用一种方法能使它跟这个库协同工作,,因此要利用到设计模式,,就是现有代码,,跟可复用的别人的库,,,,在这二者之间用设计模式进行连接,,,,发展出一种可运行的逻辑,,而非补丁式的设计模式的应用,则是在产品没有出来之前,,不需要适配既存可复用库和要写出的代码这二者,,采用的一种预先的,,大而全的设计方法,,非补丁式的设计模式,,是一种真正的设计,,,此时模式二字反而可删掉,,是一种预先想到可能想到的所有扩展能力,,决定采用什么设计模式来编码,,在这编码之前 ,,决定采用什么设计模式,或采用什么别的方法,,,这就是真正的设计,,预先的,,如果可能,尽量大而全地考虑,,,当然设计不仅是面向可复用,,还面向应用设计,,如何设计应用,,如何设计用户界面,如何分析业务逻辑以便于扩展出关于这个业务逻辑的新逻辑,,不仅是在设计如何编码了,还在于调动计算机资源的能力、思维的建模能力、分解和搭架能力,,很多人以为设计模式是补丁其实是很狭隘的东西,,其实设计模式本来就不是编码,,,只是当人们站在编码角度来理解设计模式时,,他立马就错了,,设计模式是一种流于建筑和软件界,通用的可复用策略,,是思想级的,虽然它不是不可以在代码上被表而而已
引用给了我们什么.
回复 支持 反对

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

     
    Archiver|手机版|小黑屋|( 沪ICP备12034951号 )

GMT+8, 2024-4-29 00:57 , Processed in 0.154670 second(s), 29 queries .

© 2001-2011 Powered by Discuz! X3.1

快速回复 返回顶部 返回列表