知识结构:
1.1 抽象数据类型(Abstract Data Type)的概念
抽象数据类型由一组数据以及在该组数据上的一组操作组成。
抽象数据类型的格式定义如下:
ADT Name is
Data
构成该抽象数据类型所必须的基本数据项
Operations
Constructor
Initial Values:赋给基本数据项的值
Press:初始化对象
Operation1
Input:操作1要求用户输入的值
PreCondition:系统执行操作1前的数据状态
Press:操作1的解释说明
Output:操作1结束后返回的数据
PostCondition:系统执行操作1后的数据状态
Operation2
… …
OperationN
… …
End ADT Name
例如:矩形结构的ADT描述。
ADT Rectangle is
Data
float Length
float Width
Operations
Constructor
Initial Values:构造矩形时,赋长和宽的值。
Press:初始化对象,给矩形的长和宽赋值。
SetLength
Input:赋给变量Length的新值
PreCondition:无
Press:将矩形的长度值修改为新值
Output:无
PostCondition:矩形的长度值被修改
SetWidth
Input:赋给变量Width的新值
PreCondition:无
Press:将矩形宽度值修改为新值
Output:无
PostCondition:矩形的宽度值被修改
GetArea
Input:无
PreCondition:矩形的长度和宽度都大于零
Press:得到矩形的面积
Output:返回矩形面积的值
PostCondition:无
GetPerimeter
Input:无
PreCondition:矩形的长度和宽度都大于零
Press:得到矩形的周长
Output:返回矩形的周长
PostCondition:无
End ADT Rectangle
一旦定义了矩形结构的ADT描述,就可以用代码进行实现了。
public class Rectangle
{
public float Length;
public float Width;
public Rectangle(float length, float width)
{
Length = length > 0 ? length : 0f;
Width = width > 0 ? width : 0f;
}
public void SetLength(float length)
{
Length = length > 0 ? length : 0f;
}
public void SetWidth(float width)
{
Width = width > 0 ? width : 0f;
}
public float GetArea()
{
if (Length * Width == 0)
throw new ArgumentOutOfRangeException("长度或宽度为零。");
return Length * Width;
}
public float GetPerimeter()
{
if (Length * Width == 0)
throw new ArgumentOutOfRangeException("长度或宽度为零。");
return (Length + Width) * 2;
}
}
1.2 类与对象的概念
2.1 什么是封装
把类的内部隐藏起来以防止外部看到内部的实现过程。
2.2 怎样封装
private
、protected
、public
、internal
来实现。private
:只允许类的内部访问(默认)。protected
:只允许类的内部和子类访问。public
:类的内部与外部都可以访问。internal
:在同一程序集内部访问,相当于public
。public
:都可以使用。internal
:在同一程序集内部使用(默认)。注:internal
修饰的类,方法或属性,只要是在同一个程序集中的其它类都可以访问,如果二者不在同一命名空间,只要使用using
引用上相应的命名空间即可,这里,从另外一个方面也间接看出命名空间并不是界定访问级别的,而是保证全局的类唯一性的。
参考图文:
2.3 怎样表示
private
public
protected
例子:根据下列类图实现Animal类型。
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.1 什么是继承
子类拥有父类某些Data和Operation的过程。
3.2 怎样继承
public class Child : Parent
{
//…
}
Child
:子类(派生类),Parent
:父类(基类)public sealed class Name
{
//...
}
sealed
关键字可防止所声明的类被继承。子类与父类中数据与操作的继承关系:
public
protected
private
internal
public
protected
无法继承 internal
3.3 子类怎样访问父类成员
利用base
关键字。
例子:子类访问父类且父类构造函数不带参数。
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
}
}
例子:子类访问父类且父类构造函数带参数。
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 怎样表示
例子:根据类图实现程序代码,注意类之间的继承关系。
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 实例化
为对象分配存储空间的过程。
例子:类的实例化。
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.
}
}
例子:子类与父类有重名方法。
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
。
Animal al = new Dog();
Dog dg = al;
(错误)需要强制类型转换。Dog dg = al as Dog;
(正确)若al
不是Dog
类型,返回null。Dog dg = (Dog)al;
(正确)若al
不是Dog
类型,系统会抛出异常。4.1 什么是多态
相同的操作(Operation),对于不同的对象,可以有不同的解释,产生不同的执行结果。
4.2 多态的分类
4.3 多态的实现
运行时多态:
例子:实现运行时多态的代码
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.
}
}
编译时多态:
operator
关键字例子:通过类图实现编译时多态的代码
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
- | override(覆写) | overload(重载) |
---|---|---|
位置 | 子类与父类的关系中 | 同一类中 |
方法名 | 相同 | 相同 |
参数列表 | 相同 | 不相同 |
返回值类型 | 相同 | 可以相同 |
4.4 抽象方法与抽象类
abstract
),即只有方法的声明,需要在子类中覆写(override
)该方法。例9:根据类图实现代码
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.
}
}
注意:
al.Run();
(错误)((Dog)al).Run();
(正确)抽象类中并没有Run方法,如果使用需要强制类型转换。
Animal al = new Animal ();
(错误)抽象类不可以直接实例化对象,系统会抛出异常。
总结:抽象方法和虚方法
- | 抽象方法 | 虚方法 |
---|---|---|
在父类中 | 没有实现体(abstract ) | 必须有实现体(virtual ) |
在子类中 | 必须覆写(override ) | 可以覆写也可以不覆写(override ) |
例子:饲养系统
某饲养员(Raiser)在目前状态下需要饲养三种动物:狗(Dog)、鸟(Bird)和鱼(Fish),该三种动物只需要让其睡觉(Sleep)和吃饭(Eat)即可。
请设计该饲养系统,要求满足软件设计的“开闭原则”。
方案一:
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.
}
}
方案二:
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.
}
}
方案三:
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.
}
}