成也抽象,败也抽象。何哉?
我们所处的这个世界充满了丰富多彩但杂乱无章的信息,要建立一个模型并不容易。建立模型的过程是一个抽象的过程,所以要建立模型,首先要知道如何抽象现实世界。如果我们站在很高的抽象层次,以高度归纳的视角来看这个世界的运作,就会发现现实世界无论多复杂,无论哪个行业,无论什么业务,其本质无非是人、财、事、物和规则组成的。人是一切的中心,人要做事,做事就会使用一些物(例如:花钱)并产生另外一些物,同时做事需要遵循一定的规则。人驱动系统,事体现过程,物记录结果,规则是控制。建立模型的关键就是弄明白什么人,什么人做什么事,什么事产生什么物,中间有什么规则,再把人,财,事,物,规则之间的关系定义出来,一个模型就基本成型了。
建模,是指通过对客观事物建立一种抽象的方法用以表征事物并获得对事物本身的理解,同时把这种理解概念化,将这些逻辑概念组织起来,构成一种对所观察的对象的内部结构和工作原理的便于理解的表达。
建模包含两个问题,一个是怎么建,一个是模式什么。
抽象角度决定建模方向的不同,现实世界建模的时候,首先要决定的是抽象角度,即建立这个模型的目的是什么。
模是什么?依赖于确定了抽象角度下的场景模拟。确定一个目标,找出那些满足目标的事物。
抽象层次越高,具体信息越少,概括能力越强;具体信息越丰富,结果越确定,概括能力越弱。
抽象有两种方法:一种是自顶向下,另外一种是自底向上。
自顶向下的方法适用于让我们从头开始认识的一个事物。例如:介绍汽车的工作原理时,从发动机、传动装置、变速器等较高层次的抽象概念来讲究比较容易明白。如果降一个层次,从发动机原理讲起,一大部分听众就会开始迷惑;再降一个层次,从热力学原理和力学原理讲起,那就更没人能搞懂汽车是怎么工作的了。
自底向上的方法适用于在实践中改进和提高认识。例如:在实践中发现了发动机的问题,因而改进发动机的结构,甚至采用新的发动机原理,最终能够提升汽车的质量。
抽象层次的一个问题是什么时候选择什么样的层次,以及总共要抽象多少层的问题。如果用UML来建模的话,这个问题就直接反映到如何选择用例的粒度。
视图
UML建模中的另一个非常重要的概念。视图的准确应用是建立好模型的一个重要组成部分。在实际工作中,很多人并不知道应该在什么地方应用视图、应用哪一种视图、总共需要哪些视图。现实世界中的每一个事物都有很多不同的属性,每个属性都属于这个事物并且仅能够表达这个事物的一部分。人们认识这样一个事物的时候,只有在了解了很多方面后才能够对这个事物真正理解。例如一辆汽车,人们需要了解它的大小、重量、外观、性能、安全等才会决定是否购买。上述每个属性都是这辆车的一个视图,每个视图都向观察者展示了一个视图,每个视图都向观察者展示了目标对象的一个方面。只有将必要的方面都用视图展示出来,观察者才能理解这个事物。
视角
视角是人们观察事物的角度。不同的人后者同一个人出于不同的目的会对同一个信息从不同的角度解读与评估。视角是针对每一个视图来说的,不同的视角展示了同样信息的不同认知角度以便于理解。
视图和视角是两个被忽略的关键概念,对建立一个好的模型起着很重要的作用。为特定的信息选择正确的视图,为特定的干系人展示正确的视角并不容易,需要因时因地因人制宜。
对象有以下几点属性:独立性、原子性、抽象性、层次性,这些属性是面向对象分析是应该遵循的一些原则和方法。
边界
边界决定视界,边界的大小是建模者主观臆定的。为了更接近真相,我们能够做的就是不断变换边界,改变视界,从更多的侧面去描述同一个信息,以求更大程度地符合真实的需求。如果建模的过程中,对建模结果感到疑惑,那么可以试着改变边界设定,得到不同的参与者和用例,再通过相互印证的方式得到更好的结果。
边界决定抽象层次,边界是虚幻的,又是比不可少的。以过往的经验来看,能够准确把握边界,嫩否灵活变换边界,能否控制边界的粒度是做好需求分析和系统设计的关键。夸张的说,高手和低手的差别或许就在“心中是否有边界”吧。在架构师的眼里,再复杂的世界也是被许多无形的边界隔离、包装、各行其职的。要时时牢记一句话“眼中无边界,心中有边界”。
类
属性
方法
关系
关联关系:用来定义对象之间的静态的,天然的结构。关联的两个对象之间通常不会相互直接使用,尽管它们相互知道对方的存在,但一般都由外部对象访问的,如一个外部访问者可以通过员工对象获得公司形象。关联关系具有多重行,常见的是一对一、一对多、多对多关联。
依赖关系:是一种“弱”关系,它不是天然存在的,并且会随着运动场景的变化而变化。如人和刀两个对象,平时他们是没有关系的,但当削苹果的场景里,人依赖于刀;脱离了这个场景,依赖关系也就不存在了。依赖关系最终的代码里体现是类构造方法、类方法等的传入参数。我们应当保持单向依赖,杜绝双向依赖关系的产生。
包含关系:它用于用例模型,从某种意义上讲,包含用例是被封装的,它代表可在各种不同基本用例中复用的行为。
实现关系:实现所代表的含义是,基本用例描述了一个业务目标,但是该业务目标有多种可能实现的途径,每一种实现途径可以用用例实现来表示,而用例实现和基本用例之间就构成了实现关系。
精化关系:精化关系表示由基本对象可以分解为更明确、精细的子对象,这些子对象并没有增加,减少,改变基本对象的行为和属性,仅仅是更加细致和明确化了。
泛化关系:用于说明两个对象之间的继承关系。
聚合关系:用于表示实体对象之间的关系,表达整体由部分构成的语义。
组合关系:组合关系用于类图,特别用于表示实体对象关系,表达整体拥有部分的语义。组合关系是一种强依赖的特殊聚合关系,如果整体不存在了,则部分也消亡了。
一个组件应该具有完备性、独立性、逻辑性、透明性。
完备性是说,组件包含一些类和接口,一个组件应当能够完成一项或一组特定的业务目标(或者功能),从调用者的观点看,它不需要调用多个组件来完成一个业务请求。
独立性是说,组件应当是可以独立部署的,与其他组件无依赖关系的,最多仅保持关联关系。
逻辑性是说,组件是从软件构件设计的观点来定义的,并非从需求中可以直接导出。组件的定义是为了规划系统结构,将一个复杂的系统分解为一个个具体完备功能的、可独立部署的小模块。
透明性是说,组件的修改应当只涉及组件的定义以及组件中所包含的类的重新指定,而不应该导致类的修改。例如,当一个组件的功能变化时,它所包含的类可能从原来的类A、类B、类D变化成类B、类C、类D,但是类A,B,C,都不应当被修改。
思想总结:
从方法论的角度看,面向对象提供了一种处理复杂性问题的方式。在面向对象兴起之前,结构化设计已经是系统到达了其处理能力的复杂性极点,有了对象,我们通过提升抽象级别来构建更大的,更复杂的系统,有了更高层次的认识论。所以这是面向对象取得成功的基石。
从二元论的角度看,面向对象和面向过程又有动静之分,阴阳之别之处,面向过程强调的是无处不在的变化,讲究变化中之不变,讲究的是一个整体概念;而面向对象讲究的是何为不变,它将这个世界看做一个个相互独立的对象,相互之间并无因果关系,只是在某个外部力量的驱动下,对象之间才会依据某个规律相互传递信息。
从理念论的角度看,也就是分有说还是整体说的区别,是一个事物先有整体,还是先有个体的区别,也就是哲学上的先有鸡还是先有蛋!
What is real? How do you define ‘real’? If you’re talking about what you can feel, what you can smell, what you can taste and see, then ‘real’ is simply electrical signals interpreted by your brain. ——《抽象的本质》