关于OOP中“铸造操作”的问题

时间:2010-05-28 05:14:27

标签: oop

编程时,我们通常使用一些类型转换操作。

当铸件发生在“同一级别”的物体上时,感觉还可以。但当它发生在“不同层面”(主要是父子之间)的对象上时,感觉很奇怪。

考虑到这一点:

Class Son extends Father

Son s = (Son)father;时,这绝对是不合理的。因为“儿子”不再是“父亲”,“儿子”可能会成长为“父亲”没有的一些新属性,所以施放操作使这些属性不为人知。

另一方面,Father f = (Father)son似乎是合理的,但根据LSP

  

“派生的实例应该能够替换其超类的任何实例”

“儿子”可以做任何他的“父亲”可以做的事情,所以施法操作似乎毫无用处。

那么我可以说这些铸造操作是非常好的OO设计原则但是必要吗?

5 个答案:

答案 0 :(得分:2)

我发现像这样的问题总是很有趣,它有助于我认为的某种辩论:)

以下是我的想法。 在课堂设计中,我会在这种情况下创建一个Person

class Person
{
    public bool IsFather { get; set; } // this variable will change depending on the count of children
    public List<Person> children { get; set; }
}

当我创建派生类时,该类应该是一个专门的人,在父和子的情况下,我不会创建一个父类和一个Son类。

答案 1 :(得分:2)

在OOP中转换对象通常是类继承或接口继承的产物。必须要记住,类继承表示“是一个”关系,接口继承表示“有一个”关系。

让我们回到你的例子:Class Son extends Father听起来不是一个合理的抽象,因为每个男性都是儿子,但不是所有男性都是父亲。事实上,相反的情况可能更适用:Class Father extends Son因为每个父亲都是某人的儿子。

另一方面,我们可以放弃整个抽象,并说我们有一个Class Person,可以是男性或女性,母亲或父亲,等等。每个人都有一个属性,其中包含名为Person的{​​{1}}集合。

在此抽象中,如果Children的性别为男性且Person,则Father将仅被视为Person.Children.Count > 0。这比在其中定义Father类要简单得多。

答案 2 :(得分:1)

你有一个糟糕的继承例子。

更好的可能是

Class Person 
{
    public void walk();
}
Class Man extends Person
{
    public void shaveBeard();
}

继承是表示关系的方式;例如“ManPerson”。

使用对象

这些行中的任何一行都可以。

Person p = new Person();
Person m = new Man();

可以在两者上调用p.walk。但是,要调用shavebeard()方法,m必须是Man对象。出于类型安全的原因,您必须将其强制转换为Man对象;例如(Man) m.shaveBeard();此处的投射会失败,因此最好检查变量是否指向Man的实例:

if(m instanceof Man)
{
   (Man) m.shaveBeard(); 
}

答案 3 :(得分:0)

对我来说似乎都不合理。似乎更合理的是:

Son s = (Son)person          //Valid
Father f = (Father)person    //Valid

答案 4 :(得分:0)

这是一个提示:左侧的类是超类,而右侧的类是子类,所以如果我们有这个: 对象p = new Student(); //是正确的 Student s = new Object()//错了......就像说每个Object都是学生.. 在进行显式转换时必须小心,因为它可能看起来正确但可能无法按预期工作。你不能自己实例化你父亲的私有财产。