Java 重载方法,使用子类作为参数,但将该方法称为超类

Java 重载方法,使用子类作为参数,但将该方法称为超类,java,overloading,subclass,extending-classes,Java,Overloading,Subclass,Extending Classes,我有一个抽象类Animal,有两个扩展类,Dog和Cat public abstract class Animal { ... } public class Dog extends Animal { ... } public class Cat extends Animal { ... } 在另一个类中,我有一个ArrayList,因为我需要两个单独的方法,每个方法都有一个不同的参数 编辑:我将避免使用访问者模式,因为我认为它不适合我的实际实现。将doSomething()方法移动到每个类中,

我有一个抽象类
Animal
,有两个扩展类,
Dog
Cat

public abstract class Animal {
...
}
public class Dog extends Animal {
...
}
public class Cat extends Animal {
...
}
在另一个类中,我有一个
ArrayList,因为我需要两个单独的方法,每个方法都有一个不同的参数


编辑:我将避免使用访问者模式,因为我认为它不适合我的实际实现。将doSomething()方法移动到每个类中,并进行重构以确保这具有逻辑意义(每个类执行它应该负责的操作)。谢谢

不要在客户端方法中迭代并调用doSomething(),而是将doSomething()保留为抽象类中的方法,这样您就可以在Cat或Dog中更改所需的方式

public void aMethod(){
  ArrayList<Animals> animals = getTheAnimals();
    for (Animal a : animals){
       a.doSomething();
     }
  }

abstract Animal {
   doSomething();
}

Dog extends Animal {


  doSomething() {
    //Dog stuff
  }

}

Cat extends Animal {

   doSomething() {
     //cat stuff
   }

}
public-void-aMethod(){
ArrayList animals=getTheAnimals();
(动物a:动物){
a、 doSomething();
}
}
抽象动物{
doSomething();
}
狗是动物{
doSomething(){
//狗屎
}
}
猫是动物{
doSomething(){
//猫的东西
}
}

将方法移动到
抽象类中,这样每个实现都必须创建自己的方法版本

public abstract class Animal {

  public abstract void doSomething();
}

public class Dog extends Animal {
   public void doSomething(){
       System.out.println("Bark");
   }
}

public class Cat extends Animal {
   public void doSomething(){
       System.out.println("Meow");
   }
}
然后在上面提到的另一个类中,您可以执行以下操作:

  public void vocalize(){
      ArrayList<Animals> animals = getTheAnimals();
      for (Animal a : animals){
         a.doSomething();
      }
   }
public void vocalize(){
ArrayList animals=getTheAnimals();
(动物a:动物){
a、 doSomething();
}
}

您需要双重分派:java提供的运行时类型+必须实现的运行时参数类型。访问者模式就是这样做的一种方式

引入一个
Visitable
界面,在
Animal
中实现,使其接受访问者。
然后介绍一位客人。您可以根据需要使用或不使用接口来实现它。
保持代码实际逻辑的简单版本(通过将访问者耦合到当前类):

public interface Visitable{
   void accept(MyClassWithSomeAnimals myClassWithSomeAnimals);
}

public abstract class Animal implements Visitable{
...
}

public class Dog extends Animal {
...
  void accept(MyClassWithSomeAnimals myClassWithSomeAnimals){
     myClassWithSomeAnimals.doSomething(this);
  }

}
public class Cat extends Animal {
...
  void accept(MyClassWithSomeAnimals myClassWithSomeAnimals){
     myClassWithSomeAnimals.doSomething(this);
  }
}
并使用某些动物更新
myclasses
,方法如下:

public void aMethod(){
    ArrayList<Animals> animals = getTheAnimals();
    for (Animal a : animals){
         a.accept(this);
    }
}
因此,让
MyClassWithSomeAnimals
实现它,并更改可访问类/具体类以使用它:

public interface Visitable{
  void accept(Visitor visitor);
}

public class Dog extends Animal {
...
  void accept(Visitor visitor){
     visitor.doSomething(this);
  }

}
public class Cat extends Animal {
...
  void accept(Visitor visitor){
     visitor.doSomething(this);
  }
}

是的instanceof和getclass会使您的类依赖于特定的类型,使用这样的实践并不太好

但是,通过让方法接受
Dog
Cat
,最终还是取决于具体的实现

更好的方法是在
Animal
接口
performAction()
中定义方法。在
Dog
Cat
中提供实现。现在迭代您的动物列表,只需调用
performAction()
,并根据实际实例以多态方式调用Dog或Cat实现的方法。以后,即使代码中添加了另一个Animal实现,也不需要修改代码

这样,您将在Dog类中拥有Dog相关逻辑,在Cat类中拥有Cat相关逻辑,而不在任何其他类之外。这将有助于遵守OCP和SRP(开放-关闭和单一责任原则)


另外,如果您希望稍后执行行为,并且您的案例是这样的,即您知道您的实现是固定的,并且希望稍后使用代码来注入行为,那么我建议使用
Visitor
模式,但我仍然觉得这不应该被滥用,(设计模式通常不被使用,而是被滥用)有时我们在不需要的时候强制一个模式。访问者模式使用多态性将第一个调用分派到特定实例,第二个分派从该实例调用实现访问者接口的类中的重载方法。(名称可以不同,我提到Visitor是为了暗示实现Visitor概念的类)。只有在需要时才使用访客模式之类的实现,而基于多态性的普通方法不适合这种情况。

只要在抽象类中使用
doSomething
方法,那么
Dog
Cat
就必须实现它。然后,在循环时,只需调用
doSomething
,它将调用特定于实现的对象。如果有人编写
Bird extensed Animal
,并将
Bird Bird=new Bird()
放入列表中。应该调用哪个方法?
doSomething()
可能应该在
anemial
中,并在每个子类中重写。因此,不要使用
doSomething(a)
而是使用
a.doSomething()
。这是不可能的,因为要调用的方法是在编译时选择的。请注意,只有代码的答案通常会被否决;请说明这是如何解决问题中所述问题的。请在回答中添加说明和代码+包括动物定义剂量测定()。在您的代码中,看起来Dog和Cat都有doSomething方法,但它并没有告诉任何关于动物类型引用如何调用它的信息。在你的问题中,让狗和猫实现动物界面。明白了。补充说。感谢这一点以及@Dan的代码示例对您的帮助最大。谢谢我最初不想将doSomething()方法移动到Dog和Cat类中,因为它在类实际执行的操作方面没有太多逻辑意义,但我将进行重构以更好地反映这一点。
public interface Visitor{
  void doSomething(Dog dog);
  void doSomething(Cat cat);
}
public interface Visitable{
  void accept(Visitor visitor);
}

public class Dog extends Animal {
...
  void accept(Visitor visitor){
     visitor.doSomething(this);
  }

}
public class Cat extends Animal {
...
  void accept(Visitor visitor){
     visitor.doSomething(this);
  }
}