我想知道如果你想从原始基础继承一个方法而不是你的直接前任,是否有可能跳过继承三中的一个类。
例如,假设我有三个类,GrandParent,Parent(继承自GrandParent)和Child(继承自Parent)。 GrandParent有一个方法Adresse,而Parent有一个方法Adresse来覆盖它。但是,说出于某种原因,我希望Child拥有与GrandParent相同的Adresse方法,而不是Parent。如果我遇到这样的情况,这可能还是让我搞砸了?
以下示例代码位于C#
中class GrandParent
{
private String Adresse;
public GrandParent()
{
}
public virtual void setAdress(String Adresse)
{
this.Adresse = Adresse;
}
public String getAdress()
{
return Adresse;
}
}
class Parent : GrandParent
{
public Parent()
:base()
{
}
public override void setAdress(String Adresse)
{
base.setAdress("Home: " + Adresse);
}
}
class Child : Parent
{
public Child()
: base()
{
}
}
答案 0 :(得分:3)
如果您遇到此类问题,则表示您的应用程序设计不当。您需要了解SOLID设计原则。在这种情况下,Liskov substitution principle会很有用。使用继承时,请始终验证关系是否为IS-A。
理想情况下,代码重用应该通过组合而不是继承来完成。
如果您仍想使用继承,我可以考虑一些解决此问题的方法。
第一种可能性是添加NewChild
类而不是Parent
,并且特定的功能将在该类中,并且共享功能将保留在现有Parent
中。您可能决定保留新子项的现有名称,并为现有类找到另一个名称。
另一种不那么干净的可能性是为代码共享目的添加一些受保护的方法。
但我认为如果你想保留原始层次结构来修改Parent.setAddress
方法可能会更好,这样特殊行为就会依赖于其他东西,比如传递给构造函数的布尔值。
本质上,继承应遵循IS-A规则,其他方法应该用于代码重用。对于潜在的公共部分甚至其他类,它可能是一些受保护的方法。
答案 1 :(得分:0)
没有干净方法来“跳过继承树中的类”。如果你发现自己需要这样做(因为许多人只有一种方法需要这个bastardized),我建议完全删除继承,使用顶级类中的readonly委托来定义默认行为,并允许每个子类要么创建自己的委托,要么(如果它想要顶级行为而不是其父级)重置为顶级委托:
delegate string GetMyAddress(string baseAddress);
class Grandparent
{
protected readonly GetMyAddress _baseGetMyAddress;
protected GetMyAddress _getMyAddress;
public string BaseAddress = "Foo Street";
public Grandparent()
{
_baseGetMyAddress = (a) => { return String.Format("Grandparent: {0}", a); };
_getMyAddress = _baseGetMyAddress;
}
// no longer virtual
public string MyAddress()
{
return _getMyAddress(BaseAddress);
}
}
class Parent : Grandparent
{
public Parent()
{
// does something differing from the base
_getMyAddress = (a) => { return String.Format("Parent: {0}", a); };
}
}
class Child : Parent
{
public Child()
{
// does what its parent tells it to do
}
}
class ChildTakingAfterGrandparent : Parent
{
public ChildTakingAfterGrandparent()
{
// does what its grandparent does
_getMyAddress = _baseGetMyAddress;
}
}
class WillfulChild : Parent
{
public WillfulChild()
{
// does its own thing
_getMyAddress = (w) => { return String.Format("WillfulChild: {0}", w); };
}
}
public static void Run()
{
var gp = new Grandparent();
var p = new Parent();
var c = new Child();
var cg = new ChildTakingAfterGrandparent();
var wc = new WillfulChild();
Console.WriteLine("gp.MyAddress(): \"{0}\"", gp.MyAddress());
Console.WriteLine("p.MyAddress(): \"{0}\"", p.MyAddress());
Console.WriteLine("c.MyAddress(): \"{0}\"", c.MyAddress());
Console.WriteLine("cg.MyAddress(): \"{0}\"", cg.MyAddress());
}
调用Run()
方法将显示以下内容:
gp.MyAddress(): "Grandparent: Foo Street"
p.MyAddress(): "Parent: Foo Street"
c.MyAddress(): "Parent: Foo Street"
cg.MyAddress(): "Grandparent: Foo Street"
wc.MyAddress(): "WillfulChild: Foo Street"