使用多态时未在所有派生类实现virtual方法是否属于不良编程实践?
问题1:当前实现是否属于不良编程实践?
是的,这种实现确实是不推荐的,违反了接口隔离原则(ISP)——该原则要求类不应该被迫依赖它不需要的方法。你当前的实现存在两个明确的问题:
- 对不能跳跃的Orc来说,基类暴露的
Jump()方法无实际作用,Intellisense的提示确实会造成误导,调用者很可能在不知道Orc不能跳的情况下调用该方法,得到无反馈的异常结果。 - 如果后续你修改基类
Jump()的默认实现(比如不再留空,改为抛异常、打日志),所有未重写该方法的派生类都会被影响,不符合开闭原则的预期。
问题2:支持Enemy统一存数组的替代方案
你提到的类型转换繁琐的问题在C#高版本中已经有非常简洁的解决方式,以下是几种常用的优化方案:
方案1:能力接口+模式匹配(最推荐)
把非通用能力抽成独立接口,只有符合条件的派生类实现对应接口,遍历统一数组时用模式匹配判断是否具备对应能力,代码非常简洁:
// 抽离跳跃能力接口 public interface IJumpable { void Jump(); } abstract class Enemy { public abstract void Attack(); // 不再在基类定义Jump方法 } class Spider : Enemy, IJumpable { public override void Attack() { Console.WriteLine("Bite attack!"); } public void Jump() { Console.WriteLine("Spider jump animation"); } } class Goblin : Enemy, IJumpable { public override void Attack() { Console.WriteLine("Arrow attack!"); } public void Jump() { Console.WriteLine("Goblin jump animation"); } } class Orc : Enemy { public override void Attack() { Console.WriteLine("Axe attack!"); } }
调用时的写法(完全不需要手动强转):
Enemy[] enemies = new Enemy[] { new Spider(), new Goblin(), new Orc() }; foreach (var enemy in enemies) { enemy.Attack(); // 模式匹配判断是否可跳跃,一行代码完成判断+取值 if (enemy is IJumpable jumpable) { jumpable.Jump(); } }
方案2:基类增加能力标记属性
如果你不想引入接口,也可以在基类增加能力判断属性,避免无效的方法调用:
abstract class Enemy { public abstract void Attack(); // 派生类各自声明是否支持跳跃 public abstract bool CanJump { get; } public virtual void Jump() { if (!CanJump) { throw new InvalidOperationException("当前敌方单位不支持跳跃"); // 或者留空,但建议打调试日志避免调用方疑惑 } } } class Orc : Enemy { public override bool CanJump => false; public override void Attack() { Console.WriteLine("Axe attack!"); } } // 其他支持跳跃的派生类把CanJump设为true,重写Jump方法即可
方案3:组合实现能力(适合能力多、迭代频繁的场景)
如果你的敌方单位后续会加很多其他能力(比如攀爬、飞行),用组合的方式会比继承/接口更灵活:
// 跳跃行为抽象 public interface IJumpBehavior { void Jump(); } public class NormalJump : IJumpBehavior { public void Jump() => Console.WriteLine("执行跳跃动画"); } public class NoJump : IJumpBehavior { public void Jump() { /* 无操作,或者打日志 */ } } abstract class Enemy { protected IJumpBehavior _jumpBehavior; public abstract void Attack(); public void Jump() => _jumpBehavior.Jump(); } class Orc : Enemy { public Orc() { // 不能跳跃的单位赋值无操作的跳跃行为 _jumpBehavior = new NoJump(); } public override void Attack() { Console.WriteLine("Axe attack!"); } }
这种方案下你调用Jump()不需要做任何判断,逻辑由各自的行为组件实现,非常适合游戏这类需求变化快的场景。
内容的提问来源于stack exchange,提问作者boulder
相关产品推荐
相关产品推荐

