简体   繁体   中英

Interface with implementation without abstract class?

I am writing a library and I want to have an interface

public interface ISkeleton
{
    IEnumerable<IBone> Bones { get; }
    void Attach(IBone bone);
    void Detach(IBone bone);
}

The Attach() and Detach() implementation actually should be the same for every ISkeleton. Thus, it could essentially be:

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);
    }
}

But C# doesn't allow multiple inheritance. So among various issues, users have to remember to inherit from Skeleton every time they want to implement Skeleton.

I could use extension methods

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);
    }
}

But then I need to have

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

Which I do not want, because it is not covariant and users can bypass the Attach() and Detach() methods.

Question: Must I really use an abstract Skeleton class or are there any or tricks and methods?

If you need to expose the Attach and Detach methods in your interface, there is always a way to bypass your intended implementations, as all objects implementing the interface can implement them on their own style.

You can let the abstract class Skeleton implement ISkeleton and all classes which are Skeletons do inherit from Skeleton , thus they implement ISkeleton as well.

public interface ISkeleton { ... }

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

public class SampleSkeleton : Skeleton { ... }

This way you can use your SampleSkeleton as ISkeleton , you don't have to implement these functions as long as you inherit from Skeleton and marking the methods as sealed does not allow overriding them (as long as they are instance methods).

On a side node: Do name your abstract class with Base at the end or mark the base class somehow else (but this is surely up to you).

I would make bones a special type that implements IEnumerable<T> . That way it doesn't violate the single responsibility principle.

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

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

If you want to wrap ISkeleton behaviour, you could always make it a composite object instead of inheriting the behaviour:

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);
    }
}

May be you just have to use sealed methods on abstract Skeleton class? This way they can't be overriden.

http://msdn.microsoft.com/en-us/library/aa645769(v=vs.71).aspx

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

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM