接口和类的继承。这是一种可以避免的模式吗?
对于在以下情况下应采取哪种方式,我将不胜感激。让我们看看我是否能解释清楚(英语不是我的母语,所以事情可能会变得混乱,抱歉)。
假设我有以下接口:
internal interface IBlah
{
int Frob();
}
internal interface IBlahOnSteroids: IBlah
{
double Duh();
}
现在我们有一个 Foo 类,与 IBlah 对象具有“has a”关系:
public class Foo
{
IBlah blah;
internal Foo(IBlah blah)
{
this.blah = blah;
}
public int Frob()
{
....
return this.blah.Frob();
}
}
现在我们还需要一个 FooOnSteroids 类,它与 IBlahOnSteroids 对象具有“has a”关系。 问题是,知道 IBlahOnSteroids 的一部分已经在 Foo 中实现,如果我们创建会发生什么 FooOnSteroids 继承自 Foo?
我们会得到这样的信息:
public class FooOnSteroids: Foo
{
IBlahOnSteroids blah;
internal FooOnSteroids(IBlahOnSteroids blah)
:base(blah)
{
this.blah = blah;
}
public double Duh()
{
return this.blah.Duh();
}
}
这是推荐的模式吗?我们在继承链上传递相同的“blah”对象,并且在每个“级别”我们将其存储在私有对象中 具有“有用”类型的字段。我认为我不可能将受保护的财产存储在 BlahBase 中 公开了对所有降序类的一个常见的 IBlah 引用,因为它必须是 IBlah 类型,这对 BlahOnSteroids 没有任何用处。这情景还算吗 受到推崇的?或者我们应该将 Foo 和 FooOnSteroids 实现为没有继承的独立类(这会造成代码重复)?也许这样做绝对没问题,但不知何故感觉像是黑客攻击。是吗?
使用泛型的选项可以立即解决问题,但这是不可能的,因为,是的,我知道这很糟糕,这个库必须针对 .Net 1.x 平台。
仅实现 BlahOnSteroids 的选项也是一种可能性,但这意味着根据调用者的不同,如果出现以下任何情况,我们将不得不抛出异常: IBlahOnSteroids 成员被称为。我不喜欢这样。
非常感谢您的任何建议!
I'd appreciate any advice on which way to go on in the following scenario. Let's see if I can explain it clearly (english is not my native language so things might get confusing, sorry).
Suppose I have the following interfaces:
internal interface IBlah
{
int Frob();
}
internal interface IBlahOnSteroids: IBlah
{
double Duh();
}
Now we have a Foo class with a 'has a' relationship with an IBlah object:
public class Foo
{
IBlah blah;
internal Foo(IBlah blah)
{
this.blah = blah;
}
public int Frob()
{
....
return this.blah.Frob();
}
}
Now we also need a FooOnSteroids class that has a 'has a' relationship with a IBlahOnSteroids object.
The question is, knowing that part of IBlahOnSteroids is already implemented in Foo, what happens if we create
FooOnSteroids inheriting from Foo?
We would get something like this:
public class FooOnSteroids: Foo
{
IBlahOnSteroids blah;
internal FooOnSteroids(IBlahOnSteroids blah)
:base(blah)
{
this.blah = blah;
}
public double Duh()
{
return this.blah.Duh();
}
}
Is this a recommended pattern? We are passing down the inheritance chain the same 'blah' object and at each "level" we are storing it in a private
field with a 'useful' type. There is no way, that I can see, that I could store in BlahBase a protected property that
exposed one common IBlah reference to all descending classes as it would have to be of type IBlah wich would be of no use to BlahOnSteroids. Is this scenario even
recommended? Or should we just implement Foo and FooOnSteroids as independent classes with no inheritance (this would create code duplication)? Maybe its absolutely fine to do this, but it somehow feels like a hack. Is it?
The option of using generics, which would solve the problem in no time, is not possible as, yes I know it sucks, this library must target .Net 1.x platforms.
The option of just implementing BlahOnSteroids is also a possibility but it would mean that depending on the caller, we would have to throw an exception if any of
IBlahOnSteroids members was called. I dont like that.
Thanks a lot for any advice!
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(4)
您可以通过使基本字段可用来减少重复:
并在子类型上进行强制转换(因为您希望您选择的
blah
得到尊重):您还可以在基本字段上使用泛型做一些事情 -输入(以避免强制转换),但我不确定它是否值得。但请注意,如果基类决定注入大量的装饰器(如果装饰器不提供第二个接口),这可能会爆炸。
You could reduce the duplication by making the base field available:
and cast at the sub-type (since you expect your choice of
blah
to be respected):You could also do something with generics on the base-type (to avoid the cast) but I'm not sure it is worth it. Note, however, that this might explode if the base-class decides to inject a decorator abound
blah
(if the decorator doesn't provide the second interface).一种替代模式是
然而,这与您的代码没有太大不同;如果你不能使用泛型,它们都可以。
One alternative pattern is
However, this isn't very different from your code; if you can't use generics, they're both fine.
针对您关于删除 Foo 和 FooOnSteroids 之间的继承的问题,我不知道您所有的推理,但我可以尝试提供一些一般性指导。您应该考虑使用继承,主要是为了向您的客户提供使用 FooOnSteroids 实例的能力,但只为 Foo 编写代码。
因此,如果从概念上讲您的客户这样做:
您应该保留继承权。
如果您只是为了重用代码而创建继承关系,我建议您考虑重构这些类以包含提供共享功能的类。继承并不是代码重用的最佳模式。
In response to your question about removing the inheritance between Foo and FooOnSteroids, I don't know all your reasoning, but I can try to provide some general guidance. You should consider using inheritance mainly to provide your clients the ability to use FooOnSteroids instances, but only write the code for Foo.
So, if conceptually your clients do this:
you should keep the inheritance.
If you are creating the inheritance relationship ONLY to re-use code, I suggest you consider refactoring the classes to contain a class which provides the shared functionality. Inheritance is not the best pattern for code re-use.
鉴于您不能使用泛型(这可能会或可能不会使您的特定用例变得更容易),我个人会选择转换
Foo
的blah
成员。 C# 中的转换相对轻松:如果无法将对象转换为您请求的类型,则 C# 中的
as
关键字将计算为null
。在上面的示例中,如果this.blah
不是IBlahOnSteroids
的实例,您将收到NullReferenceException
。您可以检查一个对象是否是某个类型的实例,如下所示:尽管在原始示例的代码中,
blah
不可能可能不是一个实例的 IBlahOnSteroids ,因为它是在构造函数中分配的,这会在编译时为您做出该断言。Given that you can't use generics (which may or may not make your specific use case easier) I would personally opt for casting the
blah
member ofFoo
. Casting in C# is relatively painless:The
as
keyword in C# will evaluate tonull
if the object can't be cast into the type you requested. In the above example, ifthis.blah
isn't an instance ofIBlahOnSteroids
you will get aNullReferenceException
. You can check if an object is an instance of a type like so:Though in the code in your original example it shouldn't be possible for
blah
to not be an instance ofIBlahOnSteroids
since it's assigned in the constructor, which makes that assertion at compile time for you.