接口和类的继承。这是一种可以避免的模式吗?

发布于 2024-11-09 21:42:39 字数 1376 浏览 2 评论 0原文

对于在以下情况下应采取哪种方式,我将不胜感激。让我们看看我是否能解释清楚(英语不是我的母语,所以事情可能会变得混乱,抱歉)。

假设我有以下接口:

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 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

负佳期 2024-11-16 21:42:39

您可以通过使基本字段可用来减少重复:

IBlah blah;
protected IBlah Blah { get { return blah; } }

并在子类型上进行强制转换(因为您希望您选择的 blah 得到尊重):

public double Duh() {
    return ((IBlahOnSteroids)Blah).Duh();
}

您还可以在基本字段上使用泛型做一些事情 -输入(以避免强制转换),但我不确定它是否值得。但请注意,如果基类决定注入大量的装饰器(如果装饰器不提供第二个接口),这可能会爆炸。

You could reduce the duplication by making the base field available:

IBlah blah;
protected IBlah Blah { get { return blah; } }

and cast at the sub-type (since you expect your choice of blah to be respected):

public double Duh() {
    return ((IBlahOnSteroids)Blah).Duh();
}

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).

魔法少女 2024-11-16 21:42:39

一种替代模式是

public class Foo
{
    protected IBlah Blah { get; private set; }
    ...
}
public class FooOnSteroids : Foo 
{
    private new IBlahOnSteroids Blah { get { return (IBlahOnSteroids)base.Blah; } }
    ...
}

然而,这与您的代码没有太大不同;如果你不能使用泛型,它们都可以。

One alternative pattern is

public class Foo
{
    protected IBlah Blah { get; private set; }
    ...
}
public class FooOnSteroids : Foo 
{
    private new IBlahOnSteroids Blah { get { return (IBlahOnSteroids)base.Blah; } }
    ...
}

However, this isn't very different from your code; if you can't use generics, they're both fine.

小ぇ时光︴ 2024-11-16 21:42:39

针对您关于删除 Foo 和 FooOnSteroids 之间的继承的问题,我不知道您所有的推理,但我可以尝试提供一些一般性指导。您应该考虑使用继承,主要是为了向您的客户提供使用 FooOnSteroids 实例的能力,但只为 Foo 编写代码。

因此,如果从概念上讲您的客户这样做:

Foo foo = new FooOnSteroids();
foo.Frob()

您应该保留继承权。

如果您只是为了重用代码而创建继承关系,我建议您考虑重构这些类以包含提供共享功能的类。继承并不是代码重用的最佳模式。

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:

Foo foo = new FooOnSteroids();
foo.Frob()

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.

初见终念 2024-11-16 21:42:39

鉴于您不能使用泛型(这可能会或可能不会使您的特定用例变得更容易),我个人会选择转换 Fooblah 成员。 C# 中的转换相对轻松:

public double Duh()
{
    return (this.blah as IBlahOnSteroids).Duh();
}

如果无法将对象转换为您请求的类型,则 C# 中的 as 关键字将计算为 null。在上面的示例中,如果 this.blah 不是 IBlahOnSteroids 的实例,您将收到 NullReferenceException。您可以检查一个对象是否是某个类型的实例,如下所示:

public double Duh()
{
    if (this.blah is IBlahOnSteroids)
        return (this.blah as IBlahOnSteroids).Duh();
    else
        throw new InvalidTypeException("Blah is not an instance of IBlahOnSteroids");
}

尽管在原始示例的代码中,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 of Foo. Casting in C# is relatively painless:

public double Duh()
{
    return (this.blah as IBlahOnSteroids).Duh();
}

The as keyword in C# will evaluate to null if the object can't be cast into the type you requested. In the above example, if this.blah isn't an instance of IBlahOnSteroids you will get a NullReferenceException. You can check if an object is an instance of a type like so:

public double Duh()
{
    if (this.blah is IBlahOnSteroids)
        return (this.blah as IBlahOnSteroids).Duh();
    else
        throw new InvalidTypeException("Blah is not an instance of IBlahOnSteroids");
}

Though in the code in your original example it shouldn't be possible for blah to not be an instance of IBlahOnSteroids since it's assigned in the constructor, which makes that assertion at compile time for you.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文