同时调用类似的超类和子类方法(Calling similar superclass and subclass methods at the same time)

我正在制作一个程序,其中我有一个Person子类和一个Animal超类。 我想知道在两者中同时调用类似方法的最佳方法是什么。 例如,一种方法是:

public abstract class Animal { public void walk() { // Do stuff childWalk(); } public abstract void childWalk(); } public class Person extends Animal { @Override public void childWalk() { // Do stuff } }

这样,我可以调用person.walk()并同时调用子方法和父方法,并在两者中运行代码。 我考虑的另一种方式是:

public abstract class Animal { public void walk() { // Do stuff } } public class Person extends Animal { @Override public void walk() { super.walk(); // Do stuff } }

这似乎更好,仍然称为person.walk()然而它仍然不理想,我不禁觉得有一种更有效的方法,我没有想到这样做。 让子类知道父类的方法是否被调用是错误的。 (无论如何,应该始终调用Animal.walk())也许我会以错误的方式进行调查,而实际上我根本不需要这样做? 我希望能够做到这一点的原因是因为每个Animal在行走时都需要做事情,但有时候一个人想要添加这种行为,或许为每一步增加一个变量,或者其他东西。

也许这个问题很愚蠢,但我一直在谷歌搜索一段时间,并没有看到简单的答案。

I'm making a program where I have a Person subclass and an Animal superclass. I'm wondering what's the best way of calling a similar method in both at the same time. For instance, one way to do this would be:

public abstract class Animal { public void walk() { // Do stuff childWalk(); } public abstract void childWalk(); } public class Person extends Animal { @Override public void childWalk() { // Do stuff } }

This way, I could call person.walk() and have both the child and parent methods called one after another, running the code in both. Another way I have considered is:

public abstract class Animal { public void walk() { // Do stuff } } public class Person extends Animal { @Override public void walk() { super.walk(); // Do stuff } }

Which seems to be nicer, still calling person.walk() however it's still not ideal, and I can't help but feel that there's a more efficient way of doing this that I've not thought of. It feels wrong to have it up to the child class as to whether the parent class's method is called. (Animal.walk() should always be called no matter what) Perhaps I'm going about it in the wrong way, and I don't actually need to do this at all? The reason I want to be able to do this is because every Animal needs to do things when it walks, but sometimes a Person wants to add to this behavior, perhaps incrementing a variable for every step, or something.

Perhaps this question is silly, but I've been googling for a while and see no easy answers.

最满意答案

实现此目的的一种方法是使walk() final,并让它调用抽象方法。 所以,

abstract class Animal { public final void walk() { // do stuff moreWalking(); } protected abstract void moreWalking(); } class Person extends Animal { protected void moreWalking() { // do stuff } }

请注意,我使用了一个受保护的级别访问器(非公共或私有),因此它在派生类中是可覆盖的,但不能被客户端调用。

此外,这个代码是一个“草图”,我遗漏了很多重要的东西,比如Davidxx在他的回答中谈到的Animal界面。

一旦这样做的结果是Animal的子类'必须'实现moreWalking() 。 这可以通过在基类中使用默认实现来缓解,或者通过不使用抽象方法并提供“空”实现来缓解,如下所示:

abstract class Animal { public final void walk() { // do stuff moreWalking(); } protected void moreWalking() { } } class Person extends Animal { protected void moreWalking() { // do stuff } } class Dog extends Animal { // No need to implement moreWalking }

这意味着您可以随时对任何动物调用walk() ,无论是人还是狗,但是这个人会有一些狗没有的额外东西。 我保留了Animal摘要,因为你不希望人们创建它的实例。 如果不是这种情况,那么你也可以删除它。

但请注意,我们实际上并不经常在java中以这种方式使用子类。 通常我们使用接口和实现,子类共享公共实现(有时)。 这种类型的继承很难理解和建模,事实证明它并没有那么有用。 我们通常归结为一个名为Liskov的替换原则的规则,这意味着子类化只有在我们计划使用多态时才有用 - 这基本上归结为使用多个子类型的实例来填充超类型的集合。希望迭代并调用相同的方法(这是对它的粗略描述)。

One way to achieve this is to make walk() final, and have it call an abstract method. So,

abstract class Animal { public final void walk() { // do stuff moreWalking(); } protected abstract void moreWalking(); } class Person extends Animal { protected void moreWalking() { // do stuff } }

Notice that I made moreWalking use a protected level accessor (not public or private), so that it's overridable in derived classes, but can't be called by clients.

Also, this code is a 'sketch', I've left out lots of important things, like the interface for Animal that Davidxx talks about in his answer.

Once consequence of this is that subclasses of Animal 'must' implement moreWalking(). This can be mitigated by having a default implementation in a base class, or by not having the method abstract and providing an 'empty' implementation, like this:

abstract class Animal { public final void walk() { // do stuff moreWalking(); } protected void moreWalking() { } } class Person extends Animal { protected void moreWalking() { // do stuff } } class Dog extends Animal { // No need to implement moreWalking }

This means that you can always call walk() on any animal, be they person or dog, but that person will have some extra stuff that a dog doesn't have. I've kept Animal abstract because you won't want people creating an instance of it. If this isn't the case then you can remove that too.

Be aware though, we don't actually use subclasses this way very often in java. Typically we use interfaces and implementations, with subclasses to share common implementation (sometimes). This type of inheritance is quite difficult to understand and model, and it turns out that it's just not that useful. We usually come down to a rule called Liskov's Substitution Principle, which implies that subclassing is only useful if we're planning to make use of polymorphism -- which basically boils down to having collections of the supertype populated with instances of many subtypes upon which we wish to iterate and call the same method (this is quite a rough description of it).

更多推荐