重新认识抽象类和接口的区别

因为平时项目中用到的很少,这种基础的问题,看了忘,忘了看。从网上找到的千篇一律。今天自己试验一下这些说法。

     三、抽象类和接口的区别:
      1.类是对对象的抽象,可以把抽象类理解为把类当作对象,抽象成的类叫做抽象类.而接口只是一个行为的规范或规定,微软的自定义接口总是后带able字段,证明其是表述一类类“我能做。。。”.抽象类更多的是定义在一系列紧密相关的类间,而接口大多数是关系疏松但都实现某一功能的类中.
      2.接口基本上不具备继承的任何具体特点,它仅仅承诺了能够调用的方法;     
      3.一个类一次可以实现若干个接口,但是只能扩展一个父类
      4.接口可以用于支持回调,而继承并不具备这个特点.
      5.抽象类不能被密封。
      6.抽象类实现的具体方法默认为虚的,但实现接口的类中的接口方法却默认为非虚的,当然您也可以声明为虚的.
      7.(接口)与非抽象类类似,抽象类也必须为在该类的基类列表中列出的接口的所有成员提供它自己的实现。但是,允许抽象类将接口方法映射到抽象方法上。   
       8.抽象类实现了oop中的一个原则,把可变的与不可变的分离。抽象类和接口就是定义为不可变的,而把可变的座位子类去实现。
      9.好的接口定义应该是具有专一功能性的,而不是多功能的,否则造成接口污染。如果一个类只是实现了这个接口的中一个功能,而不得不去实现接口中的其他方法,就叫接口污染。
     10.尽量避免使用继承来实现组建功能,而是使用黑箱复用,即对象组合。因为继承的层次增多,造成最直接的后果就是当你调用这个类群中某一类,就必须把他们全部加载到栈中!后果可想而知.(结合堆栈原理理解)。同时,有心的朋友可以留意到微软在构建一个类时,很多时候用到了对象组合的方法。比如asp.net中,Page类,有Server Request等属性,但其实他们都是某个类的对象。使用Page类的这个对象来调用另外的类的方法和属性,这个是非常基本的一个设计原则。
    11.如果抽象类实现接口,则可以把接口中方法映射到抽象类中作为抽象方法而不必实现,而在抽象类的子类中实现接口中方法.

 

第一条:简单点说就是抽象类是对类的抽象,接口是一个行为的规范,其他的就太XX了看不懂。

第二条:可以理解为继承接口只是为了使用接口中的方法

第三条:类可以继承自多个接口,只能继承一个类,接口也可以继承自多个接口啊,区别就是接口能不能继承自类了,写一个接口让他继承一个类。

    interface Interface1 : Class1
    {
    }

 

程序报错:

在写一个抽象类让他继承接口和类是不会报错的。

 第四条:意思就是接口可以支持回调,但是抽象类不支持回调。总网上找了个例子来试试。

复制代码
代码
    public class CallBackDemo
    {
        
public static void CallBackFunction()
        {
            
//传递对象给接口类型变量(IBack)
            Controller obj = new Controller(new CallBack());
            
//调用对象方法
            obj.Start();
        }
    }

    public interface IBack
    {
        void Run();
    }
    public class CallBack : IBack
    {

        #region IBack Members

        public void Run()
        {
            Console.WriteLine(DateTime.Now);
        }

        #endregion
    }
    
public class Controller
    {
        
public IBack CallBackObj = null;
        
public Controller(IBack obj)
        {
            CallBackObj 
= obj;
        }

        
public void Start()
        {
            Console.WriteLine(
"敲击键盘任意键显示当前时间,直到按Esc退出");
            
while(Console.ReadKey(true).Key != ConsoleKey.Escape)
            {
                CallBackObj.Run();
            }
        }
    }

复制代码

 

这个例子很简单的,就是只要不按下ESC键,他就一直执行输出当前时间,Controller类的构造函数的参数是一个接口类型的,当给他传入一个他的实现类的对象就会调用这个对象的方法输出当前时间。

结果如下:

然后用抽象类来代替这个接口看看能不能实现这个功能:

复制代码
代码
 1     public class CallBackDemo
 2     {
 3         public static void CallBackFunction()
 4         {
 5             //传递对象给接口类型变量(IBack)
 6             Controller obj = new Controller(new CallBack());
 7             //调用对象方法
 8             obj.Start();
 9         }
10     }
11     //public interface IBack
12     //{
13     //    void Run();
14     //}
15     //public class CallBack : IBack
16     //{
17 
18     //    #region IBack Members
19 
20     //    public void Run()
21     //    {
22     //        Console.WriteLine(DateTime.Now);
23     //    }
24 
25     //    #endregion
26     //}
27     public abstract class IBack
28     {
29         public abstract void Run();
30     }
31     public class CallBack : IBack
32     {
33         public override void Run()
34         {
35             Console.WriteLine(DateTime.Now);
36         }
37     }
38     public class Controller
39     {
40         public IBack CallBackObj = null;
41         public Controller(IBack obj)
42         {
43             CallBackObj = obj;
44         }
45 
46         public void Start()
47         {
48             Console.WriteLine("敲击键盘任意键显示当前时间,直到按Esc退出");
49             while(Console.ReadKey(true).Key != ConsoleKey.Escape)
50             {
51                 CallBackObj.Run();
52             }
53         }
54     }
复制代码

 

现在让Controller的构造方法接受一个IBack类型的变量,一样可以实现的。这条区别有点牵强。

第五条:抽象类不能被密封,意思就是说抽象类不能被密封,接口可以被密封。密封之后就不能被继承了,所以只要用出现:来继承就会报错。应该也会出现这样的错误的,接口也不能被密封。这条也说不过去。

写一个语句:

public sealed abstract class IBack{} 报错

意思很明显了就是说IBack这个抽象类不能被密封或是静态的。

吧sealed用在接口上public sealed interface IBack{}报错:

意思是关键字sealed不可以用在接口上,这里用item这个词,也就是说接口相当于一个变量。

两种都会报错啊,这条区别也有点牵强啊。

第六条:抽象类实现的具体方法默认为虚的,但实现接口的类中的接口方法却默认为非虚的。

抽象类中的方法是虚拟的,但是不提供virtual关键字来修饰,如果写上了会报错,接口中的方法是公共的不能申明为虚拟的。这条很明显。代码如下:

1     public  interface IBack
2     {
3         virtual void Run();
4     }

 

报错如下:

将抽象类中的方法表示为虚拟的也会报错。

    public abstract class IBack
    {
        
public virtual abstract void Run();
    }
同样也会报错:有了abstract关键字就不需要再申明为virtual的了,看来抽象和虚拟是有些类似的,抽象函数也是虚拟的。
第七条:第一句不是他两个的区别,是共同点,第二句和第十一条说的一个意思,可以让接口实现抽象类,但是不实现抽象类中的方法,但是这种做法很怪异,估计项目中不会用到这样的。
 

 

 第八条:抽象类实现了oop中的一个原则,把可变的与不可变的分离。抽象类和接口就是定义为不可变的,而把可变的座位子类去实现。这条说的也是相同点嘛,不是区别。

第九条:好的接口定义应该是具有专一功能性的,而不是多功能的,否则造成接口污染。如果一个类只是实现了这个接口的中一个功能,而不得不去实现接口中的其他方法,就叫接口污染。更谈不上区别了。

第十条:尽量避免使用继承来实现组建功能,而是使用黑箱复用,即对象组合。因为继承的层次增多,造成最直接的后果就是当你调用这个类群中某一类,就必须把他们全部加载到栈中!后果可想而知.(结合堆栈原理理解)。同时,有心的朋友可以留意到微软在构建一个类时,很多时候用到了对象组合的方法。比如asp.net中,Page类,有Server Request等属性,但其实他们都是某个类的对象。使用Page类的这个对象来调用另外的类的方法和属性,这个是非常基本的一个设计原则。说的是使用组合对象避免多重继承,这也不是区别啊。

第十一条:和第七条的后半句雷同的,抽象类可以实现接口,但是不是具体实现,而是在他的子类中实现。这也不是区别。

 

对于接口和抽象类的区别,哪位大侠能够给点经典的,经得起推敲的答案啊,还有什么时候要用抽象类?什么时候要用接口?

posted @   nd  阅读(681)  评论(2编辑  收藏  举报
编辑推荐:
· MySQL 优化利器 SHOW PROFILE 的实现原理
· 在.NET Core中使用异步多线程高效率的处理大量数据
· 聊一聊 C#前台线程 如何阻塞程序退出
· 几种数据库优化技巧
· 聊一聊坑人的 C# MySql.Data SDK
阅读排行:
· 干掉EasyExcel!FastExcel初体验
· 跟着 8.6k Star 的开源数据库,搞 RAG!
· .NET 阻止系统睡眠/息屏
· .NET 9 中的 多级缓存 HybridCache
· 夜莺 v8 第一个版本来了,开始做有意思的功能了
点击右上角即可分享
微信分享提示