Java 类模式匹配行为

Java 类模式匹配行为,java,design-patterns,Java,Design Patterns,我正在为我的简单问题寻找一种设计模式。这是一个简化的版本 class Animal{...} class Dog extends Animal{...} class Cat extends Animal{...} ... // so on, 3 other classes as of now 我有一个静态方法(实际上是通过web服务公开的,但它是同义词),它接受id并返回一个animal 如果返回了cat,则使用cat对象的另一个团队将生成一个CatReport。如果是狗,那么狗报告(他们可以

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

class Animal{...}
class Dog extends Animal{...}
class Cat extends Animal{...}
... // so on, 3 other classes as of now
我有一个静态方法(实际上是通过web服务公开的,但它是同义词),它接受
id
并返回一个animal

如果返回了
cat
,则使用
cat
对象的另一个团队将生成一个CatReport。如果是狗,那么狗报告(他们可以用它做任何事情)。显然猫和狗有不同的属性<代码>猫和狗除了它们是动物这一事实之外,没有任何共同之处。所以打下面这样的电话是不够的,因为我需要准确的类型:

public static Animal getAnimal(int id){}
这还不够,因为
animal
没有包含精确类型可以提供给我的所有信息

处理这个问题的最好办法是什么


PS:在Scala中,我只需在对象上进行模式匹配。这很好地解决了这个问题

我的一个解决方案是:进行一个调用,返回一个
enum
,表示
id
对应的内容。然后分别为以下各项打电话:

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

但是这很麻烦。

如果我正确理解了这个问题,您希望调用与您拥有的对象类型相关的方法的正确实现。所以,若一个动物是一只猫,若你们有下面这样的代码,那个么应该从cat类调用generate report方法

public static Animal getAnimal(int id){ 
 //your code to return object of either Cat or Dog
}
animal.generateReport();
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);
        }

     }

 }
首先,正如你所说

显然猫和狗有不同的属性。猫和狗没有 除了它们是动物这一事实之外,还有什么共同点吗

由于子类没有任何公共功能,因此将Animal定义为接口,而不是下面给出的类

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()方法是在接口中定义的,因此实现该接口的所有类都必须具有generateReport()

所以当你打这样的电话时

public static Animal getAnimal(int id){ 
 //your code to return object of either Cat or Dog
}
animal.generateReport();
将调用基础对象的方法

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

public static Animal getAnimal(int id){ 
 //your code to return object of either Cat or Dog
}
animal.generateReport();
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
模式模拟模式匹配行为

您可以通过以下步骤完成:

  • 定义一个接口
    Animal
    ,用
    accept
    方法表示动物
  • Animal
    添加一些子类,并给出与下面的小示例相同的实现
  • 定义一个接口
    Visitor
    ,并给它一个实现。这个类将允许您在类上模拟一些模式匹配
  • 这里有一个小例子:

    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实例)
    。使用此模式,您的代码将更具可读性,更易于扩展

    对应的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();
    ...
    

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

    我不太确定您在尝试什么。你想使用动物,但需要知道它的确切类型,因为“动物”是不够的。您可以做的是,如果客户机也定义了所有可能的类,则尝试将其转换为不同类型的动物,以查看它是什么。我建议您稍微了解一下反射,并检查这是否解决了您的用例。如果没有,您可能需要重新考虑您的设计决策。如请求中所述,这些值将从对象中读取,并由其他团队用于生成他们的报告。所以这不是解决办法。他们可以对对象做任何他们想做的事情。无论哪个团队使用它,底层对象仍然是指Dog或Cat,因此正确的实现将被调用。Nope。我不能在animal类中使用
    generateReport
    方法。他们甚至可能不做报告,只是简单地读取值并做一些事情。查看编辑后的答案。仍然可以在接口或抽象类中使用generateReport。当您在猫或狗中重写时,您可以做任何您想做的事情,而不依赖于动物类。考虑“implements Externizable”接口,其中实现它的类不依赖于Externizale接口。