您的位置:首页 > 其它

设计模式基础——抽象类、抽象方法、接口与虚方法

2017-12-06 17:02 330 查看
今天想想设计模式中的一些基本概念,发现面向对象编程也没学好,有些概念没有缕清楚,这里再复习一下,为以后的设计模式做铺垫。

这次主要介绍抽象类、抽象方法、接口与虚方法之间的联系与区别。

1. 抽象类

1.1 简介

定义:不能初始化的类被叫做抽象类,它们只提供部分实现,但是另一个类可以继承它并且能创建它们。

抽象类的功能:为子类提供功能约束。与接口不同的是它还有其他普通方法、成员变量等。

样子,以abstract修饰:

public abstract class A
{
//这是一个抽象类
}


可包含成员:普通方法、抽象方法、构造函数、成员变量(变量、常量)。

1.2注意事项

1、所有抽象方法在实例化继承时,需要全部实现,否则必须声明子类也为抽象类,即抽象类是可以继承抽象类的,当然如果继承非抽象类,那更是没问题的。

2、抽象类是可以有构造函数的。虽然构造函数用于实例化一个对象(或建立一个对象的实例),而抽象类不能被实例化,所以抽象类不应该有公共的构造函数(FxCop.设计规则)。但不应该有“公共”的构造函数,和不应该有构造函数,这是两个不同的概念。因此抽象类也是有构造函数的,不过构造函数必须是“protected”的。其作用有:初始化抽象类的成员;为继承自它的子类使用等。

3、包含抽象方法的类一定是抽象类,但是抽象类可以包含普通方法。另外抽象类不能实例化。

2. 接口

2.1 简介

接口的一个最大的刚需就是多继承,其实论功能来讲,接口并不如抽象类丰富,因为抽象类除了接口能实现的功能以外,还具备其他功能(普通方法、普通成员变量等),但抽象类只能单继承,所以接口就应运而生了。接口从本质上来说,其实还是一种类,只不过是一种特殊的类。

在小工程里,如果不能够对接口的功能进行一个清醒的认识,很容易的认为接口是非常多余的。但是一旦涉及到2个及以上的开发人员后,除了遵循开发规范,另外一点就是在定义数据结构的时候,同时遵循统一接口,这样在对接的时候,就不会出现错了。

比如,A需要问B要数据,那么B怎么给A呢,除了定义出数组的载体,也就是实体类,还需要定义A和B的统一方法原型,而这除了口头约定外,最好的方式就是继承同一握手接口。

样子:

//这是一个接口,接口通常使用I开头命名。
public interface IA
{
//其方法不能有访问修饰符
void Show();
}


2.2 接口与抽象类的区别

1、接口用于规范,抽象类用于共性。抽象类是类,所以只能被单继承,但是接口却可以一次实现多个。

2、接口中只能声明方法,属性,事件,索引器。而抽象类中可以有方法的实现,也可以定义非静态的类变量。

3、抽象类可以提供某些方法的部分实现,接口不可以。抽象类的实例是它的子类给出的。接口的实例是实现接口的类给出的。

4、在抽象类中加入一个方法,那么它的子类就同时有了这个方法。而在接口中加入新的方法,那么实现它的类就要重新编写(这就是为什么说接口是一个类的规范了)。

5、接口成员被定义为公共的,但抽象类的成员也可以是私有的、受保护的、内部的或受保护的内部成员(其中受保护的内部成员只能在应用程序的代码或派生类中访问)。此外接口不能包含字段、构造函数、析构函数、静态成员或常量。

3. 抽象方法

3.1 简介

抽象方法是抽象类的一个标志之一,具备了抽象方法的类一定是抽象类。

并且抽象方法只在抽象类中定义,方法修饰符不能使用private,virtual,static.

抽象方法的功能:子类必须实现与该抽象方法相同原型的方法。

样子:

//这是一个抽象类
public abstract class A
{
//这是一个抽象方法
public abstract void Afunc();
}


3.2注意事项:

1、一个抽象方法可以看作是一个虚函数。

2、抽象方法的声明只能在抽象类中。

3、因为抽象方法声明只提供一个无实现的方式,没有方法体。

4、方法体的实现被覆写方法提供,覆写方法是一个非抽象类的成员。

5、抽象属性的行为和抽象方法相像,除了不同的声明形式。

6.在一个静态属性中使用abstract 是一个错误。

4.虚方法

4.1 简介

声明为父类类型的引用变量只能调用父类中的方法,如果此变量实际引用的是子类对象,而子类对象中覆盖了父类的方法,这时父类对象调用的是子类中的方法,这种机制就成为虚方法调用。所以,同样的两个引用变量调用相同的方法结果可能不同。

在JAVA中,反而是非虚方法比较少,常见的非虚方法有:静态方法、私有方法、实例构造器、父类方法四种。而其他方法基本上都是虚方法。究其原因就是引文虚方法更像是一种方法引用,它可以指向不同的函数。

下面是虚方法与非虚方法的实例:

class A
{
public void F() { Console.WriteLine("A.F"); }
public virtual void G() { Console.WriteLine("A.G"); }  //定义虚方法
}
class B : A
{
new public void F() { Console.WriteLine("B.F"); }      //这里的方法则不能重写,因为基类中的F()方法不是虚方法。
public override void G() { Console.WriteLine("B.G"); }   //重写虚方法
}
static void Main(string[] args)
{
FashionCoat show = new FashionCoat();
show.ShowCoat();
BusinessFactory showbusiness = new BusinessFactory();
showbusiness.CreatCoat().ShowCoat();

B b = new B();
A a = b;      //A对象指向B对象
b.F();       //显示结果B.F
a.F();       //显示结果A.F
b.G();       //显示结果B.G
a.G();       //显示结果B.G 实际这里调用的是不是基类中的G方法,而是派生类中重写过的G方法。
Console.ReadKey();
}


可以看到,使用new关键字和使用override关键字之间的区别。使用new关键字声明同一种方法的时候,子类调用的时候和父类调用的时候是不同的,也就是说子类的F函数和父类的F函数是不一样的。而使用override的时候,其实父类调用G函数则要取决于它实例化的对象是谁。而抽象类和接口则不能具有方法体,也就是说它并不能让父类也具有一定的功能,只能由实例化对象进行功能实现。

4.2虚方法与抽象方法的区别

总结:抽象方法是只有方法名称,没有方法体(也就是没有方法具体实现),子类必须重写父类抽象方法;虚函数是该方法有方法体,但是子类可以覆盖,也可不覆盖。

1、虚方法有方法体,抽象方法没有方法体。抽象方法是一种强制派生类覆盖的方法,否则派生类将不能被实例化;

2、抽象方法只能在抽象类中声明,虚方法不是;

3、派生类必须重写抽象类中的抽象方法,虚方法则不必要。

基本上我们对于这四类进行了一次梳理,能给别人讲出来,才是真正的掌握了。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
相关文章推荐