多态性-单一职责原则(Weapon,Player)封装,只暴露了必要的接口
-
静态类型(Static Type): 静态类型是在编译时已知的,它是在代码编写时指定的变量类型。在您的代码中,
currentWeapon
的静态类型是Weapon
,因为我们声明它为Weapon
类型的变量。这意味着在编译时,编译器知道currentWeapon
是一个Weapon
对象。 -
动态类型(Dynamic Type): 动态类型是在运行时实际引用的对象的类型。在运行时,变量可以引用不同类型的对象,这就是多态性的体现。在您的代码中,
currentWeapon
的动态类型可以是Pistol
、Shotgun
或SubmachineGun
中的任何一个,具体取决于您在运行时将哪种类型的武器分配给它。 -
我们创建了一个
SubmachineGun
类的实例,并将其分配给了smg
变量。在编译时,smg
的静态类型仍然是Weapon
,但在运行时,它引用了SubmachineGun
的实例,因此它的动态类型是SubmachineGun
。当调用
player.UseWeapon()
时,currentWeapon
的动态类型(在这种情况下是SubmachineGun
)决定了哪个Fire
方法将被调用。这正是多态性的概念:相同的方法调用可以根据实际引用的对象的类型而具有不同的行为。所以,尽管currentWeapon
的静态类型是Weapon
,但在运行时,它引用了SubmachineGun
的实例,因此调用的是SubmachineGun
类中的Fire
方法。这就是为什么在
player.UseWeapon()
中能够使用SubmachineGun
中的Fire
方法的原因。多态性允许我们根据实际对象的类型来调用适当的方法,而不受静态类型的限制。
class Weapon
{
public string Name { get; set; }
public Weapon(string name)
{
Name = name;
}
public virtual void Fire()
{
Console.WriteLine($"使用了{Name}开火~~~~");
}
class Pistol : Weapon
{
public Pistol() : base("Pistol")
{
}
}
class Shotgun : Weapon
{
public Shotgun() : base("Shotgun")
{ }
}
class SubmachineGun : Weapon
{
public SubmachineGun() : base("SubmachineGun")
{
}
public override void Fire()
{
Console.WriteLine("Firiiiiiiiiiiinnnnnnngggggggggggggg the motherfuck");
}
}
class Player
{
private Weapon currentWeapon;
public Player()
{
currentWeapon = new Pistol();
}
public void PickUpWeapon(Weapon newWeapon)
{
Console.WriteLine($"你拾取了新武器{newWeapon}");
currentWeapon = newWeapon;
}
public void UseWeapon()
{
currentWeapon.Fire();
}
}
class Program
{
static void Main(string[] args)
{
Player player = new Player();
player.UseWeapon();
Weapon smg = new SubmachineGun();
player.PickUpWeapon( smg );
player.UseWeapon();
Weapon shotgun = new Shotgun();
player.PickUpWeapon(shotgun);
player.UseWeapon();
}
/* 还可以这样使用
SubmachineGun submachineGun = new SubmachineGun();
submachineGun.SpecialMethod(); // 调用 SubmachineGun 类中的特有方法
// 或者
if (weapon is SubmachineGun submachineGun)
{
submachineGun.SpecialMethod(); // 调用 SubmachineGun 类中的特有方法
}
*/
接口演示来实现相同的功能
using System;
// 武器接口
public interface IWeapon
{
void Fire();
}
// 不同类型的武器实现接口
public class SubmachineGun : IWeapon
{
public void Fire()
{
Console.WriteLine("使用冲锋枪开火!");
}
}
public class Shotgun : IWeapon
{
public void Fire()
{
Console.WriteLine("使用散弹枪开火!");
}
}
public class Pistol : IWeapon
{
public void Fire()
{
Console.WriteLine("使用手枪开火!");
}
}
// 玩家类
public class Player
{
private IWeapon currentWeapon;
public Player()
{
// 默认武器
currentWeapon = new Pistol();
}
// 拾取武器并替换当前武器
public void PickUpWeapon(IWeapon newWeapon)
{
Console.WriteLine($"拾取了 {newWeapon.GetType().Name}");
currentWeapon = newWeapon;
}
// 使用当前武器
public void UseWeapon()
{
currentWeapon.Fire();
}
}
class Program
{
static void Main()
{
Player player = new Player();
player.UseWeapon(); // 使用默认武器(手枪)
IWeapon smg = new SubmachineGun();
player.PickUpWeapon(smg); // 拾取冲锋枪
player.UseWeapon(); // 使用冲锋枪
IWeapon shotgun = new Shotgun();
player.PickUpWeapon(shotgun); // 拾取散弹枪
player.UseWeapon(); // 使用散弹枪
}
}
第二个代码演示
class Shape
{
public virtual double Area()
{
return 0;
}
}
class Circle : Shape
{
private double radius;
public Circle(double r)
{
radius = r;
}
public override double Area()
{
return Math.PI * radius * radius;
}
}
class Rectangle : Shape
{
private double width;
private double height;
public Rectangle(double w, double h)
{
width = w;
height = h;
}
public override double Area()
{
return width * height;
}
}
class Program
{
static void Main()
{
Shape shape1 = new Circle(5);
Shape shape2 = new Rectangle(4, 6);
Console.WriteLine($"形状1的面积:{shape1.Area()}");
Console.WriteLine($"形状2的面积:{shape2.Area()}");
}
}
优点缺点
使用接口的优点:
-
实现多继承: 接口允许一个类实现多个接口,这克服了一些编程语言(如C#和Java)不支持多重继承的限制。通过实现多个接口,一个类可以获得多个不同的行为。
-
松耦合: 接口提供了一种松耦合的方式来定义类之间的合同。类只需要遵循接口定义的方法,而不需要关心其他类的具体实现。这增强了代码的灵活性和可维护性。
-
代码重用: 接口允许多个类实现相同的接口,从而促进了代码重用。您可以在不修改现有代码的情况下添加新的实现类。
使用接口的缺点:
-
增加复杂性: 当一个类实现多个接口时,可能会增加类的复杂性,特别是当接口具有多个方法时。这可能会导致代码难以理解和维护。
-
过多的接口: 过多的接口可能导致类的实现变得冗长,增加了开发和维护的工作量。
使用多态性的优点:
-
灵活性: 多态性允许不同的对象以相同的接口进行操作,这增加了代码的灵活性。您可以根据实际对象的类型来调用适当的方法。
-
扩展性: 新的子类可以轻松地添加到应用程序中,而不会影响现有的代码。这使得应用程序更容易扩展。
-
代码简洁性: 多态性使得代码更具可读性和简洁性,因为它可以减少条件语句和分支。
使用多态性的缺点:
-
性能开销: 虽然多态性在设计上提供了灵活性,但在一些情况下可能会引入性能开销,特别是在运行时解析对象类型时。
-
复杂性: 当代码中存在大量的子类和多态性时,可能会增加代码的复杂性,使得程序难以维护和理解。
综上所述,使用接口和多态性都有其适用的场景和优点。通常,接口更适合定义合同和规范,以确保类遵循特定的接口。多态性则更适合在运行时根据实际对象类型来实现不同的行为。在实际编程中,通常需要根据具体需求和设计目标来决定何时使用接口、多态性或两者结合使用,以达到最佳的代码设计和架构