专注于面向对象、领域驱动设计,及软件架构方面的学习

要学会站在巨人的肩膀上让自己成长。QQ:94388050

  博客园 :: 首页 :: 新随笔 :: 联系 :: 订阅 订阅 :: 管理 ::
  39 随笔 :: 0 文章 :: 355 评论 :: 0 引用

最近对OO的理解又有了一些新的认识,拿出来和大家分享一下。为了能让大家简单直观清晰的知道我想表达的主要意思,我不说废话了。直接提出问题,然后回答。

1. 什么是真正的对象?

2. 什么是面向对象分析阶段时的对象? 

3. 什么是面向对象设计阶段时的对象?

4. 什么是面向对象实现阶段时的对象?

 

1. 真正的对象:

我所理解的真正的对象就是现实生活中客观存在或不存在的真正的对象。这个对象有一个明显的特征就是它具有非常多的状态特征和行为特征。比如一个人是一个对象,他在一生中会经历无数个交互场景,在这个过程中,每个人的行为特征会不断增多,大部分行为是通过后天学习得到的,只有少数行为是先天就具有的;另一方面,对于状态特征也是在时不时的变化,比如你的身高、体重,等等。最后,人因为会参与到不同的交互场景,会导致和他关联的各种关联信息也会不断增多,比如你去上大学,老师给你一张借书卡,此时你就拥有了一张借书卡,可以理解为你多了一个关联信息;哪一天你去参加英语四级考试,考了70分,然后你拥有了一本四级考试证书,上面写这成绩为70分,此时你也同样多了一个关联信息,就是一本英语四级考试证书;

这里我想表达的主要观点是:现实生活中的对象:1)兼具各种场景下的所有状态和行为特征;2)固有状态会时不时的变化,通过参与交互场景还会增加一些关联信息;3)行为会不断增多,一般是通过学习得到;因此,我们从中可以知道,现实生活中的对象肯定不是我们设计软件时候的对象,因为它是如此的复杂,包含了或关联了非常多的状态特征和行为特征;

 

2. 面向对象分析阶段时的对象:

既然是分析阶段,那我们就不要过多的考虑任何设计阶段的思想。我觉得在分析阶段,我们在分析对象时主要考虑两个方面:1)对象的状态特征变化规律;2)对象的行为特征变化规律;分析阶段,我们往往从某个场景出发,分析该场景中有哪些“对象”,此时的“对象”之所以加双引号是因为它不是真正的对象,而是真正的对象的某个方面,我们在某个场景下只关心对象的某个方面;我觉得分析阶段的对象和现实生活中的对象应该是一致的,或者至少是逻辑上是一致的。也就是说,在面向对象的分析阶段,我们应该将现实生活中我们所理解的对象的一切特征在脑子里描述清楚。比如同一个人,它在不同的场景下(一个场景代表了一个考虑问题的边界)会参与不同的交互活动。 这句话体现的含义是:1)同一个对象会参与不同的场景,行驶各种交互行为;2)同一个对象我们会根据我们不同的认识角度,对同一个对象的关注角度的不同,将其理解为不同的类型或角色;比如一个人,在家里可能是父亲,在公司可能是职员,在比赛场上可能是运动员。但无论我们给这个人授予什么样的称谓,这个人始终是同一个对象。所以,在面向对象的分析阶段,对象给我们的感觉是它在不停的变换其类型或角色;上面在谈到什么是真正的现实生活中的对象时提到,对象在参与到交互活动后会多出一些关联信息,这些信息是属于谁的呢?答案是:这些信息属于扮演了某个角色的对象的;之所以强调扮演了某个角色,是因为想让大家明确对象一定是在扮演某个角色参与到某个场景交互活动后才具有那些关联信息的。总结:我觉得在面向对象的分析阶段,我们分析的要点是:1)站在现实生活中真正的对象的角度去理解对象的状态特征和行为特征的变化规律;2)理解真正的对象和对象的某一个方面(即我们所关心的“对象”),3)理解同一个对象会扮演不同角色参与到不同交互场景;4)理解对象的关联信息如何产生,关联信息是属于谁的;

 

3. 面向对象设计阶段时的对象: 

首先说一下,目前的编程语言实现对象时,是以哪些方式让创建对象的。1)C#等基于类型的静态语言,类型规定了对象可以具有的状态特征和行为特征,对象的一切状态和行为都是由其所属的类型确定的;这又一个很明显的好处时,我们在任何时候都知道对象的类型或接口,从而就能明确知道其数据结构,也就知道对象的状态,从而可以方便的持久化对象的状态或者重建对象;但这种为对象带来状态和行为特征的设计思路同时也有一个缺点就是对象的类型或其表现出来的接口无法更改。这点是违背“真正的对象”或者“分析阶段的对象”的特征的;2)javascript等弱类型的动态语言,这种语言认为对象无类型,对象的状态和行为不需要从类型为模板获取,状态和行为可以随时附加到某个对象上。这种思路其实很好,因为很符合上面提到的真正的对象的状态特征与行为特征的变化规律。但是这种语言也有一些致命的缺点:1)由于没有类型,导致无法在使用时明确知道其具有哪些状态和行为,这会增加编程出错的可能性,只有在运行阶段在会检测到访问了不存在的状态或行为;2)同样是弱类型的原因,对象无法被持久化,因为不知道要持久化哪些状态,同样,更不用说重建对象了;所以,基于这两个缺点,我觉得动态语言不适合在服务器端大量使用去做工程实现业务逻辑,而在一些不需要持久化对象状态的客户端环境,只在内存中处理逻辑的情况下使用这种语言比较适合;

 

当我们在设计软件时,如果是用C#等静态语言、基于类和接口的语言去设计对象时,该如何设计呢?在设计阶段,我觉得目标就是把分析阶段得到的对象用尽量平滑的方式转换为设计;需要把握的要点是:1)从一个基本的类创建出对象;2)用尽量平滑的设计思路去支持一个对象表现出不同类型或角色的特点;举个例子吧:

var xuehua = new Person();
xuehua.Eat(); 
//吃饭
var teacher = xuehua.ActAs<ITeacher>();//扮演教师角色
teacher.Teach(); //教书

 

xuehua这个对象首先是一个人,所以从Person这个基本类型中获取基本的状态特征和行为特征(如吃饭);然后当xuehua去教书时,他会扮演教师的角色,扮演之后他就是一个教师了,然后他就具有了教师这个角色所赋予的行为(教书)了。上面的代码看上去和真正的对象在现实生活中的变化规律类似,非常平滑;这样做有几个好处:1)强类型;2)对象交互模型与现实生活中的交互模型完全一致,所以代码非常容易懂,可读性强;3)对象不会随着参与交互场景的增多而变得臃肿和复杂,因为由于引入了角色的概念,我们将交互模型实现为对象扮演某个角色参与交互活动的方式来设计,做到了对象动态被赋予身份,从而具有与该身份相关的状态特征和行为特征;4)对象参与交互场景后所关联的一些关联信息不会直接存放在对象上,而是放在了“扮演了某个角色的对象”上,在上面的例子中就是teacher对象;

 

4. 面向对象实现阶段时的对象:

那么如何实现这样的设计呢?

var teacher = xuehua.ActAs<ITeacher>(); 

其实很简单,可以类用装饰模式来实现,我们都知道,设计模式中的装饰模式可以动态给一个对象增加状态或行为。所以在实现阶段,我们可以设计一个Teacher类,大概设计如下:

public class Teacher : ITeacher
{
    
private Person actor;

    
public Teacher(Person actor)
    {
        
this.actor = actor;
    }

    
public void Teach()
    {
        
//do the teach operation.
    }

teacher就是实现阶段的对象,而Teacher类则是实现阶段的对象的类型;可以看到Teacher类关联了一个Person对象,同时实现了ITeacher角色接口。所以ActAs,

var teacher = xuehua.ActAs<ITeacher>();

这个函数做的事情就是在内部创建一个Teacher类的实例,该实例对当前的Person对象有一个引用,然后返回。也许你会说,返回回来的teacher对象已经不是原来的xuehua对象了,而是一个新的对象,并且封装了xuehua这个对象;没错,所以说这是实现上的问题。我们在关注业务时,关心的不是当前对象的真正类型,而是关心对象的状态特征、行为特征,或者技术化一点来讲就是关心对象的交互模型,关心的是对象扮演什么角色在进行交互。

 

好了,就说这么多吧,下午要去参加知识分享。希望我的文章能带给大家一些启发。 

posted on 2011-09-10 12:08 netfocus 阅读(3244) 评论(29) 编辑 收藏

评论

#1楼 2011-09-10 12:32 dax.net      
向你学习!
 回复 引用 查看   

#2楼[楼主] 2011-09-10 14:13 netfocus      
呵呵,相互学习。
 回复 引用 查看   

#3楼 2011-09-10 14:15 dudu      
好文章!有启发!谢谢分享!
 回复 引用 查看   

#4楼 2011-09-10 17:10 吉桂昕      
受教了,还是得留个脚印。继续体会“分享一些如何从:领域、对象、角色、职责、对象交互、场景等这些方面去分析和设计具有动态行为的领域模型的经验”
 回复 引用 查看   

#5楼 2011-09-11 15:28 我想我是风      
让person实现ITeacher接口不是更好么?
 回复 引用 查看   

#6楼[楼主] 2011-09-12 15:28 netfocus      
Person不能直接实现ITeacher接口,因为:
1)如果Person实现了ITeacher接口,就意味着模型和角色捆绑在一起,但实际上我们需要的是模型应该动态被赋予某个角色;
2)如果Person实现了ITeacher接口,那么按照这样的思路,Person也还会实现其他可能出现的角色接口,那么最后会导致Person类非常臃肿,所有的交互行为全部定义在Person类中。这样的话,定不定义ITeacher接口其实也无所谓了;
3)将模型与角色动态进行绑定而不是静态绑定体现出来的OO思想是:对象在不同的场景我们关心它的角度不同,因此所体现出来的状态特征和行为特征也不同,我们需要一中动态的机制为运行中的对象动态注入行为。事实上,现实生活中的真正对象这是呈现出这样的变化规律的;
 回复 引用 查看   

#7楼 2011-09-12 23:28 我想我是风      
程序只是模拟项目所关注的一部分现实,一个教师的项目难道还关注人员那天变医生?一个项目几种人物,需求阶段就应该清楚的吧
 回复 引用 查看   

#8楼 2011-09-13 01:50 NigelD7      
好文章
 回复 引用 查看   

#9楼 2011-09-13 11:12 luofer      
@netfocus
与我心有戚戚,羡慕楼主的表述能力和文笔的功底.关注后期待楼主的持续更新.
 回复 引用 查看   

#10楼 2011-09-13 11:14 luofer      
@我想我是风
中国的项目,客户开始自己都清楚需要什么,你指望他们开始就提供清晰的角色及与之关联职责吗?
 回复 引用 查看   

#11楼 2011-09-13 17:33 chris-shao      
适配器模式吧
 回复 引用 查看   

#12楼 2011-09-13 22:20 无解      
收藏,下次上网时候仔细拜读~
 回复 引用 查看   

#13楼 2011-09-14 18:40 极地雪狼      
面向对象中的对象是根据场景来的,根据对象存在的上下文来确定对象的属性和方法。现实中的对象是一种存在,只要定义了,就破坏了对象的完整性,因为定义永远是在认知的范围内的说明。
 回复 引用 查看   

#14楼[楼主] 2011-09-14 20:29 netfocus      
@极地雪狼
你说的对,所以OO中的对象只是现实生活中对象的我们所关注的一个方面。
 回复 引用 查看   

#15楼 2011-09-15 12:31 小小果果      
xuehua.ActAs<ITeacher>();
楼主这行代码有点不懂,求解释,菜鸟谢谢!
 回复 引用 查看   

#16楼[楼主] 2011-09-15 13:21 netfocus      
@小小果果
这行代码的意思就是,xuehua这个对象扮演ITeacher这个角色。从代码的角度来理解就是,将xuehua这个对象转换为一个实现了ITeacher接口的对象;
 回复 引用 查看   

#17楼 2011-09-15 14:49 淫光初学者      
学习了。。之前看过博主的文章这点已经启发到了
希望博主能更多的写些这样的好文章
能受到进一步更深的启发
 回复 引用 查看   

#18楼 2011-09-17 08:18 richardzeng      
"同样是弱类型的原因,对象无法被持久化,因为不知道要持久化哪些状态,同样,更不用说重建对象了;"

这个地方我不赞同,弱类型的语言也可以持久化和重建的,比如javascript就可以把对象持久化,对象的持久化不需要知道对象的有什么类型的状态,它自己应该负责自己的持久化问题。重建也没有问题的,javascript不久可以从json文本格式重建为javascript对象吗?

另外你的总结我也有得到更深的启发和思考,类型只是对象的一个模板, 提供状态和行为的模板,类型不是面向对象的核心,是形式上,所以类型不是面向对象的必要条件,这可以从javascript理解。
 回复 引用 查看   

#19楼[楼主] 2011-09-17 08:55 netfocus      
@richardzeng
是的,你说的很正确。弱类型的语言如javascript确实可以持久化,但只有它自己才知道如何持久化,因为别人不知道它的当前状态是什么,或者至少需要当前需要被持久化的javascript对象告诉别人如何获取我当前的所有状态这样别人才能把它的状态持久化到持久层;同样,就像你所说,重建对象也可以通过json重建。虽然确实可以持久化或重建,但是因为弱类型的原因,持久化或重建对象用无法用一些如ORM之类的工具来透明化处理,所以这给持久化或重建在一定程度上带来了麻烦。所以我觉得弱类型的语言不太适合做大型复杂的业务系统,而静态语言比较适合;

关于对象、状态、行为、交互、类这些东西的思考,我近期会出一篇文章用来表述我最新的领悟成果。
 回复 引用 查看   

#20楼 2011-09-24 17:40 leizisdu      
谢谢楼主的讲解与分享~~
 回复 引用 查看   

#21楼 2011-09-25 22:50 Botcher      
想不通actas函数怎么实现,生成新实例不就和具体的ITeacher实现绑定了吗?
 回复 引用 查看   

#22楼 2011-09-27 16:36 搏击的小船      
@Botcher
可以依赖接口,不违反面向对象原则
 回复 引用 查看   

#23楼 2011-10-08 20:20 永远的阿哲      
学习了
 回复 引用 查看   

#24楼 2011-10-10 09:17 focusJ      
javascript等弱类型的动态语言,这种语言认为对象无类型,对象的状态和行为不需要从类型为模板获取,状态和行为可以随时附加到某个对象上。
这句话让我对javascript面向对象有了一点突破,以前一直对javascript的面向对象模模糊糊,现在有点感觉了!
楼主文章写得不错,文笔很好!!与我在jdon上面看的对DCI描述很相似。不论是对象,还是场景中的数据,都与自己特定的场景,不要眉毛胡子一把抓,所以教师这个对象就不应该考虑他是不是会有饲养员的行为。对象是活的,但是场景相对来说是死的,所以对象放入场景中必须要对对象的“活性”加以控制。
 回复 引用 查看   

#25楼 2011-10-11 18:26 花花骑士      
写得非常好的文章
 回复 引用 查看   

#26楼 2011-10-22 12:53 Cn丶坏小子      
小菜菜菜菜鸟,现在理解不懂, 有一点点收获,
 回复 引用 查看   

#27楼 2011-10-28 00:08 kaleroy      
受益匪浅!!
 回复 引用 查看   

#28楼 2011-11-11 16:40 CreazyWindy      
只看了一点点,确实是好文档
 回复 引用 查看   

#29楼 2012-01-31 19:31 AlfredLee      
面向对象和面向过程只是老外提出来的一些理论。自己要正确认识。千万别盲从。有时候面向过程(函数式编程)可能对得到的大量数据处理更加流畅。加油。
 回复 引用 查看