Ø 抽象类
面向对象的编程,并不是类越多越好,类的划分是为了封装,但分类的基础是抽象,具有相同属性和功能的对象的抽象集合才是类。在类的基础上进行抽象,那么便是抽象类。
比如黑猫,白猫,小猫,大猫,它们的共同特点就是属于猫,那么猫就是一个类,同样狗也是一个类。在猫狗的基础上,因为它们均属于动物,那么动物便是它们的一个共同的类,由于我们无法描述一个动物是什么什么的,这样的类便是抽象类。
具体抽象类是:它代表一个抽象的概念,它提供一个继承的出发点,当设计一个新的抽象类时,一定是用来继承的,所以,在一个以继承关系形成的等级结构里面,树叶节点应当是具体类,树枝节点均应是抽象类。
u 需要注意的地方
一、抽象类是不能实例化的。
二、抽象方法可以看成是没有具体实现体的虚方法。
三、如果类中包含抽象方法,那么类必须定义为抽象类,不论是否还包含其他的一般方法。
Ø 接口
接口是把隐式公共方法与属性组合起来,以封装特定功能的一个集合。一旦类实现了接口,类就可以支持接口所指定的所有属性和成员。声明接口在语法上与声明抽象类完全相同,但是不允许提供接口中任何成员的执行方式。
u 需要注意的地方
一、接口不能实例化,不能有构造方法和字段。
二、不能有修饰符,比如public、private等等。
三、不能声明虚拟的或静态的等。
四、实现接口的类必须要实现接口中所有方法和属性。
五、一个类可以支持多个接口,多个类也可以支持相同的接口。
六、接口的命名,前面要加一个大写的“I”。
七、注意接口用interface声明,而不是class。
Ø 抽象类与接口的区别
u 抽象类
class Animal
{
protected string name = "";
protected int shoutNum = 3;
public int ShoutNum
{
get { return shoutNum; }
set
{
shoutNum = value;
}
}
public Animal(string name)
{
this.name = name;
}
public Animal()
{
this.name = "无名";
}
public string Shout()
{
string result = "";
for (int i = 0; i < shoutNum; i++)
result += getShoutSound() + ",";
return "我的名字叫" + name + " " + result;
}
protected virtual string getShoutSound()
{
return "";
}
}
具体实现
class Cat : Animal //同理也是
{
public Cat(): base()
{ }
public Cat(string name)
: base(name)
{ }
protected override string getShoutSound()
{
return "喵";
}
}
u 接口
第一段代码同抽象类的第一段
interface IChange
{
string ChangeThing(string thing);
}
具体实现
class MachineCat : Cat, IChange
{
public MachineCat ():base()
{
}
public MachineCat(string name):base(name)
{
}
public string ChangeThing(string thing)
{
return base.Shout() + "我有万能口袋,我可变出:" + thing;
}
}
对比分析
形态上区分:
l 抽象类是可以给出一些成员的具体实现,但是接口却不包含成员的实现。
l 抽象类的抽象成员可以被子类部分实现,但是接口的成员需要实现类完全实现。
l 一个类只能继承一个抽象类,但是可以实现多个接口等等。
还可以从另外三点区别:
u 类是对对象的抽象,抽象类是对类的抽象,而接口是对于行为的抽象。
u 如果行为跨越不同类的对象,可使用接口。对于一些相似的类对象用继承抽象类。
u 从设计上讲,抽象类是从子类中发现了公共的东西,泛化出父类,然后子类继承父类。举例:有一个猫类,又有一个狗类,于是泛化出动物类。而接口是根本不知子类的存在,方法如何实现还不确认,预先定义。举例:举办动物运动会,因为事先不知道会有什么动物来参加运动会,比赛项目也不知什么动物参加,所以事先只能定义这些比赛项目的行为接口。
小结:
抽象类和接口也是依赖倒转原则的一个关键。
依赖倒转原则:
A.高层模块不应该依赖于低层模块。两个都应该依赖于抽象。
B.抽象不应该依赖于细节,而细节应该依赖于抽象。
依赖倒转其实是面向对象设计的标志,用哪种语言来编写程序不重要,如果编写时考虑的都是如何针对抽象编程而不是针对细节编程,即程序中所有的依赖关系都是终止于抽象类或者接口,那么,就是面向对象的设计。
此外接口和抽象类的实现并不冲突,我们可以让超人继承人类,然后实现飞行接口。