03 C#面向对象设计 I 知识结构:
图1 知识结构 1、类与对象 2、封装 2.1 什么是封装
把类的内部隐藏起来以防止外部看到内部的实现过程。
2.2 怎样封装
通过限制修饰符private
、protected
、public
、internal
来实现。 对类中的数据(Data)和操作(Operation)的限制修饰符: internal
:在同一程序集内部访问,相当于public
。注:internal
修饰的类,方法或属性,只要是在同一个程序集中的其它类都可以访问,如果二者不在同一命名空间,只要使用using
引用上相应的命名空间即可,这里,从另外一个方面也间接看出命名空间并不是界定访问级别的,而是保证全局的类唯一性的。
参考图文:
2.3 怎样表示
图2 Class Diagram 例1:根据下列类图实现Animal类型。
图3 Class Diagram public class Animal { public int Age; public double Weight; public void Eat () { Console.WriteLine("Animal Eat." ); } public void Sleep () { Console.WriteLine("Animal Sleep." ); } }class Program { static void Main (string [] args) { Animal al = new Animal(); al.Eat();// Animal Eat. al.Sleep();// Animal Sleep. } }
3、继承 3.1 什么是继承
子类拥有父类某些Data和Operation的过程。
3.2 怎样继承
public class Child : Parent { //… }
Child
:子类(派生类),Parent
:父类(基类)C# 只支持单继承,但可以定义一个不允许其它类继承的类。
public sealed class Name { //... }
子类与父类中数据与操作的继承关系:
父类 public
protected
private
internal
子类 public
protected
无法继承 internal
3.3 子类怎样访问父类成员
利用base
关键字。
例2:子类访问父类且父类构造函数不带参数。
public class Parent { private int _data1; // 只能被类的内部访问 protected int Data2; // 能被子类访问和继承 public int Data3; // 能被子类访问和继承 }public class Child : Parent { public Child () { base.Data2 = 2 ; base.Data3 = 3 ; } }class Program { static void Main (string [] args) { Child cld = new Child(); Console.WriteLine(cld.Data3); // 3 } }
例3:子类访问父类且父类构造函数带参数。
public class Parent { private int _data1; // 只能被类的内部访问 protected int Data2; // 能被子类访问和继承 public int Data3; // 能被子类访问和继承 public Parent (int dt1, int dt2, int dt3) { _data1 = dt1; Data2 = dt2; Data3 = dt3; } }public class Child : Parent { public Child () : base (0 , 2 , 3 ) { ; } }class Program { static void Main (string [] args) { Child cld = new Child(); Console.WriteLine(cld.Data3);// 3 } }
3.4 怎样表示
图4 继承关系 例4:根据类图实现程序代码,注意类之间的继承关系。
图5 Class Diagram public class Animal { public int Age; public double Weight; public void Eat () { Console.WriteLine("Animal Eat." ); } public void Sleep () { Console.WriteLine("Animal Sleep." ); } }public class Bird : Animal { public void Fly () { Console.WriteLine("Bird Fly." ); } }public class Dog : Animal { public void Run () { Console.WriteLine("Dog Run." ); } }public class Fish : Animal { public void Swim () { Console.WriteLine("Fish Swim." ); } }class Program { static void Main (string [] args) { Dog dog = new Dog(); dog.Run(); //Dog Run. Bird bird = new Bird(); bird.Fly(); //Bird Fly. Fish fish = new Fish(); fish.Swim(); //Fish Swim. } }
3.5 实例化
为对象分配存储空间的过程。
例5:类的实例化。
public class Animal { public int Age; public double Weight; public void Eat () { Console.WriteLine("Animal Eat." ); } public void Sleep () { Console.WriteLine("Animal Sleep." ); } }public class Dog : Animal { public void Run () { Console.WriteLine("Dog Run." ); } }class Program { static void Main (string [] args) { Animal al = new Animal(); // 实例化Animal al.Eat(); // Animal Eat. al.Sleep(); // Animal Sleep. Dog dg = new Dog(); // 实例化Dog dg.Age = 2 ; dg.Weight = 4.5 ; Console.WriteLine("Dog Infor: Age:{0},Weight:{1}" , dg.Age, dg.Weight); // Dog Infor: Age:2, Weight:4.5 dg.Sleep(); // Animal Sleep. dg.Eat(); // Animal Eat. dg.Run(); // Dog Run. } }
例6:子类与父类有重名方法。
图6 Class Diagram public class Animal { public int Age; public double Weight; public void Eat () { Console.WriteLine("Animal Eat." ); } public void Sleep () { Console.WriteLine("Animal Sleep." ); } }public class Dog : Animal { public void Eat () { Console.WriteLine("Dog Eat." ); } public void Sleep () { Console.WriteLine("Dog Sleep." ); } public void Run () { Console.WriteLine("Dog Run." ); } }class Program { static void Main (string [] args) { Animal al = new Dog(); // 子类可以实例化父类 al.Eat(); // Animal Eat.(重名方法存在问题) al.Sleep(); // Animal Sleep. Dog dg = al as Dog; //强制类型转换或Dog dg = (Dog)al; dg.Eat(); // Dog Eat. dg.Sleep(); // Dog Sleep. dg.Run(); // Dog Run. } }
注意:
Animal al = new Dog();
(正确)Dog dg = new Animal();
(错误)子类可以实例化父类,而父类不可以实例化子类,即:Dog
一定是Animal
,而Animal
不一定是Dog
。
Dog dg = al;
(错误)需要强制类型转换。Dog dg = al as Dog;
(正确)若al
不是Dog
类型,返回null。Dog dg = (Dog)al;
(正确)若al
不是Dog
类型,系统会抛出异常。4、多态 4.1 什么是多态
相同的操作(Operation),对于不同的对象,可以有不同的解释,产生不同的执行结果。
4.2 多态的分类
运行时多态:在运行时决定执行哪个类的哪个方法。(override覆写) 编译时多态:在编译时决定执行类中的哪个方法。(overload重载) 4.3 多态的实现
运行时多态:
覆写虚方法,要求方法名,形参,返回值类型必须相同。 例7:实现运行时多态的代码
图7 Class Diagram public class Animal { public int Age; public double Weight; public virtual void Eat () { Console.WriteLine("Animal Eat." ); } public virtual void Sleep () { Console.WriteLine("Animal Sleep." ); } }public class Dog : Animal { public override void Eat () { Console.WriteLine("Dog Eat." ); } public override void Sleep () { Console.WriteLine("Dog Sleep." ); } public virtual void Run () { Console.WriteLine("Dog Run." ); } }class Program { static void Main (string [] args) { Animal al = new Dog(); //在执行时,通过判断al的类型来决定执行哪个类中的哪个方法; al.Eat(); // Dog Eat. al.Sleep(); // Dog Sleep. } }
编译时多态:
public static 类型 operator 运算符(形参列表){ … } 方法重载:必须有相同的方法名、必须有不同的参数列表、可以有相同的返回值类型 例8:通过类图实现编译时多态的代码
图8 Class Diagram public class Complex { public int A; public int B; public Complex (int a, int b) { this .A = a; //this表示在内存中Complex对象 this .B = b; } public static Complex operator +(Complex c1, Complex c2) { return new Complex(c1.A + c2.A, c1.B + c2.B); } public override string ToString () { return string .Format("{0}+{1}i" , A, B); } }public class Math { public int Add (int x, int y) { return x + y; } public double Add (double x, double y) { return x + y; } public Complex Add (Complex x, Complex y) { return x + y; } }class Program { static void Main (string [] args) { Complex c1 = new Complex(1 , 2 ); Complex c2 = new Complex(3 , 4 ); Complex c3 = c1 + c2; Console.WriteLine("C1={0}" , c1); // C1=1+2i Console.WriteLine("C2={0}" , c2); // C2=3+4i Console.WriteLine("C3={0}" , c3); // C3=4+6i Math mth = new Math(); Complex c4 = mth.Add(c2, c3); //在编译时,根据参数列表决定执行哪个类中的哪个方法; Console.WriteLine("C4={0}" , c4); // C4=7+10i } }
总结:override
和overload
4.4 抽象方法与抽象类
抽象方法:可以看成没有实现体的虚方法(abstract
),即只有方法的声明,需要在子类中覆写(override
)该方法。 抽象类:含有抽象方法的类。抽象类不可以直接实例化对象。 例9:根据类图实现代码
图9 Class Diagram public abstract class Animal { public int Age; public double Weight; public abstract void Eat () ; public abstract void Sleep () ; }public class Dog : Animal { public override void Eat () { Console.WriteLine("Dog Eat." ); } public override void Sleep () { Console.WriteLine("Dog Sleep." ); } public void Run () { Console.WriteLine("Dog Run." ); } }class Program { static void Main (string [] args) { Animal al = new Dog(); al.Eat(); // Dog Eat. al.Sleep(); // Dog Sleep. ((Dog)al).Run(); // Dog Run. } }
注意:
抽象类中并没有Run方法,如果使用需要强制类型转换。
Animal al = new Animal ();
(错误)抽象类不可以直接实例化对象,系统会抛出异常。
总结:抽象方法和虚方法
例10:饲养系统
某饲养员(Raiser)在目前状态下需要饲养三种动物:狗(Dog)、鸟(Bird)和鱼(Fish),该三种动物只需要让其睡觉(Sleep)和吃饭(Eat)即可。
请设计该饲养系统,要求满足软件设计的“开闭原则”。
方案一:
图10 Class Diagram public class Bird { public void Eat () { Console.WriteLine("Bird Eat." ); } public void Sleep () { Console.WriteLine("Bird Sleep." ); } public void Fly () { Console.WriteLine("Bird Fly." ); } }public class Dog { public void Eat () { Console.WriteLine("Dog Eat." ); } public void Sleep () { Console.WriteLine("Dog Sleep." ); } public void Run () { Console.WriteLine("Dog Run." ); } }public class Fish { public void Eat () { Console.WriteLine("Fish Eat." ); } public void Sleep () { Console.WriteLine("Fish Sleep." ); } public void Swim () { Console.WriteLine("Fish Swim." ); } }public class Raiser { public void RaiseDog () { Dog dog = new Dog(); dog.Eat(); dog.Sleep(); } public void RaisBird () { Bird bird = new Bird(); bird.Eat(); bird.Sleep(); } public void RaisFish () { Fish fish = new Fish(); fish.Eat(); fish.Sleep(); } }class Program { static void Main (string [] args) { Raiser rar = new Raiser(); rar.RaiseDog(); // Dog Eat. // Dog Sleep. rar.RaisBird(); // Bird Eat. // Bird Sleep. rar.RaisFish(); // Fish Eat. // Fish Sleep. } }
方案二:
图11 Class Diagram public class Bird { public void Eat () { Console.WriteLine("Bird Eat." ); } public void Sleep () { Console.WriteLine("Bird Sleep." ); } public void Fly () { Console.WriteLine("Bird Fly." ); } }public class Dog { public void Eat () { Console.WriteLine("Dog Eat." ); } public void Sleep () { Console.WriteLine("Dog Sleep." ); } public void Run () { Console.WriteLine("Dog Run." ); } }public class Fish { public void Eat () { Console.WriteLine("Fish Eat." ); } public void Sleep () { Console.WriteLine("Fish Sleep." ); } public void Swim () { Console.WriteLine("Fish Swim." ); } }public enum AnimalType { Dog, Bird, Fish };public class Raiser { public void Raise (AnimalType alt) { switch (alt) { case AnimalType.Bird: Bird bird = new Bird(); bird.Eat(); bird.Sleep(); break ; case AnimalType.Dog: Dog dog = new Dog(); dog.Eat(); dog.Sleep(); break ; case AnimalType.Fish: Fish fish = new Fish(); fish.Eat(); fish.Sleep(); break ; } } }class Program { static void Main (string [] args) { Raiser rar = new Raiser(); rar.Raise(AnimalType.Dog); // Dog Eat. // Dog Sleep. rar.Raise(AnimalType.Bird); // Bird Eat. // Bird Sleep. rar.Raise(AnimalType.Fish); // Fish Eat. // Fish Sleep. } }
方案三:
图12 Class Diagram public abstract class Animal { public int Age; public double Weight; public abstract void Eat () ; public abstract void Sleep () ; }public class Bird : Animal { public override void Eat () { Console.WriteLine("Bird Eat." ); } public override void Sleep () { Console.WriteLine("Bird Sleep." ); } public void Fly () { Console.WriteLine("Bird Fly." ); } }public class Dog : Animal { public override void Eat () { Console.WriteLine("Dog Eat." ); } public override void Sleep () { Console.WriteLine("Dog Sleep." ); } public void Run () { Console.WriteLine("Dog Run." ); } }public class Fish : Animal { public override void Eat () { Console.WriteLine("Fish Eat." ); } public override void Sleep () { Console.WriteLine("Fish Sleep." ); } public void Swim () { Console.WriteLine("Fish Swim." ); } }public class Raiser { public void Raise (Animal al) { al.Eat(); al.Sleep(); } }class Program { static void Main (string [] args) { Raiser rsr = new Raiser(); rsr.Raise(new Dog()); // Dog Eat. // Dog Sleep. rsr.Raise(new Bird()); // Bird Eat. // Bird Sleep. rsr.Raise(new Fish()); // Fish Eat. // Fish Sleep. } }