【从零开始入门unity游戏开发之——C#篇26】C#面向对象动态多态——接口(Interface)、接口里氏替换原则、密封方法(`sealed` )
文章目录
- 一、接口(`Interface`)
- 1、接口的定义
- 接口的基本语法:
- 2、接口的实现
- 实现接口:
- 3、接口的特性
- 4、接口的优势
- 5、小结
- 二、接口也遵循里氏替换原则
- 三、密封方法(`sealed` )
- 1、**密封方法的定义**
- 2、**如何使用密封方法**
- 示例代码:
- 3、**解释**
- 4、**为什么要使用密封方法?**
- 5、**注意事项**
- 6、**总结**
- 专栏推荐
- 完结
一、接口(Interface
)
在 C# 中,接口(Interface) 是一种定义契约的方式,它指定了类或者结构体应该提供哪些方法、属性、事件或索引器,但是不提供实现细节。接口为不同的类提供了一个共同的访问方式,使得它们能够通过接口进行交互。
接口与抽象类相似,都用于定义行为,但两者有一些重要的区别。接口只能包含方法的声明(没有实现),而抽象类可以包含方法的实现。
1、接口的定义
接口使用 interface
关键字定义,接口中的成员默认为 public
,且不能包含字段(只能包含方法、属性、事件和索引器)。此外,接口不能包含构造函数和静态成员。
接口命名规范:帕斯卡命名前面加个I
接口的基本语法:
public interface IAnimal
{
// 接口中的方法声明,不包含实现
void Speak();
// 接口中的属性声明
string Name { get; set; }
}
2、接口的实现
类或者结构体使用 : interface
来实现一个接口,并必须实现接口中声明的所有成员。
实现接口:
using System;
public interface IAnimal
{
void Speak();
string Name { get; set; }
}
public class Dog : IAnimal
{
public string Name { get; set; }
public Dog(string name)
{
Name = name;
}
// 实现接口中的 Speak 方法
public void Speak()
{
Console.WriteLine($"{Name} barks.");
}
}
public class Cat : IAnimal
{
public string Name { get; set; }
public Cat(string name)
{
Name = name;
}
// 实现接口中的 Speak 方法
public void Speak()
{
Console.WriteLine($"{Name} meows.");
}
}
class Program
{
static void Main()
{
IAnimal dog = new Dog("Buddy");
IAnimal cat = new Cat("Whiskers");
dog.Speak(); // 输出:Buddy barks.
cat.Speak(); // 输出:Whiskers meows.
}
}
在上面的代码中,IAnimal
是一个接口,Dog
和 Cat
类实现了该接口。每个类提供了对接口成员 Speak
方法的具体实现。
3、接口的特性
-
接口中的成员不能包含实现:
- 接口定义了方法签名和属性声明,但不包括方法体和属性的实现。接口只描述了功能,而不涉及实现。
-
类可以实现多个接口:
- 在 C# 中,一个类可以实现多个接口。这使得 C# 支持多重继承(通过接口实现),弥补了单继承的不足。
public interface IAnimal { void Speak(); } public interface IFlyable { void Fly(); } public class Bird : IAnimal, IFlyable { public void Speak() { Console.WriteLine("Bird chirps."); } public void Fly() { Console.WriteLine("Bird flies."); } }
-
接口成员是隐式
public
:- 接口中的成员默认是
public
,并且不能使用private
、protected
等访问修饰符。这意味着接口中的所有成员都会公开给实现它的类。
- 接口中的成员默认是
-
接口不能包含字段和静态成员:
- 接口中不能包含字段、构造函数、静态成员或静态方法,只有成员方法、属性、事件和索引器。
-
接口不能包含实现代码:
- 接口本身不提供任何实现,它仅定义类或者结构体应该提供的方法签名。实现接口的类才提供方法的实现。
-
接口可以继承其他接口:
- 接口可以继承其他接口,使得接口可以构建更加复杂和灵活的契约。
public interface IAnimal { void Speak(); } public interface IFlyable { void Fly(); } public interface IFlyingAnimal : IAnimal, IFlyable { // 继承自 IAnimal 和 IFlyable } public class Bird : IFlyingAnimal { public void Speak() { Console.WriteLine("Bird chirps."); } public void Fly() { Console.WriteLine("Bird flies."); } }
-
接口与抽象类的区别:
- 继承方式:类可以实现多个接口,但只能继承一个抽象类。
- 成员实现:抽象类可以包含方法实现,而接口只定义方法签名,不包含实现。
- 构造函数:抽象类可以有构造函数,而接口不能有构造函数。
- 字段:抽象类可以包含字段,接口则不能。
-
接口可以作为参数类型:
- 接口非常适合用于方法参数类型,以实现松耦合和多态性。
public class AnimalSoundPlayer { public void PlaySound(IAnimal animal) { animal.Speak(); } } class Program { static void Main() { IAnimal dog = new Dog("Buddy"); IAnimal cat = new Cat("Whiskers"); AnimalSoundPlayer soundPlayer = new AnimalSoundPlayer(); soundPlayer.PlaySound(dog); // 输出:Buddy barks. soundPlayer.PlaySound(cat); // 输出:Whiskers meows. } }
4、接口的优势
-
解耦:通过接口定义契约,使得不同的类之间的实现细节得以解耦。即使某些类的实现发生了变化,只要它们依然遵循接口的契约,外部代码就不需要修改。
-
多态:接口提供了多态性。通过接口类型引用不同实现类的对象,使得代码更加灵活和可扩展。
-
支持多重继承:C# 不支持类的多重继承,但通过接口可以实现多重继承的效果,一个类可以实现多个接口。
-
可扩展性和灵活性:接口可以用于扩展系统而不改变现有代码的结构。如果你想给某个类添加新的功能,只需要定义新的接口并让该类实现即可。
5、小结
- 接口 提供了一种方式来定义功能的契约或规范,而不涉及具体的实现。
- 接口可以被多个类实现,使得不同类能够共享相同的行为。
- 与抽象类不同,接口不包含任何实现代码,而是定义类必须实现的成员。
- 使用接口能够提高代码的可扩展性和灵活性,尤其适用于定义多个类之间共享的行为。
二、接口也遵循里氏替换原则
里氏替换原则:可以用父类容器装载子类对象
interface IRun { }
class GameObject { }
class Player : GameObject, IRun
{
public void PlayerAtk()
{
Console.WriteLine("玩家攻击");
}
}
class Monster : GameObject, IRun
{
public void MonsterAtk()
{
Console.WriteLine("怪兽攻击");
}
}
class Boss : GameObject, IRun
{
public void BossAtk()
{
Console.WriteLine("Boss攻击");
}
}
调用
IRun player = new Player();
IRun monster = new Monster();
IRun boss = new Boss();
if (player is Player)
{
(player as Player).PlayerAtk();
}
三、密封方法(sealed
)
在 C# 中,密封方法(sealed
method)是指在派生类中无法进一步被重写的方法。密封方法是通过 sealed
关键字来实现的,通常是为了阻止进一步的修改,确保在继承结构中该方法的行为是固定的。
1、密封方法的定义
-
基本概念:密封方法是用于防止在子类中重写的方法。它是通过在派生类中使用
sealed
关键字与override
关键字一起定义的。 -
使用场景:当你希望某个方法在继承层次结构中保持固定且不能被子类修改时,可以使用密封方法。
2、如何使用密封方法
在 C# 中,密封方法是通过在派生类中重写父类方法时使用 sealed
关键字来标记的。这样,子类就无法再重写这个方法。
示例代码:
using System;
class BaseClass
{
// 普通虚方法
public virtual void DoSomething()
{
Console.WriteLine("BaseClass: Doing something...");
}
}
class DerivedClass : BaseClass
{
// 重写父类的方法
public override void DoSomething()
{
Console.WriteLine("DerivedClass: Doing something...");
}
}
class FinalClass : DerivedClass
{
// 密封方法,防止在子类中被重写
public sealed override void DoSomething()
{
Console.WriteLine("FinalClass: Doing something in a sealed way...");
}
}
class Program
{
static void Main()
{
BaseClass obj = new FinalClass();
obj.DoSomething(); // 输出: FinalClass: Doing something in a sealed way...
}
}
3、解释
- BaseClass 类定义了一个虚方法
DoSomething
,该方法允许被子类重写。 - DerivedClass 类重写了
DoSomething
方法,使得它的行为发生了变化。 - FinalClass 类重写了
DoSomething
方法,并使用了sealed
关键字标记它。这样,FinalClass
不能再被任何进一步的派生类重写此方法。
4、为什么要使用密封方法?
-
控制继承结构:通过密封方法,可以确保某些方法的行为不会被进一步改变。这有助于保持代码的一致性和可预测性,特别是在设计中希望防止继承类修改某些关键功能时。
-
性能优化:在一些情况下,密封方法可以帮助编译器优化代码,因为密封方法在继承层次中不会被重写,所以编译器可以做更多的优化。
5、注意事项
- 只能在派生类中密封方法:即必须先在基类中定义为
virtual
或abstract
方法,然后才能在派生类中使用sealed
来封闭它。 - 不能密封非虚方法:只有虚方法(
virtual
或abstract
)才能被密封。普通的非虚方法不能使用sealed
关键字。
6、总结
密封方法(sealed
method)是 C# 中用于防止在子类中重写父类方法的一种机制,通常用于确保某些方法在继承层次结构中保持一致性和固定的行为。在派生类中使用 sealed
来标记一个方法时,后续的类将不能重写此方法,从而保证了该方法的行为不会被进一步改变。
专栏推荐
地址 |
---|
【从零开始入门unity游戏开发之——C#篇】 |
【从零开始入门unity游戏开发之——unity篇】 |
【制作100个Unity游戏】 |
【推荐100个unity插件】 |
【实现100个unity特效】 |
【unity框架开发】 |
完结
赠人玫瑰,手有余香!如果文章内容对你有所帮助,请不要吝啬你的点赞评论和关注
,你的每一次支持
都是我不断创作的最大动力。当然如果你发现了文章中存在错误
或者有更好的解决方法
,也欢迎评论私信告诉我哦!
好了,我是向宇
,https://xiangyu.blog.csdn.net
一位在小公司默默奋斗的开发者,闲暇之余,边学习边记录分享,站在巨人的肩膀上,通过学习前辈们的经验总是会给我很多帮助和启发!如果你遇到任何问题,也欢迎你评论私信或者加群找我, 虽然有些问题我也不一定会,但是我会查阅各方资料,争取给出最好的建议,希望可以帮助更多想学编程的人,共勉~