第一章:C#面向对象编程
第一节:抽象
什么是面向对象的抽象?这里不说纯理论的知识,其实说白了,就是从我们自身观察者角度找出类和对象,构建对象模型。
在实际操作中,我们只需要记住下面几个特质即可:
1. 模块间的关联强度应该是最低的;(低耦合) [重要]
2. 模块内各个元素的关联强度是紧密的;(高内聚) [重要]
3. 抽象足够多的特征来进行有意义和有效的交互; [了解]
4. 类和模块的接口记录全部特征; [了解]
5. 访问抽象底层表现形式才能够有效地实现操作。 [了解]
第二节:封装
我们熟知,C#的class对象中,主要分为field(字段)、property(属性)和method(方法)。
如:
1 public class Person 2 { 3 #region Fields 4 private string _name; 5 private bool? _sex; 6 #endregion 7 8 #region Constructors 9 public Person(string name) 10 : this(name, null) { } 11 12 public Person(string name, bool? sex) 13 { 14 this._name = name; 15 this._sex = sex; 16 } 17 #endregion 18 19 #region Properties 20 public string Name 21 { 22 get { return this._name; } 23 } 24 25 public bool? Sex 26 { 27 get { return this._sex; } 28 } 29 #endregion 30 31 #region Methods 32 private string GetSexName(bool? value) 33 { 34 string sexName = null; 35 switch (value) 36 { 37 case null: 38 sexName = "undefined"; 39 break; 40 case true: 41 sexName = "male"; 42 break; 43 case false: 44 sexName = "female"; 45 break; 46 default: 47 break; 48 } 49 return sexName; 50 } 51 52 public void Speak(string words) 53 { 54 Console.WriteLine(string.Format("{0}({1}) says: {2}", this._name, this.GetSexName(this._sex), words)); 55 } 56 #endregion 57 }
我们需要注意的封装对象的修饰符,分别用修饰符public, internal, protected, private设定,可作用于类的字段,属性和方法,甚至于类对象本身。具体的访问权限如下:
public: 所有对象都可以访问;
protected internal:同一个程序集内的对象,或者该类对象以及子类可访问;
internal:同一个程序集的对象可访问;
protected:该类对象以及其子类对象可访问;
private: 只有该类对象本身在对象内部可访问;
对Person类内部代码的解析(针对于需掌握基础知识的读者)
#region Your Description Here
#endregion
折叠代码用,若代码很长,我们可以用此方式折叠代码。折叠后,在VS编辑器可以折叠,折叠后只会看到对该折叠部分的描述文字,即:Your Description Here
1. field定义
_name和_sex是两个字段,并定义为private,即:只能在该类对象内部可访问;
其中:bool? 这个是对bool类型的一个扩展。我们所熟知的bool是一个值类型,在其后加上"?",即是一个新的数据类型,在bool的基础上扩展为可为null值的数据类型(引用类型)。
我们可以从下面的GetSexName函数略知其常见用法:
1 private string GetSexName(bool? value) 2 { 3 string sexName = null; 4 if (value == null) 5 { 6 sexName = "undefined"; 7 } 8 else 9 { 10 sexName = value.Value ? "male" : "female"; 11 } 12 return sexName; 13 }
2. constructor定义
定义了两个构造函数(constructor)
1 public Person(string name) 2 : this(name, null) { } 3 4 public Person(string name, bool? sex) 5 { 6 this._name = name; 7 this._sex = sex; 8 }
我们可以在实例化的时候,有两种选择。一种是传一个参数name,另一种是传两个参数name和sex。
若只传一个参数,则会选择第一个构造函数:
public Person(string name) : this(name, null) { }
其中,该构造函数会再次调用两个参数的构造函数,即内部构造函数间可用上述代码的方式调用。若该构造函数内部有自身的逻辑,那么,这些逻辑会在调用完:this(...)函数后再执行。
3. Property定义
1 public string Name 2 { 3 get { return this._name; } 4 } 5 6 public bool? Sex 7 { 8 get { return this._sex; } 9 }
只定义了get,并为定义set
如若想要外部可对property进行赋值,可加上set,例Sex属性:
1 public bool? Sex 2 { 3 get { return this._sex; } 4 set { this._sex = value; } 5 }
4. Method定义
定义了两个函数,一个是public void Speak(string words),另一个是private string GetSexName(bool? value)
这里,我们要新增一个知识点,即一个针对函数传参的语法糖,例Speak函数:
1 public void Speak(string words="Hello, world!") 2 { 3 Console.WriteLine(string.Format("{0}({1}) says: {2}", this._name, this.GetSexName(this._sex), words)); 4 }
细细对照,可发现在Speak函数传参words的地方,有一个预定义为"Hello, world!"的值。
上面的代码即类似于下面的函数重载效果:
1 public void Speak() 2 { 3 this.Speak("Hello, world!"); 4 } 5 6 public void Speak(string words) 7 { 8 Console.WriteLine(string.Format("{0}({1}) says: {2}", this._name, this.GetSexName(this._sex), words)); 9 }
两种写法,我们在调用的时候,都可以传words参数的值,也可以不写,效果是一样的。但前面的那种写法更加简洁明了,现多被广泛使用。