【C#】抽象类和接口

【前言】

        前几天在验收设计模式的时候要验收抽象类和接口,于是又重新复习了一下。对于使用面向对象编程语言的程序员来说,“接口”和“抽象类”这两个名词一定不陌生,下面给大家简单的介绍一下

【抽象类】

1、什么是抽象类

       在面向对象的概念中,所有的对象都是通过类来描绘的,但是反过来,并不是所有的类都是用来描绘对象的。如果一个类中没有包含足够的信息来描绘一个具体的对象,这样的类就是抽象类

2、抽象类的特征

(1)抽象类不能实例化

(2)抽象类可以包含抽象方法和抽象访问器。抽象方法必须是被子类重写的方法

(3)从抽象类派生的非抽象类必须包括继承的所有抽象方法和抽象访问器的实际实现

(4)不能用sealed修饰符修饰抽象类,因为这两个修饰符的含义是相反的。采用sealed修饰符的类无法继承,而abstract修饰符要求对类进行继承

3、与具体对象比较

(1)抽象类不能直接实例化,并且对抽象类使用new运算符会导致编译时错误。虽然一些变量和值在编译时的类型可以是抽象的,但是这样的变量和值必须或者为null,或者含有对非抽象类的实例的引用(此非抽象类是从抽象类派生的)

(2)允许(但不要求)抽象类包含抽象成员

(3)抽象类不能被密封

【接口】

1、面向接口编程和面向对象编程是什么关系

        面向接口编程和面向对象编程并不是平级而定,它并不是比面向对象编程更先进的一种独立的编程思想,而是附属于面向对象思想体系,属于其一部分。或者说,它是面向对象编程体系中的思想精髓之一

2、什么是接口

       接口是指定一组函数成员而不实现成员的引用类型,其它类型 类和接口可以实现接口

3、接口的特性

(1)接口类似于抽象基类,不能直接实例化接口,接口中的方法都是抽象方法,实现接口的任何非抽象类型都必须实现接口的所有成员:

        当显式实现该接口的成员时,实现的成员不能通过类实例访问,只能通过接口实例访问

        当隐式实现该接口的成员时,实现的成员可以通过类实例访问,也可以通过接口实例访问,但是实现的成员必须是公有的

        这两种实现有什么优缺点?

        一般情况,当类或者结构要实现的是单个接口,可以使用隐式实现。如果类或者结构继承了多个接口且多个接口中具有相同名称成员时,就要用到显示实现,当显式实现方式存在问题时,隐式实现方式就失效了

       

interface IProgram
    {
        void Fun();
    }
    interface IAProgram
    {
        void Fun();
    }
    class Program : IProgram, IAProgram
    {
        void IProgram.Fun()  //显式实现接口IProgram
        {
            Console.WriteLine("I am IProgram Fun.");
        }
        void IAProgram.Fun()  //显式实现接口IAProgram
        {
            Console.WriteLine("I am IAProgram Fun.");
        }
        //public void Fun()   //隐式实现接口
        //{
        //    Console.WriteLine("I am Program Fun.");
        //}
        static void Main(string[] args)
        {
            //IProgram p = new Program();
            //p.Fun();
            //IAProgram ap = new Program();
            //ap.Fun();
            Program pro = new Program();
            ((IProgram)pro).Fun();
            ((IAProgram)pro).Fun();
            Console.Read();
        }
    }

        显示结果:


(2)接口不能包含常量、字段、运算符、实例构造函数、析构函数或类型、不能包含静态成员

(3)接口成员是自动公开的,不能包含任何访问修饰符

        为什么不能制定接口中方法的修饰符?

       接口中的方法用来定义对象之间通信的契约,指定接口中的方法为私有或保护没有意义。它们默认为公有方法

(4)接口自身可从多个接口继承,类和结构可继承多个接口,但接口不能继承类

4、接口的本质

       接口,在表面上是由几个没有主体代码的方法定义组成的集合体,有唯一的名称,可以被类或其他接口所实现(或者也可以说继承),它在形式上可能是如下的样子:

       
interface InterfaceName
    {
        void Method1();
        void Method2(int para1);
        void Method3(string para2, string para3);
    }

       那么,接口的本质是什么?或者说接口存在的意义是什么?我认为可以从以下两个视角考虑:
(1)接口是一组规则的集合,它规定了实现本接口的类或接口必须拥有的一组规则。体现了自然界“如果你是...则必须能..”的理念
        例如,在自然界中,人都能吃饭,即“如果你是人,则必须能吃饭”。那么模拟到计算机程序中,就应该有一个IPerson(习惯上,接口名由“I”开头)接口,并有一个方法叫Eat(),然后我们规定,每一个表示“人”的类,必须实现IPerson接口,这就模拟了自然界“如果你是人,则必须能吃饭”这条规则。
        从这里,我想各位也能看到些许面向对象思想的东西。面向对象思想的核心之一,就是模拟真实世界,把真实世界中的事物抽象成类,整个程序靠各个类的实例互相通信、互相协作完成系统功能,这非常符合真实世界的运行状况,也是面向对象思想的精髓。
(2)接口是在一定粒度视图上同类事物的抽象表示
        面向对象思想和核心之一叫做多态性,什么叫多态性?说白了就是在某个粒度视图层面上对同类事物不加区别的对待而统一处理。而之所以敢这样做,就是因为有接口的存在。

【接口和抽象类的区别】

1、接口和抽象类的概念不同

接口是对动作的抽象,抽象类是对根源的抽象。抽象类表示的是,这个对象是什么;接口表示的是,这个对象能做什么

2、接口是抽象类的变体,接口中所有的方法都是抽象的。而抽象类是声明方法的存在而不去实现它的类

3、接口可以多继承,抽象类不可以

4、接口定义方法不能实现,而抽象类可以实现部分方法

5、接口中基本数据类型为static,而抽象类不是

         下面给大家举一个小例子


        需求已经在上图,下面是分析与代码

       

    /*
      教练和运动员案例(学生分析然后讲解)
      乒乓球运动员和篮球运动员。
      乒乓球教练和篮球教练。
      为了出国交流,跟乒乓球相关的人员都需要学习英语。
      请用所学知识:
      分析,这个案例中有哪些抽象类,哪些接口,哪些具体类。
    
      整个分析过程,我是通过画图讲解的。 
     */

    //定义一个说英语的接口
    interface SpeakEnglish
    {
        //说英语
        public abstract void speak();
    }

    //定义人的抽象类
    abstract class Person
    {
        private String name;
        private int age;

        public Person() { }
        public Person(String name, int age)
        {
            this.name = name;
            this.age = age;
        }
        public String getName()
        {
            return name;
        }
        public void setName(String name)
        {
            this.name = name;
        }
        public int getAge()
        {
            return age;
        }
        public void setAge(int age)
        {
            this.age = age;
        }
        //睡觉
        public void sleep() 
        {
            System.out.println("人都是要睡觉的");
        }
        //吃饭
        public abstract void eat();
    }

    //定义运动员抽象类
    abstract class Player extends Person 
    {
         public Player() {}
    
         public Player(String name,int age) 
         {
             super(name,age);
         }
    
         //学习
         public abstract void study();
    }

     //定义教练抽象类
     abstract class Coach extends Person 
     {
         public Coach() {}
    
         public Coach(String name,int age) 
         {
             super(name,age);
         }
    
         //教
         public abstract void teach();
      }

    //定义乒乓球运动员具体类
    class PingPangPlayer extends Player implements SpeakEnglish
    {
        public PingPangPlayer(){}
    
        public PingPangPlayer(String name,int age) 
        {
            super(name,age);
        }
    
        //吃
        public void eat() 
        {
            System.out.println("乒乓球运动员吃大白菜,喝小米粥");
        }
    
        //学习
        public void study() 
        {
           System.out.println("乒乓球运动员学习如何发球和接球");
         }
    
        //说英语
        public void speak() 
        {
           System.out.println("乒乓球运动员说英语");
        }
    }

    //定义乒乓球教练具体类
    class PingPangCoach extends Coach implements SpeakEnglish 
    {
        public PingPangCoach(){}
    
        public PingPangCoach(String name,int age) 
        {
            super(name,age);
        }
    
        //吃
        public void eat() 
        {
            System.out.println("乒乓球教练吃小白菜,喝大米粥");
        }
    
        //教
        public void teach() 
        {
            System.out.println("乒乓球教练教如何发球和接球");
        }
    
        //说英语
        public void speak() 
        {
            System.out.println("乒乓球教练说英语");
        }
    }

    //定义篮球教练具体类
    class BasketballCoach extends Coach 
    {
        public BasketballCoach(){}
    
        public BasketballCoach(String name,int age) 
        {
            super(name,age);
        }
    
        //吃
        public void eat() 
        {
            System.out.println("篮球教练吃羊肉,喝羊奶");
        }
    
        //教
        public void teach() 
        {
            System.out.println("篮球教练教如何运球和投篮");
        }
    }

    class InterfaceDemo
    {
        public static void Main(string[] args)
        {
             //测试运动员(乒乓球运动员和篮球运动员)
             //乒乓球运动员
             PingPangPlayer ppp = new PingPangPlayer();
             ppp.setName("王浩");
             ppp.setAge(33);
             System.out.println(ppp.getName()+"---"+ppp.getAge());
             ppp.eat();
             ppp.sleep();
             ppp.study();
             ppp.speak();
             System.out.println("----------------");
            //通过带参构造给数据
        
            //篮球运动员
            BasketballPlayer bp = new BasketballPlayer();
            bp.setName("姚明");
            bp.setAge(34);
            System.out.println(bp.getName()+"---"+bp.getAge());
            bp.eat();
            bp.sleep();
            bp.study();
            //bp.speak(); //没有该方法
        
            //测试教练自己做
        }
    }

【小结】

        抽象类的功能要远远超过接口,但是定义抽象类的代价高。因为对于高级语言来说每个类只能继承一个类。在这个类中,必须继承或编写出其所有子类的所有共性。虽然接口在功能上会弱化许多,但是它只是针对一个动作的描述。而且可以在一个类中同时实现多个接口,在设计阶段会降低难度的

        如果单从具体代码来看,对这两个概念很容易模糊,甚至觉得接口就是多余的,因为单从具体功能来看,除多重继承外(C#,Java中),抽象类似乎完全能取代接口。但是,难道接口的存在是为了实现多重继承?当然不是。我认为,抽象类和接口的区别在于使用动机。使用抽象类是为了代码的复用,而使用接口的动机是为了实现多态性。所以,如果你在为某个地方该使用接口还是抽象类而犹豫不决时,那么可以想想你的动机是什么。


       本文只是对基础知识做一个小小的总结,不深究。如有不同,见解欢迎指正

       本文所有代码均已通过作者测试

       本文所有内容均为作者原创,如有转载,请注明出处

       

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 72
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值