OOP:面向对象编程,一提到面向对象,大家可能就想到类,接口。一说特性,大家可能张口就来:继承、封装、多态,那么到底什么样的对象(类)才是真正意义上的对象呢?特别是现在流行的DDD领域驱动设计思想,讲究职责划分,那么如何定义一个对象(类)它应该具有的一些特性、行为方法及承担责任成为关键。
一个看似简单的问题,其实也是耐人思索,之前也在网上看到一些人关于讨论类的设计问题,认为设计类时不应该考虑数据库,我觉得这只是实现真正的面向对象设计的基础,也是前提条件,大多数程序员之前都是受面向过程编程思想的影响,我(梦在旅途)也不例外,一个需要求下来,首先就是想它需要存哪些数据,建哪些表,要定义哪些个方法来完成数据的存储,整个过程基本是围绕数据库来进行的,我这里称之为数据驱动编程,这样开发其实也没有错,因为存在即有存在的道理,我也可以分析出这种编程的优点:开发速度快,执行效率高(没有层级或层级之前只是简单的转发),缺点是:可读性差,不利于后续的二次开发等,简单的应用程序或某个独立的核心模块使用这种编程方式我觉得也是可以的,但除此之外,我仍觉得合理的面向对象是有必要的,我这里强调合理,是不要一味的盲目采用某个框架或某种设计模式,没有最好的框架,同样也没有最好的设计模式,唯有最适合的框架与设计模式,那么如何评估框架与设计是否合适,我认为对象(类)的设计至关重要,下面就我的经验及我所看到的现象来谈谈的对象的设计问题,由于我不是什么大牛,所以难免表达有误的地方,请多包涵,当然也欢迎大家一起讨论。
1.对象是什么?
在现实生活中,对象指的是某一个客观存在的事物,它具有能识别它唯一性的属性,比如:某人的某个品牌的某个型号的汽车,我这里为什么用了多个某个,因为人+品牌+型号+汽车,就能确定具对这个对象,而不是汽车这么简单,注意汽车并不是一个对象,它只是表示的是某类事物,所以通过现实生活的分析,我们可以转换思想到编程的世界中,来分析对象与类的区别。在编程中,类就是上面的汽车,而对象则是类的实例化,识别对象的唯一性从计算机的角色讲,应该是内存堆中地址,每一个地址确定一个对象。
2.对象有什么?
对象指的是具体的某个事物,除了有识别它唯一性的属性外,它应该还有以下几个特性:
一、状态(也可以简单的称之为属性):描述一个对象的特征,这个特征可以永久的,也可以是受外界影响而改变的,比如:某人的某个品牌的某个型号的汽车,如果这辆车重新喷漆,换了一种颜色,那么的它此时的状态,颜色被改变;如果车被卖给另外一个人,那么它此时的状态,车的所有者也被改变了。
代码示例:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
|
public class Car //这是一个类 { public Car( string owner, string brand, string model, string color) { this .Owner = owner; this .Brand = brand; this .Model = model; this .Color = color; } public string Owner { get ; set ; } public string Brand { get ; set ; } public string Model { get ; set ; } public string Color { get ; set ; } } public static void Main( string [] args) { var car = new Car( "张三" , "宝马" , "B01" , "黑色" ); //这是一个对象 car.Color = "红色" ; //状态被改变 car.Owner = "李四" ; //状态被改变 } |
二、行为(也可以简单的称之为方法、函数):一个对象主动或被动去执行某种动作,比如:张三这个人,他吃饭,他看书,他睡觉等都是一种行为,包括我现在写博客也是一种行为。行为又分主动与被动,主动是指一个对象主观意识的动作,比如:张三吃饭就是主动,而被动则是需另一个对象来命令它来执行某种动作,比如:汽车启动,启动是一个行为,但它不能自己启动,需要驾驶人去通过汽车给定的启动方法与步骤来请求汽车执行启动,又或者说是取款机,取款机提供一个取款的行为,而具体什么时候来取,取多少,均由人来告诉它。
代码示例:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
|
public class Car //这是一个类 { public Car( string owner, string brand, string model, string color) { this .Owner = owner; this .Brand = brand; this .Model = model; this .Color = color; } public string Owner { get ; set ; } public string Brand { get ; set ; } public string Model { get ; set ; } public string Color { get ; set ; } public string Status { get ; private set ; } public Driver Driver { get ; set ; } public void Start() //启动方法,被动 { if ( this .Driver!= null ) { this .Status = "运行中" ; } else { throw new InvalidOperationException( "没有驾驶员,不能自动启动!" ); } } public void Stop() //启动方法,被动 { this .Status = "停止" ; } } public class Driver { public string Name { get ; set ; } public Driver( string name) { this .Name = name; } public void Drive(Car car) //驾驶,主动 { car.Driver = this ; //坐在车上 car.Start(); //启动汽车,并运行 car.Stop(); //到达终点,停止汽车 } } public class APP9 { public static void Main( string [] args) { var car = new Car( "张三" , "宝马" , "B01" , "黑色" ); //这是一个对象 var driver = new Driver( "李四" ); driver.Drive(car); //李四来开张三的车,现实生活中不能随便借车开哦!~V~ } } |
有人看了上面的代码后,可能再想,不是所有的对象都有行为吧,既然是行为,行为又代表一种动作,那么也只有能动的对象才有行为,不能动的对象就没有,是这样吗?我在写这篇博文前也思考了这个问题,开始也这样认为的,后面仔细一想,不对,应该是所有的对象都有行为,就拿不动的东西来说吧,比如一张纸,纸本身本是不能动的,但如果你把它扔起来,那么纸就具备了被动的移动方法,根据爱因斯坦的相对论,没有绝对的静止,只有相对的静止,所以就看在什么情况下,参照物是什么,有点扯远了哈,回归正题,有人可能还是不服,所有的对象都有行为方法,那我不是非要对所有的类都定义方法吗,不然就不符合真正的对象?我认为不是这样的,场景决定一个对象的状态与方法,这也是下面我将要说明的角色定位的问题,这里我可以很负责任的告诉你,我们所有的定义的对象都有行为,只是你没有意识到而矣,是什么呢?那就是构造函数与析构函数,它们就是被动的行为方法,这也是符合现实生活的对象,任何一个对象都有创建与毁灭,你敢说不是吗?请举出例子来吧!
3.对象角色定位
任何一个对象在不同的场景中应该有不同的状态及行为,比如:张三,张三在学校他是学生,具有学生的状态及行为,在公司工作他是员工,具有员工的状态及行为,取得驾照驾驶汽车,具备驾驶员的状态及行为,在图书馆看书,具备读者的状态与行为。由此可知,对象是复杂的,类是具体一些,对象存在多变性,而类则应具备不变性,可能有人不明白,我这里具体解释一下,我这里说的可变性,不是面向对象的那个多态,而是指对象角色的可变性,比如:学生类,那么它就表示学生,它不可能还表示作者,当然它可以表示人,但一般人不会这样表示,而对象则不同,正如上面我讲的张三的不同角色,他不同类的实例化,类不支持多重继承,我觉得对的,因为一个类可以代表一个角色,一个角色只能做这个角色的事情,比如:学生,他就是学习,老师,他就是教书,有人可能还会说,兼职多个角色,又是员工又是驾驶员,又是老师同时又是学生,是的,确实存在,但上面说过了,兼职的时候一个对象不可能同时做某个事情,比如:又是员工又是驾驶员,难道他同时工作又同时开车,有人说:出租车司机呀!好吧,你历害,但仍然是角色不同,出租车司机开车就是工作,当他不工作开车时,他就是驾驶员。好了,说了这么多,看是来看一下代码示例吧!
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
|
public class Person //人 { public string IdNo{ get ; set ;} public string Name { get ; set ; } public string Sex { get ; set ; } public double Height { get ; set ; } public double Weight { get ; set ; } public DateTime BirthDay { get ; set ; } } public class Post //文章 { public string Title { get ; set ; } public string Content { get ; set ; } public Author Author { get ; set ; } public DateTime CreateDatetime { get ; set ; } } public class Author : Person //角色为作者 { public void Write(Post post) { //行为 } } public class Book //书 { public string Name { get ; set ; } public DateTime IssuedDate { get ; set ; } public List<Post> Posts; } public class Library //图书馆 { public string Name { get ; set ; } public List<Book> Books { get ; set ; } public void Borrow(Reader reader, IEnumerable<Book> books) //借出书,被动 { Books.RemoveAll(b=>books.Contains(b)); //其它操作 } public void Return(Reader reader,IEnumerable<Book> books) //还入书,被动 { Books.AddRange(books); //其它操作 } } public class Reader : Person //角色为读者 { public List<Book> Books { get ; set ; } public IEnumerable<Post> Read(Book book, params int [] pages) //读书,主动 { var posts = new List<Post>(); if (pages != null ) { foreach ( int i in pages) { posts.Add(book.Posts[i]); } } else { posts = book.Posts; } return posts; } public void Borrow(IEnumerable<Book> books, Library library) //主动借书 { library.Borrow( this ,books); Books.AddRange(books); } public void Return(IEnumerable<Book> books, Library library) //主动还书 { library.Return( this , books); Books.RemoveAll(b => books.Contains(b)); } } public class Driver:Person //角色为驾驶员 { public void Drive(Car car) { car.Driver = this ; car.Start(); car.Stop(); } } public class Car { public Driver Driver { get ; set ; } public string Status{ get ; private set ;} public void Start() { this .Status= "运行中" ; } public void Stop() { this .Status= "停止" ; } } |
结 尾
我这里只是定义,没有列出运行时代码。例子比较简单,大家看一下就好了。最后要说明的是,对象虽然都有状态与行为,而且角色不同状态与行为也随之不同,但在编程的世界里,我们可以只关注我们所关注的,比如:一个博客系统,我们只关注作者,阅读者,回复者三个角色,从这三个角色应该具备的状态与行为进行设计相关的类,这样就比较符合真实的对象了,也就不会出现大家常见的:状态类-僵尸类(只有属性,无方法),方法类-孤魂野鬼类(只有方法,无属性