模式匹配行为

时间:2015-08-04 08:46:27

标签: java design-patterns

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

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

我有一个静态方法(实际上是通过网络服务公开但是它的同义词),它采用id并返回一只动物。

如果返回cat,那么使用cat对象的其他团队会生成CatReport。如果狗,然后狗报告(他们可以用它做任何事情)。显然Cat& Dog 具有不同的属性。除了动物之外,CatDog没有任何共同之处。所以拨打下面的电话是不够的,因为我需要精确的类型:

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){}
....

但这很麻烦。

3 个答案:

答案 0 :(得分:2)

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

您可以通过以下几个步骤执行此操作:

  1. 定义代表具有Animal方法
  2. 的动物的界面accept
  3. 将一些子类添加到Animal并提供相同的实现,如下面的小例子所示。
  4. 定义接口Visitor并为其提供实现。这个classe将允许您在类上模拟一些模式匹配。
  5. 这里有一个小例子:

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

答案 1 :(得分:0)

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

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

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

答案 2 :(得分:-1)

如果我正确理解了这个问题,你想要调用关于你所拥有的对象类型的方法的正确实现。因此,如果动物是猫,如果您有类似下面的代码,则应从Cat类调用生成报告方法

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

首先,正如你所说,

  

显然Cat&狗有不同的属性。猫与狗没有   除了他们是动物之外的任何其他共同点。

由于子类没有任何通用功能,因此将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方法返回,即Cat或Dog),你可以像下面那样检查

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

     }

 }