【发布时间】:2012-06-11 23:20:23
【问题描述】:
我正在为“可运行”的东西开发一个迷你框架。 (它们是实验、测试、任务等)
// Something that "runs" (in some coordinated way) multiple "runnable" things.
interface IRunnableOf<T> where : IRunnable
// Provide base-class functionality for a "runner"
abstract class RunnerBase<T> : IRunnableOf<T>
class SequentialRunner<T> : RunnerBase<T> // Same interface, different behavior.
class ConcurrentRunner<T> : RunnerBase<T>
// other types of runners.
class ConcurrentBlockRunner : SequentialRunner<Block>
class SequentialBlockRunner : ConcurrentRunner<Block>
现在,我该如何协调 ConcurrentBlockRunner 和 SequentialBlockRunner?我的意思是:
由共同的祖先引用它们,以便在集合中使用。 (
IEnuerable<T>其中 T = ??)提供额外的基类功能。 (例如,添加一个属性)。
我通过添加另一个只为IA<T> 指定类型参数的接口来补救#1:
interface IBlockRunner : IRunnableOf<Block> { }
并将我的 ConcurrentBlockRunner 和 SequentialBlockRunner 定义修改为:
class ConcurrentBlockRunner : SequentialRunner<Block>, IBlockRunner
class SequentialBlockRunner : ConcurrentRunner<Block>, IBlockRunner
由于ConcurrentBlockRunner 和SequentialBlockRunner 都使用Block 作为它们的类型参数,这似乎是一个正确的解决方案。但是,我不禁对此感到“奇怪”,因为我只是添加了那个界面。
对于#2,我想向ConcurrentBlockRunner 和SequentialBlockRunner 添加一些公共数据。有几个属性适用于它们,但不适用于它们唯一的公共基类,一直到 RunnerBase<T>。
这是我第一次在使用 C# 时觉得多重继承会有所帮助。如果可以的话:
abstract class BlockRunnerBase {
int Prop1 { get; set; }
int Prop2 { get; set; }
class ConcurrentBlockRunner : SequentialRunner<Block>, BlockRunnerBase
class SequentialBlockRunner : ConcurrentRunner<Block>, BlockRunnerBase
然后我可以简单地将这些额外的属性添加到 BlockRunnerBase,一切都会正常工作。有没有更好的办法?
我知道我会立即被推荐考虑composition,我开始使用它:
class BlockRunner : IBlockRunner {
IBlockRunner _member;
int Prop1 { get; set; } // Wish I could put these in some base class
int Prop2 { get; set; }
// Lots of proxy calls, and proxy events into _member
void Method() { _member.Method(); }
event SomeEvent
{
add { _member.SomeEvent += value; }
remove { _member.SomeEvent -= value; }
}
}
我遇到的问题(促使我写这个问题)是一旦你写了,你就失去了类型兼容性。在我的例子中,_member 触发了一个事件,所以sender 参数的类型是SequentialBlockRunner。但是,事件处理程序试图将其转换为类型BlockRunner,这当然失败了。那里的解决方案不是使用add/remove 来代理事件,而是实际上处理它们,并引发我自己的事件。仅仅为了添加几个属性就做了这么多工作......
【问题讨论】:
-
如果你需要多重继承——你的设计很糟糕。你的实际情况是什么,没有
A、B等代号? -
在其他语言中存在多重继承的有效用例...例如 C++。但是 C++ 没有接口和扩展方法。
-
@Yorye,将多重继承请求一概驳回为“糟糕的设计”,这表明您不理解。 C++ 设计者添加 MI 支持是有原因的,我相信 Bjarne 比你聪明得多。在其他语言中也是如此。 MI 很难做好,但也非常有用。
-
您是否考虑过以不同的方式解决这个问题,也许不是从传统的 OOP 角度来解决这个问题,而是考虑完全不同的东西,例如 AOP?那么,您可以使用方面向某些 IRunnable
注入“BlockRunner”行为吗?这些天,当我遇到 MI 问题时,我开始自动思考“方面”而不是“对象”。 -
@Yorye:C# 迎合的程序员和 C++ 设计的程序员之间存在很大差异。 C# 放弃了许多特性,不是因为它们没有用,而是因为它们很难正确使用(有时对程序员来说,更常见于编译器编写者)。例如,C# 没有提供任何接近 C++ 模板的功能。这不是“我们在 20 年的经验中学到了一些东西”,这是“足够熟练的程序员处理模板和他们的错误消息不是在寻找一种新的语言,让我们为那些没有的程序员制作一种更简单的语言。”
标签: c# oop multiple-inheritance