1. 引言
提起面向对象,每个程序设计者总会说出一堆自己的理解,有独特的、有偏废的,不尽而然。但是无论所云,几个基本的概念总会得到大家的首肯,它们是:类、对象、继承、封装和多态。很对,差不多就是这些概念构成了面向对象设计开发技术的基本逻辑,成为数以千万计程序设计者不懈理解和实践的标语。而实际上,理解面向对象一个重要的方法就是以实际的生活来类比对象世界,对象世界的逻辑和我们生活的逻辑形成对比的时候,我们的理解将会更有亲切感,深入程度自然也就不同以往,因为谁能对生活没有理解呢?
本文,就从对象这一最基本元素开始,进行一次深度的对象旅行,把.NET面向对象世界中的主角来次遍历式曝光。 把对象的世界和人类的世界进行一些深度类比,以人类的角度来戏说对象,同时也以对象的逻辑来反思人类。究竟这种品查,会有什么样的洞悉,看我且来演义。
2 出生
对象就像个体的人,从生而来,入世而归。
我们对对象的戏说就从对象之生开始吧。首先,看看一个对象是如何出生的:
Person aPerson = new Person("Xiao Wang", 27);
那么一个人又是如何出生呢?每个婴儿随着一声啼哭来到这个世界,鼻子是鼻子、嘴巴是嘴巴,呱呱落地,一个可爱的生命来到人间。可见,怀胎十月是人出世之前的成长过程,母亲为孩子提供了一切出世为人的环境,这个过程就是一次实实在在的生物化构造。同样的道理,对象的出生,也是一次完整的构造过程:首先会在内存中分配一定的存储空间;然后初始化其附加成员,就像给人取个标识的姓名一样;最后,再调用构造函数执行初始化,这样一个对象实体就完成了其出生的过程,例如上例中我们为aPerson对象初始化了姓名和年龄。
正如人出生之时,一身赤裸没有任何的附加品,一切的所属品将在生命的旅程中逐渐完善,生不带来就是这个意思。对象的出生也只是完成了对必要字段的初始化操作,其他的数据要等后面的操作来完成。例如对属性赋值,通过方法获取必要的信息等待。
3 旅程
新生的孩子一经出世,就来到人间,加入了人类这个大家庭,社会这个大环境。从而经历一次在人类伦理与社会规则的双重标准中生活,这就是人的旅程。同理,对象也一样。
最为个体的人,首先是有类型之分的,农民、工人、学者、官员等等,为的是方便管理,所以形成的社会规则就是农民一般居住在农村,工人一般生活在城市,学者探讨知识,官员管理国家。
对象也是一样,是有类型的,例如整型、字符型等等。当然,分类的标准不同,得到的角度也会不同,但是常见的分类就是值类型和引用类型两种。其依据是对象在运行时在内存中的位置,值类型位于线程的堆栈,而引用类型位于托管堆。正如,农民也可以进城生活,工人也可以隐居于乡村,值类型和引用类型的角色也会发生转变,这个过程在面向对象中称为装箱与拆箱。这点倒是有些变相的贴切,农民进城,工人回乡,不都得把行李装进箱子里折腾嘛。
作为人,我们都是有属性的,例如你的名字、年龄、籍贯等等,用于描述了你的状态信息,同时每个人也有不同的行为来操作自己的属性,实现了与外界进行交互的手段。对象的字段、属性就是我们自己的标签,例如人的姓名、性别、年龄和身份;而方法就是操作这些标签的行为。人的名字来自于父母,是每个人在出生之时构造的,这和对象产生时给字段赋值一样。但是每个人都有随时更名的权力,这种操作自己名称的行为,我们称之为方法。在面向对象中,可以像这样来完成:
aPerson.ChangeName("Apple Boy");
所以,对象的旅行过程,在某种程度上就是以方法与外界进行交互,从而达到改变对象状态信息的过程,这也和人的生存过程是一致的。
人与人的交互是通过语言。既然生则为人,就必然和这个世界的其他人发生交流与切磋,从而才构成一个流动的社会群体,这应该是社会学的基本常识。在对象的世界里,你得绝对相信对象之间也是相互关联的,不同的对象之间发生着不同的交互性操作,那么对象的交互是通过什么方式呢?对象的交互方式被记录在一个称为设计模式的魔法书中,当你不解以什么样的方式建立对象与对象之间的关系时,学习前人的经验是最好的选择,有时候弯路就是这样变成捷径的。
下面,我们简要的分析一下对象到底旅行在什么样的世界里?
对象的载体是CLR,而人的载体是社会。CLR提供了对象赖以生存的规则,称之为语法,例如类型、继承、多态、垃圾回收等等,对象世界建立了真正的法制秩序;而社会提供了人行走江湖的秩序,称之为法律,例如版权、人权、产权,这是我们力图实现的社会秩序。
人类社会就是系统架构,也是分层的。上层建筑代表管理与民主,而人民大众则在底层完成价值的创造。上层建筑靠协约与法律来管理个体的人,在对象世界中,这称之为接口。面向接口的编程就是以接口方式来抽象变化,从而形成体系。而人类不是也以法律手段来维系社会体系的运作和秩序吗,这是它们的神似。
由此可见,对象的旅行就是这样一个过程,在一定的约定与规则下,通过方法进行彼此的交互操作,从而达到改变本身状态的目的。虽然这种概括未免牵强,但是从最简单的方式理解实际情况,也确实如此,这些体会的确可以从人的旅程中得到启示。
4 插曲
接下来,我们以几个最熟悉的概念来进一步阐释对象世界与人类世界的和谐统一。
关于继承。人的社会中,继承一般发生在有血缘关系的族群中。最直接的例子一般是,儿子继承父亲,包括姓氏、基因、财产和一切可以遗留的东西。但并不代表可以继承所有,因为父亲隐私的那一部分属于父亲独有,不可继承。当然,也可能是继承于族群的其他人,视实情而定。而在面向对象中,继承无处不在,子类继承父类,以访问权限来实现不同的控制规则,称为访问级别,主要包括:
访问修饰符
访问权限
pubic
对访问成员没有限制,属于最高级别访问权限
protect
访问包含类或者从包含类派生的类。
internal
访问仅限于程序集。
protected internal
访问仅限于从包含类派生的当前程序集或类型。也就是同一个程序集的对象,或者该类及其子类可以访问。
private
访问仅限于包含类型。
这些规则,以人的视角来理解,我们以公司的体制来举例说明,将公司职权的层级与面向对象的访问权限层级做以类比,应该是这个样子:
·public,具有最高的访问权限,就像是公司的总经理具有最高的决策权与管理权,因此public开发性最大,是的不管是同一个程序集或者不管是否继承,都可以访问;
·protected,类似于公司业务部门经理的职责,具有对本部门的直接管辖权,在面向对象中就体现为子类继承这种纵向关系的访问约定,也就是只要继承了该类,则其对象就有访问父类的权限,而不管这两个具有继承关系的类是否在同一个程序集中;
·internal,具有类比意义的就是internal类似于公司的职能部门的职责,不管是否具有上下级的隶属关系,人力部都能管辖所有其他部门的员工考勤。这是一种横向的职责关系,在面向对象中用来表示同一程序集的访问权限,只要是隶属于同一程序集,则对象即可访问其属性,而不管是否存在隶属关系。
·protected internal,可以看作是protected internal的并集,就像公司中掌管职能部门的副总经理,从横向到纵向都有管理权。
·private,具有最低的访问权限,就像公司的一般员工,管好自己就行了。因此,对应于面向对象的开发性最小。
另外,对象中的继承的目的是提高软件复用,而人类中的继承,不也是现实中的复用吗?
关于多态。人的世界中,我们常常在不同的环境中表现为不同的角色,并且遵守不同的规则。例如在学校我们是学生,回到家里是儿女,而在车上又是乘客,同一个人在不同的情况下,代表了不同的身份,在家里你可以撒娇但是在学校你不可以,在学校你可以打球但在车上你不可以。所以这种身份的不同,带来的是规则的差异。在面向对象中,我们该如何表达这种复杂的人类社会学呢?显然,我们让不同角色的Person继承同一个接口:IPerson。然后将不同的实现仍给不同角色的人自行负责,不同的是PersonAtHome在实现时可能是CanBeSpoil (),而PersonOnBus可能是BuyTicket()。不同的角色实现不同的规则,也就是接口协定。在使用上的规则是这个样子:
IPerson aPerson = new PersonAtHome();
aPerson.DoWork();
另一个角色又是这个样子:
IPerson bPerson = new PersonOnBus();
bPerson.DoWork();
由此带来的好处是显而易见的,我们以IPerson代表了不同角色的人,在不同的情况下实现了不同的操作,而把决定权交到系统自行处理。这就是多态的魅力,其乐无穷中,带来的是面向对象中最为重要的特性体验。记住,很重要的一点是,DoWork在不同的实现类中体现为同一命名,不同的只是实现的内部逻辑。
由此可见,以我们自己的角度来阐释技术问题,有时候会有意想不到的收获,否则你将被淹没在诸如为什么以这种方式来实现复用的叫喊中不能自省。换一个角度,理一种思路,眼界与思路都会更加开阔。
5 消亡
对象和人,有生必然有死。在对象的世界里,它的生命是由GC控制的,而人的世界我们把GC称作为自然规律。不死的人,就像进入死循环的对象,都是违反规则的,终究被Kill的命运。
在这一部分,我们首先观察对象之死,以此反思和体味人类入世的哲学,两相比较,也会给我们更多关于自己的启示。对象的生命周期由GC控制,其规则大概是这样:GC管理所有的托管堆对象,当内存回收执行时,GC检查托管堆中不再被使用的对象,并执行内存回收操作。不被应用程序使用的对象,指的是对象没有任何引用。关于如何回收、回收的时刻,以及遍历可回收对象的算法,是个较为复杂的问题,我们将以专题加以讨论。不过,从这个回收过程中,足以给人类更多的启示来反思,自己生存与世的道理,大自然就是那么看不见的GC,要想努力的活着,就不要使自己变成可回收的垃圾,而是有益与人的人。
5. 结论
程序世界其实和人类世界有很多相似的地方,本文就以这种类比的方式来诠释程序世界的主角如何类似于人类社会的主角,以演化推进的手段来描述面向对象程序世界的主角:对象由生而死的全过程,借以品味一下复杂的人类世界主角。人,也是可以简单的。所以这是一种相互的较量,也是一种相互的借鉴。
提起面向对象,每个程序设计者总会说出一堆自己的理解,有独特的、有偏废的,不尽而然。但是无论所云,几个基本的概念总会得到大家的首肯,它们是:类、对象、继承、封装和多态。很对,差不多就是这些概念构成了面向对象设计开发技术的基本逻辑,成为数以千万计程序设计者不懈理解和实践的标语。而实际上,理解面向对象一个重要的方法就是以实际的生活来类比对象世界,对象世界的逻辑和我们生活的逻辑形成对比的时候,我们的理解将会更有亲切感,深入程度自然也就不同以往,因为谁能对生活没有理解呢?
本文,就从对象这一最基本元素开始,进行一次深度的对象旅行,把.NET面向对象世界中的主角来次遍历式曝光。 把对象的世界和人类的世界进行一些深度类比,以人类的角度来戏说对象,同时也以对象的逻辑来反思人类。究竟这种品查,会有什么样的洞悉,看我且来演义。
2 出生
对象就像个体的人,从生而来,入世而归。
我们对对象的戏说就从对象之生开始吧。首先,看看一个对象是如何出生的:
Person aPerson = new Person("Xiao Wang", 27);
那么一个人又是如何出生呢?每个婴儿随着一声啼哭来到这个世界,鼻子是鼻子、嘴巴是嘴巴,呱呱落地,一个可爱的生命来到人间。可见,怀胎十月是人出世之前的成长过程,母亲为孩子提供了一切出世为人的环境,这个过程就是一次实实在在的生物化构造。同样的道理,对象的出生,也是一次完整的构造过程:首先会在内存中分配一定的存储空间;然后初始化其附加成员,就像给人取个标识的姓名一样;最后,再调用构造函数执行初始化,这样一个对象实体就完成了其出生的过程,例如上例中我们为aPerson对象初始化了姓名和年龄。
正如人出生之时,一身赤裸没有任何的附加品,一切的所属品将在生命的旅程中逐渐完善,生不带来就是这个意思。对象的出生也只是完成了对必要字段的初始化操作,其他的数据要等后面的操作来完成。例如对属性赋值,通过方法获取必要的信息等待。
3 旅程
新生的孩子一经出世,就来到人间,加入了人类这个大家庭,社会这个大环境。从而经历一次在人类伦理与社会规则的双重标准中生活,这就是人的旅程。同理,对象也一样。
最为个体的人,首先是有类型之分的,农民、工人、学者、官员等等,为的是方便管理,所以形成的社会规则就是农民一般居住在农村,工人一般生活在城市,学者探讨知识,官员管理国家。
对象也是一样,是有类型的,例如整型、字符型等等。当然,分类的标准不同,得到的角度也会不同,但是常见的分类就是值类型和引用类型两种。其依据是对象在运行时在内存中的位置,值类型位于线程的堆栈,而引用类型位于托管堆。正如,农民也可以进城生活,工人也可以隐居于乡村,值类型和引用类型的角色也会发生转变,这个过程在面向对象中称为装箱与拆箱。这点倒是有些变相的贴切,农民进城,工人回乡,不都得把行李装进箱子里折腾嘛。
作为人,我们都是有属性的,例如你的名字、年龄、籍贯等等,用于描述了你的状态信息,同时每个人也有不同的行为来操作自己的属性,实现了与外界进行交互的手段。对象的字段、属性就是我们自己的标签,例如人的姓名、性别、年龄和身份;而方法就是操作这些标签的行为。人的名字来自于父母,是每个人在出生之时构造的,这和对象产生时给字段赋值一样。但是每个人都有随时更名的权力,这种操作自己名称的行为,我们称之为方法。在面向对象中,可以像这样来完成:
aPerson.ChangeName("Apple Boy");
所以,对象的旅行过程,在某种程度上就是以方法与外界进行交互,从而达到改变对象状态信息的过程,这也和人的生存过程是一致的。
人与人的交互是通过语言。既然生则为人,就必然和这个世界的其他人发生交流与切磋,从而才构成一个流动的社会群体,这应该是社会学的基本常识。在对象的世界里,你得绝对相信对象之间也是相互关联的,不同的对象之间发生着不同的交互性操作,那么对象的交互是通过什么方式呢?对象的交互方式被记录在一个称为设计模式的魔法书中,当你不解以什么样的方式建立对象与对象之间的关系时,学习前人的经验是最好的选择,有时候弯路就是这样变成捷径的。
下面,我们简要的分析一下对象到底旅行在什么样的世界里?
对象的载体是CLR,而人的载体是社会。CLR提供了对象赖以生存的规则,称之为语法,例如类型、继承、多态、垃圾回收等等,对象世界建立了真正的法制秩序;而社会提供了人行走江湖的秩序,称之为法律,例如版权、人权、产权,这是我们力图实现的社会秩序。
人类社会就是系统架构,也是分层的。上层建筑代表管理与民主,而人民大众则在底层完成价值的创造。上层建筑靠协约与法律来管理个体的人,在对象世界中,这称之为接口。面向接口的编程就是以接口方式来抽象变化,从而形成体系。而人类不是也以法律手段来维系社会体系的运作和秩序吗,这是它们的神似。
由此可见,对象的旅行就是这样一个过程,在一定的约定与规则下,通过方法进行彼此的交互操作,从而达到改变本身状态的目的。虽然这种概括未免牵强,但是从最简单的方式理解实际情况,也确实如此,这些体会的确可以从人的旅程中得到启示。
4 插曲
接下来,我们以几个最熟悉的概念来进一步阐释对象世界与人类世界的和谐统一。
关于继承。人的社会中,继承一般发生在有血缘关系的族群中。最直接的例子一般是,儿子继承父亲,包括姓氏、基因、财产和一切可以遗留的东西。但并不代表可以继承所有,因为父亲隐私的那一部分属于父亲独有,不可继承。当然,也可能是继承于族群的其他人,视实情而定。而在面向对象中,继承无处不在,子类继承父类,以访问权限来实现不同的控制规则,称为访问级别,主要包括:
访问修饰符
访问权限
pubic
对访问成员没有限制,属于最高级别访问权限
protect
访问包含类或者从包含类派生的类。
internal
访问仅限于程序集。
protected internal
访问仅限于从包含类派生的当前程序集或类型。也就是同一个程序集的对象,或者该类及其子类可以访问。
private
访问仅限于包含类型。
这些规则,以人的视角来理解,我们以公司的体制来举例说明,将公司职权的层级与面向对象的访问权限层级做以类比,应该是这个样子:
·public,具有最高的访问权限,就像是公司的总经理具有最高的决策权与管理权,因此public开发性最大,是的不管是同一个程序集或者不管是否继承,都可以访问;
·protected,类似于公司业务部门经理的职责,具有对本部门的直接管辖权,在面向对象中就体现为子类继承这种纵向关系的访问约定,也就是只要继承了该类,则其对象就有访问父类的权限,而不管这两个具有继承关系的类是否在同一个程序集中;
·internal,具有类比意义的就是internal类似于公司的职能部门的职责,不管是否具有上下级的隶属关系,人力部都能管辖所有其他部门的员工考勤。这是一种横向的职责关系,在面向对象中用来表示同一程序集的访问权限,只要是隶属于同一程序集,则对象即可访问其属性,而不管是否存在隶属关系。
·protected internal,可以看作是protected internal的并集,就像公司中掌管职能部门的副总经理,从横向到纵向都有管理权。
·private,具有最低的访问权限,就像公司的一般员工,管好自己就行了。因此,对应于面向对象的开发性最小。
另外,对象中的继承的目的是提高软件复用,而人类中的继承,不也是现实中的复用吗?
关于多态。人的世界中,我们常常在不同的环境中表现为不同的角色,并且遵守不同的规则。例如在学校我们是学生,回到家里是儿女,而在车上又是乘客,同一个人在不同的情况下,代表了不同的身份,在家里你可以撒娇但是在学校你不可以,在学校你可以打球但在车上你不可以。所以这种身份的不同,带来的是规则的差异。在面向对象中,我们该如何表达这种复杂的人类社会学呢?显然,我们让不同角色的Person继承同一个接口:IPerson。然后将不同的实现仍给不同角色的人自行负责,不同的是PersonAtHome在实现时可能是CanBeSpoil (),而PersonOnBus可能是BuyTicket()。不同的角色实现不同的规则,也就是接口协定。在使用上的规则是这个样子:
IPerson aPerson = new PersonAtHome();
aPerson.DoWork();
另一个角色又是这个样子:
IPerson bPerson = new PersonOnBus();
bPerson.DoWork();
由此带来的好处是显而易见的,我们以IPerson代表了不同角色的人,在不同的情况下实现了不同的操作,而把决定权交到系统自行处理。这就是多态的魅力,其乐无穷中,带来的是面向对象中最为重要的特性体验。记住,很重要的一点是,DoWork在不同的实现类中体现为同一命名,不同的只是实现的内部逻辑。
由此可见,以我们自己的角度来阐释技术问题,有时候会有意想不到的收获,否则你将被淹没在诸如为什么以这种方式来实现复用的叫喊中不能自省。换一个角度,理一种思路,眼界与思路都会更加开阔。
5 消亡
对象和人,有生必然有死。在对象的世界里,它的生命是由GC控制的,而人的世界我们把GC称作为自然规律。不死的人,就像进入死循环的对象,都是违反规则的,终究被Kill的命运。
在这一部分,我们首先观察对象之死,以此反思和体味人类入世的哲学,两相比较,也会给我们更多关于自己的启示。对象的生命周期由GC控制,其规则大概是这样:GC管理所有的托管堆对象,当内存回收执行时,GC检查托管堆中不再被使用的对象,并执行内存回收操作。不被应用程序使用的对象,指的是对象没有任何引用。关于如何回收、回收的时刻,以及遍历可回收对象的算法,是个较为复杂的问题,我们将以专题加以讨论。不过,从这个回收过程中,足以给人类更多的启示来反思,自己生存与世的道理,大自然就是那么看不见的GC,要想努力的活着,就不要使自己变成可回收的垃圾,而是有益与人的人。
5. 结论
程序世界其实和人类世界有很多相似的地方,本文就以这种类比的方式来诠释程序世界的主角如何类似于人类社会的主角,以演化推进的手段来描述面向对象程序世界的主角:对象由生而死的全过程,借以品味一下复杂的人类世界主角。人,也是可以简单的。所以这是一种相互的较量,也是一种相互的借鉴。