在计算机软件中,各种新技术曾出不穷,令人眼花缭乱,目不暇接。但是我通过长期的编程,发觉其主要技术也无外乎以下三点:
1、树形结构
2、分层和分类
3、简单的逻辑推理
先说树形结构。在长期的使用软件和开发软件的过程中,我发现,几乎每一个成熟的商业软件,都会使用到树形结构。从Windows的注册表到Oracle的PL/SQL,从Visual Studio.Net的开发环境,到Delphi的开发环境;从公司的BOSS系统和经分系统,到我自己开发的库存管理系统……这些系统无论大小,都无一例外地使用了树形结构。
然后我就总结,为什么这些优秀的软件都要使用树形结构?不使用树形结构不行吗?树形结构在描述一些复杂的关系时,具有强大的威力,且非常符合人类的思维。人类的家族关系,人类的社会阶层,公司的组织关系等都是一个树形结构,都是一个金字塔式的模型。在金字塔顶端(即根节点),能够控制有限的第一层,第一层又能控制有限的第二层……依次类推,最顶层的一个人就可以轻易控制一个数量庞大的群体。国家的组织关系,军队的组织关系,公司的组织关系等都是这样的。
根据这个思维,我反过来看一些成熟的商业软件。商业软件和人的现实生活联系非常密切,且逻辑关系非常复杂。如何描述这些复杂的商业逻辑呢?用树形结构。使用Visual Studio.Net 开发系统时,观察每个项目的解决方案,你都可以清晰地看到一个项目的结构就是一棵树。
在面向对象的编程思想中,类是面向对象的基本元素。通过观察类,我发现类自身就是一棵树,根节点是类名,叶子节点是成员变量和成员函数,成员变量也可以是另外一个类。这些类之间的关系,又组成了一棵树。有的类继承另外一个类,这两个类就成了父子关系;有的类和另外一个类互相利用,他们彼此之间是兄弟关系……
XML是目前比较流行的技术。很多软件学家都预测未来的Web软件开发离不开XML技术。通过仔细观察,XML无非也是一棵树。每一个XML文档都必须有一个根元素(RootElement),根元素下面有子元素(ChildElement),子元素下面又有子元素……这样,一个XML文档就可以包含任意多个复杂的元素,可以利用递归的方法,访问每一个元素。一个文本文档经过稍微组织的,就可以包含任意多个信息元素,且能够顺利地存取访问,难怪XML技术会发展的这么迅速。
除了XML技术,HTML文档不也是一棵组织有序的树吗?看下面的例子:
<html>
<title>Hello World
</title>
<body><form></form>
</body>
</html>
上面是一个标准的简单的HTML文档(XHTML规定,的标准格式必须写成这样),而不能有任何省略。还有javaScript的DOM(Document Objcet Model)模型,不也是一棵树吗?
Delphi中的对象浏览器,PL/SQL中的对象浏览器,包括Word中的文档结构图,都是使用树形结构的典范。通过树形结构,再复杂的关系,都被展示地清清楚楚。
除了这些成熟的商业软件,就连我们平时自己开发的项目,也无一例外的用到了树形结构。譬如你想开发一个人事管理系统,各个部门之间的组织关系,部门和员工之间的关系,都显然是一棵树形结构。当然你可以不使用树形结构,你把这些部门和员工一一罗列下来。这样的话,就会跟人一种凌乱的感觉,且人们使用到你的系统时,感觉很不习惯,很不舒服。如果你使用树形结构,无论层次多么复杂,都可以轻松搞定,用户不用培训就可以使用系统,节约了大量的项目成本。
最后,我用一句话来总结树形结构。树形结构广泛应用于各种商业软件中,当您开发项目遇到困难或者不知道如何管理和组织某项业务时,请优先考虑树形结构。
分层和分类
在计算机编程过程中,分层和分类是一项重要的思路和技术。
什么是分类?
就是把系统中所需要的信息(或涉及的实体)分门别类,每一类都是相同特征的事物的集合。当然,分类的标准不一样,分类的结果也有较大的差别。但无论有多大的差别,首先要做的是将大量复杂的事物根据某一个统一的标准分类。
为什么要分类?
分类有助于我们更加清晰地了解事物,甄别事物的共性和个性。通过分类,我们可以把复杂的事物简单化,有利于我们更好地了解事物的本质。
分类完毕以后,大量的事物就被分成有限的几大类,每一类究竟有什么关系呢?这就用到了分层的概念。分层,顾名思义,就是分层次。将复杂的事物分为有限的几个种类,我们管理这些事物时就会容易很多;当我们再挖掘这几个有限的种类的层次关系时,我们对他们的管理就更上一层楼了。在我看来,分类+分层是任何软件的基本设计思想。
分类和分层究竟有什么区别呢?
分类强调的是将大量事物分成几块,分层强调的是这几块之间的关系。依照这种思路,分成的块与块之间的关系总的说来也就下面三种:
1、一对一的关系
2、一对多的关系
3、多对多的关系
这三种关系在数据库设计和类图设计时都会经常用到。
我们先看数据库设计。
对于第一种情况(即一对一的关系),我们通常会设计两个表,来对应两者之间的关系,每个表都有一个主键(Primary Key),表与表之间没有直接的关系。
对于第二种情况(即一对多的关系),我们通常会设计两个表,每个表都有一个主键,除此以外,第一个表中有额外的一列,和第二个表的主键对应,这一列称为第一个表的外键(Foreign Key)。两个表之间通过外键关联。
对于第三种情况(即多对多的关系),我们通常会设计三个表,其中前两个表对应于关系中的两个表,每个表都有一个主键,第三个表则由前两个表的主键组成,专门用来描述前两个表之间的关系。
在具体设计软件的数据库时,我们首先根据业务逻辑画出标准的E-R(Entry-Relationship)图,将实体、及实体关系标注清楚。之后根据这些关系,对照上面的三种情况,就可以设计出较好的数据库。
通过这种方式设计出来的数据库,消除了非主属性对码的部分函数依赖和传递函数依赖,一般都会满足3NF(3rd Normal Formula)。我们设计数据库时,只要达到3NF,就是一个设计的比较科学的数据库,就可以在以后的编程过程中,较为方便地从数据库中存取数据。否则,数据库设计不好,就会在以后的编程过程中,引发插入异常或是删除异常,越写越不顺,越写越麻烦,以至于最后不得不推翻重来。
看完数据库设计之后,我们来看类设计。为什么要看类设计呢?在面向对象编程的过程中,主要牵涉到类的设计。类设计和数据库设计之间有着相似的部分,但又有很多不同。最大的不同就是类设计比数据库设计更加细化。在用途方面也有很大的不同。数据库设计,主要目标是通过数据库管理系统(DBMS)把数据存储在硬盘(Hard Disk)上;类设计,主要目标是通过内存访问机制把数据存储在内存(Random Access Memory)中。
我们再来看类设计:
对于第一种情况(即一对一的关系),在UML(Unified Modeling Language)中称为关联关系(Association)。当一个类是另一个类的变量成员时,我们就称这两个类之间是关联关系。我们可以设计两个类,分别对应两者之间的关系。现实生活中,丈夫和妻子就是一对一的关系,用java代码段描述就是:
Public Class Husband()
{
Public Husband(){}; ///Constructor
Private Wife myWife;
}
Public Class Wife()
{
Public Wife(){}; ///Constructor
Private Husband myHusband;
}
对于第二种情况(即一对多的关系),在UML中,称为聚合关系(Aggregation),聚合关系表示两个类之间有整体和部分的关系。譬如部门和人员的关系,连队和士兵的关系,球队和球员的关系等等。一个部门下有多个人员,一个人员只能属于一个部门。显然,部门和人员是一对多的关系。用java代码段描述就是:
Public Class Department()
{
Public Department(){};
Public Vector allEmployee;//Vector 是一个链表
}
Public Class Employee()
{
Public Employee(){};
Public Department myDepartment;
}
对于第三种情况(即多对多的关系),在UML中,并没有多对多的关系。但是UML中,可以将关联关系、聚合关系、泛化关系组合起来,共同描述多对多的关系。关联关系和聚合关系我们已经阐述,接下来我们来说泛化关系(Generalization)。
什么是泛化关系?依我看来,就是族谱关系,借用《愚公移山》中的话来说就是“子又生孙,孙又生子,子子孙孙无穷尽矣”。泛化关系表示“类B是类A的一种”。泛化与继承(Inheritance)的概念可以互换。譬如,球员分为大球员和小球员,大球员又分为篮球员和足球员……用java代码段描述就是:
Public Class BigBall()
{
Public BigBall(){};//构造函数
}
Public Class Football extends BigBall()//足球从大球继承而来
{
Public Football(){};//构造函数
}
当然,上面我是将数据库设计和类设计关联起来,并将关系一一作了对应。事实上,UML中对类之间的关系更加细化,除了我上面提到的关联关系、聚合关系、泛化关系之外,还有组合关系(Composition)、依赖关系(Dependency)、实现关系(Realization)等等,如果想确切了解这些关系的含义,请参考UML方面的书籍。
在我看来,这些关系中比较重要和常用的,就是前面提到的三种:关联关系、聚合关系、泛化关系。使用这三种关系,就可以将复杂的业务逻辑用面向对象的思想描述出来。
以上篇幅,我花费了大量的精力描述了分层(层次关系)的概念,并且将这些关系映射到数据库设计和类设计上。为什么我要描述这些内容呢?因为在我看来,使用面向对象设计时,可以根据客户需求,将系统中涉及的实体分类,根据业务规则,描述出实体与实体之间的关系。然后,根据这些类和关系,参照上面的设计原则,就可以轻松地设计出数据库和类图。之后,就可以将数据存取在数据库或是内存中。有了存取,经过简单的计算,一套商业软件就可以投入使用了。
最后,我用一句话来总结分类和分层。分类和分层广泛应用于软件开发过程中,分类强调将复杂的、大量的信息变成简单的有限的几个种类;分层强调的是分成的种类之间的关系。有了类,有了关系,按照我们上面的设计原则,就可以设计出数据库和类图,数据库和类图正是我们软件开发的基础。有了这些基础,加上复杂的业务逻辑,我们就可以完成任何商业软件。
简单的逻辑推理
在长期的软件开发过程中,我经常会遇到一些令人左右为难的情况:如果按照A思路往下走,就会和B功能冲突;如果不按照A思路,又实现不了和C模块的联动功能。那么这时,我是按照A思路走,还是不按照A思路走呢?
这个问题曾经困扰我很长时间,每次我都需要冥思苦想,才能够最终把问题解决。不能以后每次遇到这些问题都浪费大量的时间吧?后来,我就不断总结,经过长期思索,我对这个问题终于有了普遍的解决方案。
如果再次遇到这样的问题,我不会陷入“按照A走还是不按照A走”的思路,我会跳出A、B的思维,从整个软件项目上考虑A、B、C,用最简单的、常人都接受的逻辑推理,推出到底是按A思路走,还是不按A思路走。
这样一来,通常的结果是按A思路设计不对,不按A思路设计也不对。这个时候,我会从更大范围上重新设计业务的逻辑规则,按照新的规则,系统就会十分顺利的完成。
在日常生活中,我就经常问自己:什么是简单的逻辑推理?简单的逻辑推理,就是简单的连小孩都知道的推理:譬如说,如果前面遇到一堵墙,你就必须停下来;如果前面是大路,你就可以走过去。遵循这些逻辑规则,你就能顺顺利利地通过,否则就会撞的头破血流。这些道理大家都懂,但软件中复杂的逻辑规则,都是由这些十分简单的逻辑规则组合而成的。如果我们将每个简单的逻辑规则都搞清楚了,将这些简单的规则组合起来,整个软件的逻辑规则就水到渠成了。
写上面这些话时,我都感觉自己是不是太幼稚了。但是,我经常把日常生活中最简单的逻辑融入到软件开发和设计的思想中,反复问自己如果生活中的逻辑体现在软件中该如何实现,如何更好的实现?我想这对于我软件开发的思想是有帮助的,毕竟软件要服务于现实生活,使现实生活变得更规范、更容易、更高效。
在软件开发过程中,如果我们优先使用树形结构表示复杂的组织关系,对软件中的实体进行分层分类,以简单的逻辑去推理,那么我们在开发软件过程中就会少走一些弯路,提高一些效率。