我正在写一个库,我想要一个接口
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);
}
}
但是我需要
public interface ISkeleton
{
ICollection<IBone> Bones { get; }
}
我不想要,因为它不是协变的,用户可以绕过Attach()和Detach()方法。
问题:我真的必须使用抽象的Skeleton类,还是有任何或技巧和方法?
答案 0 :(得分:5)
如果需要在界面中公开Attach
和Detach
方法,总会有一种方法绕过预期的实现,因为实现界面的所有对象都可以按照自己的风格实现它们。
您可以让抽象类Skeleton
实现ISkeleton
,并且所有Skeletons类都继承自Skeleton
,因此它们也会实现ISkeleton
。
public interface ISkeleton { ... }
public abstract class Skeleton : ISkeleton { ... } // implement attach and detach
public class SampleSkeleton : Skeleton { ... }
这样您就可以将SampleSkeleton
用作ISkeleton
,只要您继承Skeleton
并将方法标记为sealed
,就不必实现这些功能}不允许覆盖它们(只要它们是实例方法)。
在一个侧节点上:在末尾用Base
命名你的抽象类,或者以其他方式标记基类(但这肯定取决于你)。
答案 1 :(得分: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);
}
答案 2 :(得分: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);
}
}
答案 3 :(得分:0)
你可能只需要在抽象的Skeleton类上使用密封方法吗? 这样他们就无法覆盖。
http://msdn.microsoft.com/en-us/library/aa645769(v=vs.71).aspx
答案 4 :(得分:0)
您可以创建一个实现“Attach”和“Detach”方法的包装类,并将此功能注入您的接口。