以子类为参数的重载方法,但具有称为超类的方法

时间:2018-08-23 16:04:10

标签: java overloading subclass extending-classes

我有一个抽象类Animal,其中有两个扩展类DogCat

public abstract class Animal {
...
}
public class Dog extends Animal {
...
}
public class Cat extends Animal {
...
}

在另一堂课中,我有一个ArrayList<Animal> animals,其中同时包含CatDog的实例。

在具有ArrayList<Animal>的类中,我希望能够重载带有doSomething()Dog d作为参数的方法Cat c,但仍然能够从动物的ArrayList调用它们。如下:

public void aMethod(){
    ArrayList<Animals> animals = getTheAnimals();
    for (Animal a : animals){
        doSomething(a);
    }
}
public void doSomething(Dog a){
//a is an object of type dog
}
public void doSomething(Cat a){
//a is an object of type cat
}

从本质上讲,每种方法都充当“选择器”,该方法正在为其接收动物type

按上述方式尝试时,出现以下编译错误:

  

错误:找不到适合doSomething(Animal)的方法

我知道我可以使用instanceOfa.getClass().equals(type)之类的东西,但是我已经读到这是不好的做法。 这个问题与this other question略有不同,因为我想要两个单独的方法,每个方法具有不同的参数。

编辑:我将避免使用“访客模式”,因为我认为它不完全适合我的实际实现。将doSomething()方法移入每个类,并进行重构以确保这在逻辑上有意义(每个类执行应负责的操作)。谢谢。

4 个答案:

答案 0 :(得分:1)

与其在客户端方法中进行迭代并调用doSomething(),还不如在抽象类中保留doSomething()作为方法,那样您就可以更改在Cat或Dog中的使用方式。

disk = ${var.disks}

答案 1 :(得分:1)

将方法移动到df = pd.read_csv(filename.csv) corpus = df.corpus 类中,因此每个实现都必须制作自己的方法版本。

Abstract

然后在上面提到的另一个类中,您可以执行以下操作:

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");
   }
}

答案 2 :(得分:1)

您需要双重调度: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);
  }
}

并以这种方式更新MyClassWithSomeAnimals

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

此解决方案有效,但有一个缺点。它向MyClassWithSomeAnimals子类公开Animal,而这些子类仅需要一种方法来调用visitor方法,而不是任何公共方法。
因此,一种改进方法是引入一个Visitor接口,以限制doSomething() Animal对访问者的了解:

public interface Visitor{
  void doSomething(Dog dog);
  void doSomething(Cat cat);
}

因此,使MyClassWithSomeAnimals实现它并更改Visitable类/具体类以使用它:

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);
  }
}

答案 3 :(得分:0)

是的,instanceof和getclass会使您的类依赖于特定的类型,并且使用这种做法不太好。

但是,通过让方法接受DogCat,您再次取决于具体的具体实现。

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

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

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