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接口。