我一直在寻找设计思路来解决
Java中的这个问题.
我正在使用一个库(我无法改变它),对于这个例子,我只是称之为“动物”.它包含一个Animal接口和一堆实现;我需要根据动物的实现调用不同的方法:
List<Animal> animals = Service.getAnimals(); for(Animal a : animals) { process(a); } private void process(Animal animal) { if (animal instanceOf Cat) { processCat(animal); } else if (animal instanceOf Dog) { processDog(animal); } else { System.out.println("unsopported animal"); } }
我目前正在通过反射解决这个问题,一个类包含所有“处理器”并使用它来调用它们
String methodName = "process" + Animal getClass().getSimpleName(); //ugh
我正在使用Java 8,我很确定必须有更好的设计来解决这个问题.
任何帮助表示赞赏!
解决方法
如果Animal是一个密封类,也就是说,它不是动态可扩展的,并且具有有限的已知数量的子类,那么在示例中偶然发现的if-instanceof模式是经典的“模式匹配”.
如果Animal是一个你可以控制的类,那么你可以使用Visitor Pattern直接在Animal上创建一个访问方法.
但是,您声明Animal来自外部库,这限制了您可以采取的方法.
您仍然可以使用访问者模式,使所有代码都负责在单个类中与Animals交互,使用方法重载在运行时解析类型(假设您没有任何泛型问题).
但实际上这就像if-instanceof方法一样不灵活,只会让OO人感觉更好.
老实说,if-instanceof就是我想要的,除非方法/行为的数量开始变得过于复杂.
在这种情况下,我会创建一种注册表,为每种动物类型注册一个处理器.
然后,您可以创建一个简单的类,从注册表中获取Animal类型所需的处理器.
我见过的这种注册表模式在Minecraft中使用了很多,但我不确定它是否在其他地方记录过.
基本上它的使用看起来像这样.
void onApplicationStart(){ Registry registry = new Registry(); registry.register(Cat.class,cat -> catProcessor.process(cat)); registry.register(Dog.class,dog -> dogProcessor.process(dog)); registry.registerFallback(Animal.class,ani -> animalProcessor.process(ani)); }
void whenNeeded(Animal animal){ Registry registry = fetchRegistrySomehow(); registry.for(animal.getClass()).apply(animal); }
编辑:故意丢失注册表的实现,因为确切的行为会有所不同,具体取决于您希望如何进行查找,处理类层次结构,何时以及是否应在某些应用程序启动事件后密封注册表.