3

我正在解决一个问题,即不同的动物类型从 Animal 接口实现相同的 talk() 方法。
如果您查看getAnimal()方法,您会发现,当将一种新的动物添加到程序中时,该方法的内部也必须更改。
我想通过继承 Animal 来添加新动物,而不改变现有类中的任何内容。
例如,添加一个动物“狗”,criteria="loyal";谈话=“汪汪”。
你能告诉我,这怎么可能?下面是我的代码:

interface Animal {

    public void talk();
}

class Lion implements Animal {

    @Override
    public void talk() {
        System.out.println("ROARRRRR");
    }
}

class Mouse implements Animal {

    @Override
    public void talk() {
        System.out.println("SQUEEEEEAK");
    }
}

class Bison implements Animal {

    @Override
    public void talk() {
        System.out.println("BELLOWWWWW");
    }
}

class AnimalType {

    public static Animal getAnimal(String criteria) {

        // I refactor this method
        if (criteria.equals("small")) {
            return new Mouse();
        } else if (criteria.equals("big")) {
            return new Bison();
        } else if (criteria.equals("lazy")) {
            return new Lion();
        }
        return null;
    }
}

public class AnimalExamples {

    public static void main(String[] args) {
        AnimalType.getAnimal("small").talk();
        AnimalType.getAnimal("big").talk();
        AnimalType.getAnimal("lazy").talk();

        //  how to add an animal "Dog" here, criteria="loyal"; talk="woof"
        AnimalType.getAnimal("loyal").talk();

        try {
            AnimalType.getAnimal("small").talk();
        } catch (Exception ex) {
            System.out.println("Animal does not exists");
        }
    }
}

我在谷歌上搜索,了解它可以通过反射来完成。但不知道如何。如果可能的话,你能帮我解决这个问题吗?提前致谢!

4

4 回答 4

4

只是为了让您知道运行时类的生成非常复杂,不建议该语言的初学者使用。这将是使用匿名类映射的绝佳场景。

class AnimalType {
    private static final Map<String, Animal> animals  = new HashMap<String, Animal>();

    static {
        // Populating map with default animals
        addAnimal("big","BELLOWWWWW"); // bison
        addAnimal("small","SQUEEEEEAK"); // mouse
        addAnimal("lazy","ROARRRRR"); // lion
        addAnimal("loyal","WOOF "); // dog
    }

    public static void addAnimal(String criteria, final String sound) {
        // Assigning a anonymous implementation of animal to the given criteria
        animals.put(criteria, new Animal() {
            @Override
            public void talk() {
                System.out.println(sound);
            }
        });
    }

    public static Animal getAnimal(String criteria) {
        // Returning an animal from the animals map
        return animals.get(criteria);
    }
}

如果您确实坚持真正的运行时类生成,或者如果您对它的工作原理感到好奇,请查看ByteBuddy

于 2016-12-01T06:20:55.123 回答
3

老问题,但这里是如何创建类......对我来说,简单的方法是使用 Javassist。我在这里创建了一个小例子:http: //hrabosch.com/2018/04/08/generate-class-during-runtime-with-javassist/

但这里是重点:

public static Class generateClass(String className, String methodName, String methodBody)
  throws CannotCompileException {
ClassPool pool = ClassPool.getDefault();
CtClass cc = pool.makeClass(className);
StringBuffer method = new StringBuffer();
method.append("public void ")
      .append(methodName)
      .append("() {")
      .append(methodBody)
      .append(";}");
cc.addMethod(CtMethod.make(method.toString(), cc));
return cc.toClass();
}

所以我做了什么......通过Javassist,我在ClassPool 中创建了一个类。我还在这个类中添加了一个方法,并通过反射调用了它。

希望能帮助到你。

只要记住你想在生成的类中使用什么,没有导入,所以你必须使用完全限定的名称。

于 2018-04-09T11:20:56.503 回答
0

Java 不支持在运行时创建类。但是,确实有更好的方法可以在这里实现您想要的。我会提议两个。

首先,您可以创建一个AnimalType包含有关物种的所有共享行为的类。然后,您可以拥有一个Animal将 aAnimalType作为构造函数参数的类。

其次,您可以使用原型设计模式。在这种情况下,Animal该类需要一个clone方法来从原型创建一个新动物。然后,工厂类可以有一个原型列表,并使用您希望选择要克隆的正确原型的任何逻辑。

如果您想了解更多详细信息或这些选项中的任何一个的示例代码,请在下方评论。

于 2016-12-01T06:38:43.813 回答
0

你必须定义狗类

class Dog implements Animal {

    @Override
    public void talk() {
        System.out.println("woof");
    }
}

并将 if else 添加到 AnimalType

} else if ("loyal".equals(criteria)) {
      return new Dog();
}
于 2016-12-01T05:09:03.010 回答