没有抽象类的实现接口?

4
我正在编写一个库,我希望拥有一个接口。
public interface ISkeleton
{
    IEnumerable<IBone> Bones { get; }
    void Attach(IBone bone);
    void Detach(IBone bone);
}

对于每个ISkeleton,Attach()和Detach()的实现应该是相同的。因此,它可以基本上是这样的:

public abstract class Skeleton
{
    public IEnumerable<IBone> Bones { get { return _mBones; } }

    public List<IBone> _mBones = new List<IBone>();

    public void Attach(IBone bone)
    {
         bone.Transformation.ToLocal(this);
         _mBones.add();
    }

    public void Detach(IBone bone)
    {
        bone.Transformation.ToWorld(this);
         _mBones.Remove(bone);
    }
}

但是C#不允许多重继承。因此,除了其他问题之外,用户必须记住每次想要实现Skeleton时都要继承自Skeleton。
我可以使用扩展方法。
public static class Skeleton
{   
    public static void Attach(this ISkeleton skeleton, IBone bone)
    {
         bone.Transformation.ToLocal(skeleton);
         skeleton.Bones.add(bone);
    }

    public static void Detach(this ISkeleton skeleton, IBone bone)
    {
        bone.Transformation.ToWorld(this);
         skeleton.Bones.Remove(bone);
    }
}

但是我需要有 <\p>。
public interface ISkeleton
{   
    ICollection<IBone> Bones { get; }
}

我不希望这样做,因为它不是协变的,用户可以绕过Attach()和Detach()方法。

问题:我真的必须使用抽象骨架类吗?还有其他技巧或方法吗?


为什么必须是 IEnumerable - Daniel A. White
如果您的骨架实现将保持不变,那么首先要问的问题是为什么需要接口?我会使用抽象的SceletonBase。 - Renatas M.
2
为什么不让Skeleton/SkeletonBase实现ISkeleton,或者干脆完全摒弃ISkeleton - Oded
1
用户必须记住从Skeleton继承 - 这同样适用于ISkeleton,不是吗? - clearpath
1
Jake - 如果一个抽象概念没有用处,就把它去掉。 - Oded
显示剩余5条评论
5个回答

5

如果您需要在接口中公开 AttachDetach 方法,那么总有一种方法可以绕过您打算的实现,因为实现接口的所有对象都可以按照自己的风格实现它们。

您可以让抽象类 Skeleton 实现 ISkeleton,并且所有作为骨架的类都从 Skeleton 继承,因此它们也实现了 ISkeleton 接口。

public interface ISkeleton { ... }

public abstract class Skeleton : ISkeleton { ... } // implement attach and detach

public class SampleSkeleton : Skeleton { ... }

这样你就能将SampleSkeleton用作ISkeleton,只要你从Skeleton继承即可,无需实现这些函数,而将方法标记为sealed则无法覆盖它们(只要它们是实例方法)。
另外一点:请以Base结尾命名抽象类,或以其他方式标记基类(但这完全取决于您)。

在哪种情况下,ISkeleton不是必需的。 - Oded
@Oded 当然,你是正确的。但是如果抽象类Skeleton(或任何继承自它的类)提供其他公共方法(用于实现其他接口),则应使用接口来控制访问。 - Matten
关于我在帖子末尾提出的实际问题,你是说抽象类是正确的选择? - Jake
@Jake 不是和是的 :) 这完全取决于你的项目范围,特别是你的软件架构。使用接口来隐藏实现,但如果一个单独的类实现了整个接口而没有额外的功能(请参见Oded的评论),则不要使用接口。 - Matten

3

我会将骨头作为一种特殊类型来实现 IEnumerable<T>,这样它就不会违反单一职责原则。

public interface ISkeleton
{
    AttachableEnumerable<IBone> Bones { get; }
}

public class AttachableEnumerable<T> : IEnumerable<T>
{
    // implementation needed.
    void Attach(T item);
    void Detach(T item);
}

是的,这完美地运作了。我太尴尬了,没能看出这个模式。 - Jake

1
如果你想封装ISkeleton的行为,你可以将其作为一个组合对象而不是继承行为。
public class Body : ISkeleton
{
    private SkeletonImpl _skeleton = new SkeletonImpl;

    public IEnumerable<IBone> Bones { get { return _skeleton.Bones; } }

    public void Attach(IBone bone)
    {
        _skeleton.Attach(bone);
    }

    public void Detach(IBone bone)
    {
       _skeleton.Detach(bone);
    }
}

0

0
你可以创建一个包装类,实现“Attach”和“Detach”方法,并将此功能注入到你的接口中。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接