C#接口和抽象类的总结

一、接口的简单实现

接口更好地实现了多态,体现了约定和实现相分离的原则。通过面向接口编程,可以降低代码间的耦合性,提高代码的可扩展性和可维护性。在面向对象编程中,提倡面向接口编程,而不是面向实现编程。面向接口编程意味着,开发系统时,主体架构使用接口,接口构成系统的骨架,这样就可以通过更换实现接口的类来实现更换系统。一个类实现的某个接口,就表示这个类具有了某种能力,这个能力具体体现在实现接口的方法上。

如下代码,有一个Duck父类,它有三个子类,RealDuck、WoodDuck、RubberDuck。其中RealDuck和RubberDuck会叫,只是叫声不一样,WoodDuck不会叫。有一个鸭子叫的接口IBark。

/// <summary>
    /// 鸭类
    /// </summary>
    public class Duck
    {
        public void Swin()   //游泳方法
        {
            Console.WriteLine("鸭子在水中游...");
        }
    }
    //鸭子叫的接口
    public interface IBark
    {
        void Bark();
    }

    /// <summary>
    /// 真实的鸭子
    /// </summary>
    public class RealDuck : Duck, IBark
    {
        public void Bark()
        {
            Console.WriteLine("嘎嘎叫...");
        }
    }

    /// <summary>
    /// 橡皮鸭
    /// </summary>
    public class RubberDuck : Duck, IBark
    {
        public void Bark()
        {
            Console.WriteLine("唧唧叫...");
        }
    }

    /// <summary>
    /// 木头鸭
    /// </summary>
    public class WoodDuck : Duck
    {

    }
在Main()方法中,当我们想要让鸭子叫时,不能用父类变量指向会叫的鸭子对象,因为这样会让这个变量无法调用子类鸭子叫的方法,而是应该用接口来声明这个变量。代码如下:
static void Main(string[] args)
        {
            //Duck duck = new RealDuck();
            
            IBark bark = new RealDuck();
            bark.Bark();

            Console.ReadKey();
        }
这样在控制台上显示的结果是“嘎嘎叫...”。

二、显式实现接口

先看如下示例代码,一个具有飞行功能的接口IFlyable,一个可以飞行的超人接口ISuperman,这两个接口里面有一个同名的飞行方法Fly,另外有一个学生类同时继承了这两个接口,并且实现了接口所具有的Fly()方法,一个是直接实现,一个是显式实现。

//具有飞行功能的接口
    public interface IFlyable
    {
        void Fly();
    }

    //具有飞行功能的超人接口
    public interface ISuperman
    {
        void Fly();
    }

    public class Student : IFlyable,ISuperman
    {
        public void Fly()
        {
            Console.WriteLine("IFlyable接口中的Fly方法");
        }

        void ISuperman.Fly()
        {
            Console.WriteLine("ISuperman接口中的Fly方法(显示实现的方法)");
        }
    }
在Main方法中,我们让三个不同类型的变量分别指向一个学生对象,如下:
static void Main(string[] args)
        {
            IFlyable fly = new Student();  //飞行类
            fly.Fly();

            ISuperman man = new Student();  //超人类
            man.Fly();

            Student stu = new Student();  //学生类
            stu.Fly();

            Console.ReadKey();
        }
运行程序,结果如图所示:

从上面可以看出,显式实现的Fly方法的对象只有用实现该显式方法的接口来声明,我们才可以调用这个显式方法。在上面的代码中,你会发现,显式实现的方法前面没有访问修饰符,也就是默认为private,而直接实现的方法的访问修饰符是public。如果在显式实现的方法前面加一个public访问修饰符,那么程序就会报错,如图所示:


错误信息提示我们:修饰符public对该项无效。这也告诉我们,显式实现接口的方法必须为private。既然这个方法是私有的,那在外界就不能访问了,那我们用ISuperman类型的变量指向的Student对象为什么又可以访问到呢?因为这个对象访问的是ISuperman接口中的Fly方法,而所有接口中的方法都默认必须为public,并且继承这个接口的Student类已经显式的实现了这个Fly方法,所以可以访问到。显式实现接口的目的,就是为了解决方法重名的问题。

假如我们把Student类中直接实现的IFlyable接口的方法删掉,然后让这个接口也显式实现其方法,如下所示:

public class Student : IFlyable,ISuperman
    {
        //public void Fly()
        //{
        //    Console.WriteLine("IFlyable接口中的Fly方法");
        //}

        void ISuperman.Fly()   //显式实现ISuperman接口的方法
        {
            Console.WriteLine("ISuperman接口中的Fly方法(显示实现的方法)");
        }

        void IFlyable.Fly()   //显式实现IFlyable接口的方法
        {
            throw new NotImplementedException();
        }
    }
那么,在Main方法中,我们会发现程序报错,如图:

我们会发现,用Student类声明的对象无法访问到Fly这个方法,因为这个方法是私有的(private),外界声明的Student类型的对象无法访问。所以,我们可以得出结论,显式实现的方法必须要由实现显式方法的接口声明的对象调用。


三、接口特点的总结:

1.接口是一种规范,是为了更好的实现多态。

2.接口不能被实例化。

3.接口中的成员不能加访问修饰符。因为接口中的成员的访问修饰符默认就为public,不能修改。

4.接口中的成员不能有任何实现(也就是光说不做,只是定义了一组未实现的成员)。

5.接口中只能有方法、属性、索引器、事件,不能有字段。

6.接口与接口之间可以继承,并且可以多继承。

7.实现接口的子类必须实现该接口的全部成员。

8.一个类可以同时继承一个类并实现多个接口,如果一个子类同时继承了父类A,并且实现了接口IA,那么语法上A必须写在IA的前面,因为类是单继承的。

9.当一个抽象类实现接口的时候,如果不想把接口中的成员实现,可以把该成员实现为abstract。

10.显式实现接口,只能通过接口变量来调用,因为显式实现接口后,成员必须为private(上面已有示例)。


四、使用接口的建议:

面向抽象编程,我们提倡使用抽象(父类、抽象类、接口)而不使用具体,我们在编程时:

1.在定义方法返回值、参数、声明变量的时候能使用抽象就不要用具体。这个顺序一般为:接口→抽象类→父类→具体类。

2.能使用接口就不用抽象类,能用抽象类就不使用父类,能用父类就不使用子类。

3.避免定义体积庞大的接口和多功能接口,这样会造成接口污染。只需要把相关联的一组成员定义到一个接口中,尽量在接口中少定义成员,这就是单一职责原则。

4.我们一般应定义多个职责单一的接口来组合使用。


五、抽象类的特点

1.不能被实例化,需要被继承,这是为了实现多态。

2.子类必须重写父类所有的抽象成员,除非子类也是一个抽象类。

3.抽象成员在父类中不能的任何实现。

4.抽象类中可以有实例成员。

5.抽象成员的访问修饰符不能是private。

6.抽象成员只能写在抽象类中。


六、抽象类和接口的区别

1.抽象类适用于同一系列(类型),并且有需要继承的成员。

2.接口适用于不同系列的类具有相同的动作(行为、动作、方法)。

3.对于不是相同的系列,但具有相同的行为时,就应该要使用接口。

4.接口解决了类不能多继承的问题。





  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
抽象类接口C#中有以下异同点: 相同点: 1. 都不能被实例化,只能通过实现它们的子类或实现类来创建对象。 2. 子类或实现类必须实现抽象类接口中的所有法才能被实例化。 3. 可以被其他类继承或实现。 异同点: 1. 抽象类是特殊的类,可以包含成员变量、法、属性等,而接口只能包含法、属性、事件和索引器的声明。 2. 一个类只能继承一个抽象类,但可以实现多个接口。 3. 抽象类可以有法的实现,而接口只能有法的声明。 4. 抽象类可以有字段和构造函数,而接口不能有字段和构造函数。 5. 接口可以被其他接口继承,形成接口继承链,而抽象类不能被继承总结来说,抽象类更适合用于定义一些具有共同特征的类的基类,而接口更适合用于定义一些行为的规范,使得不同的类可以实现这些规范。 #### 引用[.reference_title] - *1* [Java抽象类接口的异同点](https://blog.csdn.net/m0_64742984/article/details/124610167)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^control_2,239^v3^insert_chatgpt"}} ] [.reference_item] - *2* *3* [C# 抽象类接口异同](https://blog.csdn.net/Monkey_Xuan/article/details/115915086)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^control_2,239^v3^insert_chatgpt"}} ] [.reference_item] [ .reference_list ]

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值