类似模式匹配的行为

Pattern Matching like behavior

我正在为我的简单问题寻找设计模式。这是一个简化版本。

class Animal{...}
class Dog extends Animal{...}
class Cat extends Animal{...}
... // so on, 3 other classes as of now

我有一个静态方法(实际上是通过网络服务公开的,但它是同义词),它需要一个 id 和 returns 一个动物。

如果返回 cat,则 其他团队 使用 cat 对象生成 CatReport。如果是狗,则狗报告(他们可以将其用于任何事情)。显然猫狗有不同的属性CatDog 除了都是动物之外没有任何其他共同点。所以像下面这样打电话是不够的,因为我需要精确的类型:

public static Animal getAnimal(int id){}

不够,因为 animal 没有包含精确类型所能提供的所有信息。

处理这个问题的最佳方法是什么?


PS:在Scala中,我只会对对象进行模式匹配。这样就优雅的解决了问题

我的一个解决方案是:调用 returns 一个 enum 表示 id 对应的内容。然后分别调用每个:

public static AnimalType getAnimalType(int id){}
public static Cat getCat(int id){}
public static Dog getDog(int id){}
....

但这很麻烦。

如果我对问题的理解正确,你想调用关于你拥有的对象类型的方法的正确实现。因此,如果动物是猫,如果您有如下代码

,则应从 Cat class 调用生成报告方法
public static Animal getAnimal(int id){ 
 //your code to return object of either Cat or Dog
}
animal.generateReport();

首先正如你所说,

Obviously Cat & Dog have different attributes. Cat and Dog dont have anything else in common apart from the fact that they are Animals.

由于 subclasses 没有任何共同的功能,将 Animal 定义为接口而不是像下面给出的 class

interface Animal{
 public void generateReport();
}

然后像这样创建猫狗

class Cat implements Animal{
//define cat specific attributes here
 public void generateReport(){
   //your logic to generate cat report
 }

}

class Dog implements Animal{
 //define dog specific attributes here
 public void generateReport(){
   //your logic to generate dog report
 }

}

由于接口中定义了generateReport()方法,所有实现该接口的classes都必须有generateReport()。

所以当你这样打电话时,

public static Animal getAnimal(int id){ 
 //your code to return object of either Cat or Dog
}
animal.generateReport();

底层对象的方法将被调用。

如果你只是想知道动物对象指的是什么(从 getAnimal 方法返回,即猫或狗),你可以像下面这样检查

class Animal{

}
class Dog extends Animal{
     public String dogName = "Dog1";
}

class Cat extends Animal{
    public String catName = "Cat1";
}


public class HelloWorld{

     public static void main(String []args){

        //call getAnimal and get the object instead of following line
        Animal animal = new Cat();

        if ( animal instanceof Cat ){

            //cast Animal to Cat
            Cat cat = (Cat) animal;
            System.out.println(cat.catName);

        }else if ( animal instanceof Dog ){

            //cast Animal to Dog
            Dog dog = (Dog) animal;
            System.out.println(dog.dogName);
        }

     }

 }

在像 Java 这样的语言中,您可以使用 Visitor 模式模拟模式匹配行为。

您可以分几步完成:

  1. accept 方法定义一个接口 Animal 表示 Animal
  2. Animal 添加一些子 类 并提供与下面我的小示例相同的实现。
  3. 定义一个接口Visitor并给它一个实现。该类将允许您在 类.
  4. 上模拟一些模式匹配

这里有一个小例子:

public interface Animal {
    public void accept(AnimalVisitor v); 
}

public class Dog extends Animal {
    public void accept(AnimalVisitor v) {
        v.visit(this);
    }
}

public class Cat extends Animal {
    public void accdept(AnimalVistior v) {
        v.visit(this);
    }   
}

public interface AnimalVisitor {
    public void visit(Dog d);
    public void visit(Cat c);
}

public class PrintAnimal implements AnimalVisitor {

    public void visit(Dog d) {
        System.out.println("Dog");
    }

    public void visit(Cat c) {
        System.out.println("Cat");
    }

}

Visitor 模式是解决问题的一种优雅方式,它也避免了在一个函数中累积 if (x instance of bar)。使用此模式,您的代码将更具可读性和更易于扩展。

对应的Scala代码来理解我的回答:

abstract class Animal {}

case class Dog() extends Animal
case class Cat() extends Animal 

object Animal {

  def printAnimal(a : Animal) = a match {
    case x : Dog => "Dog"
    case x : Cat => "Cat"
    case _ => "Unknown"
  }
  def main(args : Array[String]) = {
    println(printAnimal(Dog()))
  }
}

好吧,我没有看到任何真正优雅的解决方案,但你可以用这种代码创建一种报表工厂

public Report getCorrespondingReport(Animal animal){
    if(animal instanceof Dog) return new DogReport();
    if(animal instanceof Cat) return new CatReport();
...

...或者您可以制作一个通用报告并使用反射来检查您的 Animal 实例并按照一般规则生成您的报告,但这可能不可行。