java重构严格的代码以消除检查instanceOf的ifelse语句
大家好,
我有一个关于重构一段代码的问题。这些课程的结构如下:
abstract class A
class A1 extends class A
class A2 extends class A
class A3 extends class A
abstract class AdditionalStuff {
abstract void function();
}
class AdditionalStuffForA1 extends AdditionalStuff
class AdditionalStuffForA2 extends AdditionalStuff
class AdditionalStuffForA3 extends AdditionalStuff
class Implementation {
List<A> aList;
.... //add A1, A2, A3 to aList
AdditionalStuff aS;
for (A instance: aList) {
if(instance instanceOf A1)
aS = new AdditionalStuffForA1();
else if(instance instanceOf A2)
aS = new AdditionalStuffForA2();
else
aS = new AdditionalStuffForA3();
aS.function()
}
}
我认为上面的代码是严格的,因为每次添加新类An(例如A4和AdditionalStuffForA4)时,也必须修改if-else语句
我曾想过使用Decorator模式,但现在我认为Decorator模式不能解决我的问题。我想问一下,你能不能建议我一种重构上述代码的方法,以消除if-else语句的使用?(请注意,我无法将AdditionalStuff的函数添加到内部,因为它们的使用方式不同)
# 1 楼答案
经典的“文本书方法”是访问者模式
首先,您需要定义一个访问者界面:
然后需要通过抽象方法扩展
A
类以接收访问者:您的类
A1
、A2
和A3
需要recieve方法的实现:最后,您必须在实现类中定义不同的
visit
方法:这种方法的优点是,您的A、A1、A2和A3类不需要任何关于这些
AdditionalStuff
类的知识。缺点是当您需要第四个类A4时,必须向接口添加visitA4
方法。。。在实现这个AVisitor
接口的每个类中。(编辑:但与if (... instanceof ...) else if (... instanceof ...)
方法不同的是:visitor方法将保证您不会错过特殊的实例检查。如果您忘记添加用于处理A4类的实现,编译器将告诉您。 编辑:修复实现类的代码# 2 楼答案
使用接口
在Java8或更高版本中,接口可以有默认的方法实现
您可以定义:
并使用适当的接口创建类:
执行此命令时:
将打印:
可以使用参数(对象…参数)控制其他行为
# 3 楼答案
您可以尝试以下方法
首先,如果没有必要,请避免使用继承。例如,您的
AdditionalStuff
只定义了一个契约方法function
,该方法需要由您拥有的各种类来实现。可以将其更改为interface
类而不是abstract
类有了它,只需更改列表以容纳各种接口实现,例如:
然后,只需在一行中遍历所有内容,然后执行以下操作:
通过这种方式,您将避免复杂的继承(这里不需要),以及内省和其他一切
# 4 楼答案
对此有多种方法。但是扩展现有实现的最简单答案如下所示
# 5 楼答案
我可以想出两个好办法。两者都是“工厂”设计模式的变体
方法1是使
A
类负责创建AdditionalStuff
子类型的实例方法2是将测试实例抽象为工厂方法:
或者更好:
您可以用
switch
替换if instanceof
测试,并打开instance
的类名。但对于少数子类来说,这样做几乎没有什么好处。(海事组织)# 6 楼答案
在不理解代码的实际用途的情况下提出合理的建议有点困难,但我会研究工厂模式,即为每个
AdditionalStuff
子类提供一个工厂,在一些映射中注册它,并通过实例的类进行查找:然后在某个地方有一个
Map<Class<? extends A>, AdditionalStuffFactory>
,其中会充满工厂实例,例如registry.put(A1.class, new AdditionalStuffA1Factory() );
然后,您的循环将如下所示:
当然还有进一步的优化,例如让“registry”委托调用,从而得到类似
registry.createFor(instance)
的结果,但你应该明白这一点添加另一个
AdditionalStuff
将需要以下内容: