属性是字段向方法的过渡
 

1public class Person
2{
3
4public int age;//直接公开字段,无法控制用户输入非法的值
5
6
7//Java模式的对Age控制方式,需要两个方法,Get和Set。麻烦麻烦阿!
8 public int GetAge()
9{
10return Age;
11 }

12
13public void SetAge(int personAge)
14{
15if (personAge < 18)
16{
17 personAge = 18;
18 }

19if (personAge>81)
20{
21 personAge = 81;
22 }

23 age = personAge;
24 }

25
26//C#模式的Age控制方式,Set和Get是属性的两个访问器,管理方便
27 public int Age
28{
29set
30{
31if (value < 18)
32{
33 value = 18;
34 }

35if (value > 81)
36{
37 value = 81;
38 }

39 age = value;
40 }

41get
42{
43return age;
44 }

45
46 }

47
48 }

现在我们来看一个应用,描述部门和员工的一对多的关系。先看一个错误的设计:

 

1 public class Space
2{
3
4public static void Main(string[] args)
5{
6 Department dep = new Department();
7//错误一,Staffs所存储的值类型无法被控制。Staffs又可以放字符串,又可以放对象 数据无法统一。
8 dep.Staffs.Add("leo"); //放字符串
9 dep.Staffs.Add(new Staff("King")); //放对象
10
11//错误二,一旦Department对Staffs的设计改变(比如用数组描述),遍历代码就要改变
//遍历1:类Department将Staffs描述为字符串
12 for (int i = 0; i <= dep.Staffs.Count - 1; i++)
13{
14 System.Console.WriteLine(dep.Staffs[i]);
15 }

16
//遍历2:类Department将Staffs描述为数组
17for (int i = 0; i <= dep.Staffs.Length - 1; i++)
18{
19 System.Console.WriteLine(dep.Staffs[i]);
20 }

21
//造成用户必须根据Staffs数据描述的方式不同而编写不同的代码的原因为类Department设计不合理。
22 }

23 }

24
25public class Department
26{
27//这是一个错误的设计,向用户暴露了Staffs的数据结构
28 public System.Collections.ArrayList Staffs = new System.Collections.ArrayList();
29 }

30
31public class Department
32{
33//这是一个错误的设计,向用户暴露了Staffs的数据结构
34 public Staff[] Staffs = new Staff[] { new Staff("leo"), new Staff("King") };
35 }

36
37public class Staff
38{
39public Staff(string name)
40{
41 Name = name;
42 }

43
44public string Name;
45 }


好的设计方法是向用户关闭数据结构的细节
 

1 public class Space
2{
3
4public static void Main(string[] args)
5{
6 Department dep = new Department();
7//无论将来Staffs的数据结构有什么变化,调用的代码不会有变化
8 dep.AddStaff(new Staff("leo"));
9 dep.AddStaff(new Staff("King"));
10for (int i = 0; i <= dep.StaffsCount - 1;i++ )
11{
12 System.Console.WriteLine(dep.GetStaffFromIndex(i).Name);
13 }

14 }

15 }

16
17public class Department
18{
19//这是正确的设计
20 private System.Collections.ArrayList Staffs = new System.Collections.ArrayList(); //private隐藏了Staffs的数据结构
21
22public int StaffsCount //统一遍历代码
23{
24get
25{
26return Staffs.Count;
27 }

28 }

29
30public int AddStaff(Staff staff) //统一Staffs的数据结构
31{
32return this.Staffs.Add(staff);
33 }

34
35public void Remove(Staff staff)
36{
37this.Staffs.Remove(staff);
38 }

39
40public Staff GetStaffFromIndex(int index)
41{
42return (Staff)this.Staffs[index];
43 }

44
45 }

46
47public class Staff
48{
49public Staff(string name)
50{
51 Name = name;
52 }

53
54public string Name;
55 }

如果我们引入索引器,那代码能更合理
 

1 public class Space
2{
3
4public static void Main(string[] args)
5{
6 Department dep = new Department();
7//无论将来Staffs的数据结构有什么变化,调用的代码不会有变化
8 dep.AddStaff(new Staff("leo"));
9 dep.AddStaff(new Staff("King"));
10for (int i = 0; i <= dep.StaffsCount - 1;i++ )
11{
12 System.Console.WriteLine(dep[i].Name); //注意下标
13 }

14 }

15 }

16
17public class Department
18{
19//这是正确的设计
20 private System.Collections.ArrayList Staffs = new System.Collections.ArrayList();
21
22public int StaffsCount
23{
24get
25{
26return Staffs.Count;
27 }

28 }

29
30public int AddStaff(Staff staff)
31{
32return this.Staffs.Add(staff);
33 }

34
35public void Remove(Staff staff)
36{
37this.Staffs.Remove(staff);
38 }

39
40public Staff this[int index]
41{
42set
43{
44 Staff[index] = value;
45 }

46get
47{
48return (Staff)Staff[index];
49 }

50 }

51
52 }


注意代码的第40的变化,不过在一个类中,只能有一个this[int index]。
注意使用了第40行的索引器,第12行可以象数组下标一样用啦。

不过,这样的设计还不完善,请看下篇,初见继承威力。