【发布时间】:2019-08-23 12:23:04
【问题描述】:
考虑到已接受的答案here,一般建议的想法是,在可能的情况下,倾向于定义类而不是接口。
考虑以下设计:
- 基类
ChessPiece,其中还定义了多个子类 -
某些类型的片段如果已经被移动,则需要记录(即
Pawn、Rook、King):bool HasMoved属性 - 一类棋子,即
King,无法捕获;其他一切都可以是:bool IsCaptured属性
问题是因为派生类King在#2和3中常见的#2和3之间的冲突(如果我只实现两者中的一个就没有问题)。
理想情况下,应该实现两个抽象类CapturablePiece 和MoveRecordedPiece,它们都继承自ChessPiece。但是 C#不允许多类继承,这就是接口的用武之地。
如果实现了接口,现在所有具体的子类都可以手动实现每个必需的属性。那么考虑这个例子:
// needed type-check
ChessPiece piece;
// some calculations...
if (piece is ICapturablePiece) // or using the 'as' keyword
//or...
if (piece is IMoveRecordedPiece)
// which in the case of non-conflicting abstract classes,
// this is easily doable and valid because of
// inheritance to the base class
我不能这样做,因为接口是原样的。它不能从任何东西继承,它只是必须实现的方法的独立标记。
抽象类版本仍然更可取 - CapturablePiece 和 MoveRecordedPiece,因为它的基本类型是 ChessPiece,我确信这个逻辑是“is-an " 而不是 "can-do"(如上面的链接中所述)。
我现在的问题是,我将如何改进设计考虑:
- 你不能继承多个类,接口不能继承任何东西。
- 抽象类优于接口
- 需要类型检查的代码块
编辑:
这不是链接问题的重复。这更像是在考虑接口和抽象类的同时如何改进设计。
【问题讨论】:
-
我猜大部分人都回答了here
-
请记住,Microsoft 设计指南中的“首选类而不是接口”来自于向后兼容的问题——你不能在不破坏向后兼容的情况下向接口添加方法。如果这些类型都只是在你自己的代码中使用,那不是问题,所以不用担心。在你的例子中,我会使用接口——接口描述对象的一些行为——“这个对象可以被捕获”,“这个对象可以保留它的移动历史”等等。虽然在实践中,我不会使用这里的任何接口:
ChessPiece将有bool IsCaptured -
再次阅读您的问题,您能解释一下“我不能这样做,因为接口是原样的” 是什么意思吗?
-
This series 作者是 Eric Lippert,对于试图将类型系统与游戏规则结合起来的人们来说,这是必读的。确保您阅读了所有 5 个部分 - 第 5 部分尤其重要。
-
再次感谢@John。
标签: c# oop abstract-class abstraction