c#笔记之接口和抽象类

为什么要有接口和抽象类

开闭原则:

  • 对扩展开放 新增功能、新需求时,可以新增代码、新增类,来扩展原有系统。

  • 对修改关闭 已经写好、测试通过、正在运行的原有代码不要改,尽量不去动老逻辑,避免改出 Bug。

就是要封装确定的开发不确定的;


学习内容:

一、抽象类

1.1一句话定义

  • abstract 修饰的类
  • 不能直接 new 对象
  • 可以包含:普通方法、抽象方法、字段、属性、构造方法
  • 作用:做父类模板,强制子类必须实现某些方法
  • 抽象方法就是没有大括号没有方法要做什么,就是正常声明加了 abstract 修饰

1.2格式

cs 复制代码
// 抽象类
public abstract class Animal
{
    // 普通字段
    public string Name { get; set; }

    // 普通方法(有实现)
    public void Eat()
    {
        Console.WriteLine($"{Name} 在吃东西");
    }

    // 抽象方法:没有方法体,必须加 abstract
    public abstract void Shout();
}

子类必须要实现抽象方法,就是子类必须要override重写抽象方法

cs 复制代码
public class Dog : Animal
{
    // 必须实现抽象方法 Shout()
    public override void Shout()
    {
        Console.WriteLine("汪汪汪");
    }
}

public class Cat : Animal
{
    public override void Shout()
    {
        Console.WriteLine("喵喵喵");
    }
}

1.3推导过程

现在有一个猫和狗都会叫

cs 复制代码
public class Cat
{
    public void Shout()
    {
        Console.WriteLine("喵喵喵");
    }
}
public class Dog
{
    public void Shout()
    {
        Console.WriteLine("汪汪汪");
    }
}

但是很麻烦可以直接建立一个动物类

cs 复制代码
 public class Animal
 {
   public string Name { get; set; }
     public void Shout()
     {
         if(Name =="Cat")
         {
             Console.WriteLine("喵喵喵");
         }
         else if(Name == "Dog")
         {
             Console.WriteLine("汪汪汪");
         }
     }
 }

但是这样如果后面要加别的动物也很麻烦,而且这样也违反了开闭原则,不是新功能也一直在修改原类;这时候就可以使用重写把这个Animal类作为基类,这样加一个动物就重写Shout方法就好了

cs 复制代码
public class Animal //作为基类
{
   public string Name { get; set; }
public void Eat()
    {
        Console.WriteLine("动物吃");
    }
    public virtual void Shout()
    {
        Console.WriteLine("动物叫");
    }
}
public class Cat:Animal
{
    public override void Shout() //重写
    {
        Console.WriteLine("喵喵喵");
    }
}
public class Dog:Animal
{
    public override void Shout() //重写
    {
        Console.WriteLine("汪汪汪");
    }
}

现在Animal这个类一般也不会实例出来用Shout方法了那不如不写具体的方法把方法体删掉;这时候就是抽象方法了就把方法体删掉把virtual换成abstract 来修饰,类就变成了抽象类也要加abstract ,因为是基于重写的只是virtual换了所以派生类重写方法还是要有override;

而且现在派生类如果不重写Shout方法的话就会报错;

cs 复制代码
public abstract class Animal //抽象类
{
   public string Name { get; set; }
public void Eat()
    {
        Console.WriteLine("动物吃");
    }
    public abstract void Shout();//抽象方法
   
}
public class Cat:Animal
{
    public override void Shout()
    {
        Console.WriteLine("喵喵喵");
    }
}
public class Dog:Animal
{
    public override void Shout()
    {
        Console.WriteLine("汪汪汪");
    }
}

而且现在派生类如果不重写Shout方法的话就会报错;

cs 复制代码
public abstract class Animal //抽象类
{
   public string Name { get; set; }
    public abstract void Shout();//抽象方法
   
}
public class Cat:Animal //这样就会报错
{
   
}
public class Dog:Animal
{
    public override void Shout()
    {
        Console.WriteLine("汪汪汪");
    }
}

二、接口

2.1 定义 接口是什么?

接口就是一份 "规矩"、一份 "合同"。 它只规定:必须做什么,不规定怎么做。


接口里只有 "要求",没有 "实现"

比如你跟快递约定:

  • 必须能寄件
  • 必须能查运费

这就是接口

顺丰怎么做、京东怎么做,接口不管。你只要实现了这个接口,就必须按规矩写这两个方法。

注意接口的方法默认是public的因为接口里的所有方法都要被所有的派生类重写所以只能是默认public

2.2格式

用大写i开头 ,interface修饰

cs 复制代码
public interface IExpress
{
    void Send();    // 必须能寄
    decimal GetFee(); // 必须能算运费
}

2.3推导

在抽象类里还有正常的方法和属性;那如果一个抽象类要全是抽象的方法呢

cs 复制代码
public abstract class Animal
{
 public string Name { get; set; }//常规属性

    public void Eat()//常规方法
    {
        Console.WriteLine("动物吃");
    }

    public abstract void Shout();//抽象方法
    
}
   
public class Dog:Animal
{
    public override void Shout()
    {
        Console.WriteLine("汪汪汪");
    }
}

那就是接口了,因为接口可以理解为全是抽象方法的抽象类,所以可知:接口里的方法派生类必须要都要实现;而且这里不需要override了和继承差不多;

cs 复制代码
 interface iAnimal
 {
    void Shout();
     
 }

 public class Dog:iAnimal
 {
     public  void Shout()
     {
         Console.WriteLine("汪汪汪");
     }
 }

2.4 作用

接口的功能用基类继承也可以做到为什么还要有接口呢?

2.4.1. 最核心原因:C# 类只能继承一个父类

现实世界里,一个东西往往有多种身份

  • 人:既是动物 ,又是劳动者 ,还是消费者
  • 手机:既是通讯工具 ,又是相机 ,还是游戏机

但 C# 规定:一个类只能有一个直接父类,不能同时继承好几个类,但是可以继承无限的接口;

2.4.2. 接口代表 "能力",而不是 "种类"

  • 类继承:是什么 (is a)
    • Dog : Animal → 狗 动物
  • 接口实现:能做什么 (can do)
    • Dog : IRunnable → 狗 能跑
    • Ca'r : IRunnable → 车 也能跑

它们不是一家人,但拥有同一种能力,就可以用同一个接口统一调用。有基类又有接口的时候基类要写在前面:

cs 复制代码
class Player : GameObject, IMovable, IAttackable, IHealable//多接口
{
    // 第一个GameObject是基类名字
}

没有基类的时候
class Player : IMovable, IAttackable, IHealable//多接口
{
    
}

三、抽象类继承、普通继承、接口使用

  • 强制子类必须实现方法 → 用 abstract 抽象类
  • 有默认实现,子类可选重写 → 用 普通类 + virtual
  • 多能力、多 "证书",(多个基类 )→ 用 接口

学习时间:

26.03.27


相关推荐
小羊羔heihei2 小时前
Python列表操作全攻略
经验分享·笔记·python·学习·其他·交友
mo_alo2 小时前
Everything Claude Code 完全指南:给 Claude Code 装上涡轮增压【安装和使用超详细教程!!!】
笔记·embedding·ai编程·claude·ecc
kyq___3 小时前
环路稳定性补偿学习笔记
笔记·学习
CyrusCJA3 小时前
日语零基础每天学习笔记【11-20】
笔记·学习
oi..3 小时前
Flag入门—Flag在返回包中
网络·笔记·测试工具·安全·网络安全
职豚求职小程序3 小时前
[特殊字符]京东笔试在线系统练习笔试题库更新版本
笔记
NULL指向我3 小时前
信号处理学习笔记2:软件RC二阶高通\低通滤波
笔记·学习·信号处理
左左右右左右摇晃3 小时前
ConcurrentHashMap ——put + get
java·开发语言·笔记
朱一头zcy4 小时前
设计模式入门:最简单的模板方法模式
笔记·设计模式·模板方法模式