大家好,
我有一个关于重构一段代码的问题。这些类的结构为:
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 Pattern,但现在我认为Decorator Pattern无法解决我的问题。我想问一下,您能否建议我一种重构上述代码的方法,以消除使用if-else语句? (请注意,我不能将AdditionalStuff的函数添加到A内,因为它们的用法不同)
答案 0 :(得分:3)
对此有多种方法。但是扩展现有实施的最简单答案就是这样
abstract class A {
public abstract AdditionalStuff getAdditionalStuff();
}
class A1 extends class A {
@Override
public AdditionalStuff getAdditionalStuff() {
return new AdditionalStuffA1();
}
}
class A2 extends class A {
@Override
public AdditionalStuff getAdditionalStuff() {
return new AdditionalStuffA2();
}
}
class A3 extends class A {
@Override
public AdditionalStuff getAdditionalStuff() {
return new AdditionalStuffA3();
}
}
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) {
aS = instance.getAdditionalStuff();
aS.function()
}
}
答案 1 :(得分:2)
经典的“课本方法”就是“访客模式”。
首先,您需要定义一个访问者界面:
interface AVisitor<T> {
T visitA1(A1 a1);
T visitA2(A2 a2);
T visitA3(A3 a3);
}
然后,您需要通过一种抽象方法扩展A
类以接收访问者:
abstract class A {
...
public <T> abstract T recieve(AVisitor<T> visitor);
}
您的类A1
,A2
和A3
需要receve方法的实现:
class A1 extends A {
...
public <T> T recieve(AVisitor<T> visitor) {
return visitor.visitA1(this);
}
}
class A2 extends A {
...
public <T> T recieve(AVisitor<T> visitor) {
return vistor.visitA2(this);
}
}
class A3 extends A {
...
public <T> T recieve(AVisitor<T> visitor) {
return visitor.visitA3(this);
}
}
最后,您必须在实现类中定义不同的visit
方法:
class Implementation implements AVisitor<AdditionalStuff> {
void ... () {
List<A> aList;
....
for (A instance : aList) {
AdditionalStuff aS = instance.recieve(this);
aS.function();
}
}
public AdditionalStuff visitA1(A1 a1) {
return new AdditionalStuffForA1();
}
public AdditionalStuff visitA2(A2 a2) {
return new AdditionalStuffForA2();
}
public AdditionalStuff visitA3(A3 a3) {
return new AdditionalStuffForA3();
}
}
此方法的优点是您的A,A1,A2和A3类不需要任何关于这些AdditionalStuff
类的知识。缺点是,当您需要第四类A4时,必须在接口中添加visitA4
方法,并且在实现此AVisitor
接口的每个类中都需要添加方法。 (编辑:但是与您的if (... instanceof ...) else if (... instanceof ...)
方法不同:访问者方法将确保您不会错过特殊实例检查。如果您忘记添加用于处理A4类的实现,则编译器会告诉您。
编辑:修复实现类的代码
答案 2 :(得分:1)
我可以想到两种好的方法。两者都是“工厂”设计模式的变体。
方法1是使A
类负责创建AdditionalStuff
子类型的实例。
abstract class A {
abstract AdditionalStuff makeAdditionalStuff();
...
}
class A1 extends class A {
AdditionalStuff makeAdditionalStuff() {
return new AdditionalStuffForA1();
...
}
class Implementation {
List<A> aList;
.... //add A1, A2, A3 to aList
for (A instance: aList) {
instance.getAdditionalStuff().function()
}
}
方法2是将instanceOf测试抽象为一种工厂方法:
AdditionalStuff getAdditionalStuff(A instance) {
if (instance instanceOf A1) {
return new AdditionalStuffForA1();
} else if(instance instanceOf A2) {
return new AdditionalStuffForA2();
} else {
return new AdditionalStuffForA3();
}
}
或更好:
AdditionalStuff getAdditionalStuff(A instance) {
if (instance instanceOf A1) {
return new AdditionalStuffForA1();
} else if (instance instanceOf A2) {
return new AdditionalStuffForA2();
} else if (instance instanceOf A3) {
return new AdditionalStuffForA3();
} else {
throw new RuntimeException("not implemented");
}
}
您可以将if instanceof
测试替换为switch
,并打开instance
的类名。但是对于少数子类而言,这样做几乎无济于事。 (IMO)
答案 3 :(得分:1)
在不了解您的代码实际上是要做什么的情况下提出明智的建议有点困难,但是我会研究工厂模式,即为每个AdditionalStuff
子类提供一个工厂,在一些地图中注册它,然后通过实例的类查找它:
interface AdditionalStuffFactory {
AdditionalStuff create();
}
class AdditionalStuffA1Factory implements AdditionalStuffFactory {
public AdditionalStuff create() {
return new AdditionalStuffForA1();
}
}
然后您在某个地方有一个Map<Class<? extends A>, AdditionalStuffFactory>
,那里将充满工厂实例,例如registry.put(A1.class, new AdditionalStuffA1Factory() );
您的循环将如下所示:
for (A instance: aList) {
AdditionalStuff aS = registry.get(instance.getClass()).create();
aS.function();
}
当然还有进一步的优化,例如让“注册表”委派电话,从而得到类似registry.createFor(instance)
的信息,但您应该明白这一点。
再添加另一个AdditionalStuff
,则需要满足以下条件:
答案 4 :(得分:1)
您可以尝试以下方法。
首先,如果不需要,请避免使用继承。例如,您的AdditionalStuff
仅使用方法function
定义了一个合同,该合同需要由您拥有的各种类来实现。可以将其更改为interface
类,而不是abstract
类。
有了这个,只需更改列表即可容纳各种接口实现,例如:
List<SomeInterface> list = new ArrayList<>;
Collections.addAll(list, new ClassA(), new ClassB());
然后只需一行就可以遍历所有对象,然后执行以下操作:
list.forEach(SomeInterface::function);
通过这种方式,您将避免复杂的继承(此处未进行继承)以及自省和其他所有内容。
答案 5 :(得分:1)
使用界面!
在Java 8或更高版本中,接口可以具有默认的方法实现。
您可以定义:
public interface AdditionalStuff {
void function(Object... params);
}
public interface AdditionalStuffForA1 extends AdditionalStuff {
default void function(Object... params) {
//do something with params here
System.out.println("implementation for A1");
}
}
public interface AdditionalStuffForA2 extends AdditionalStuff {
default void function(Object... params) {
//do something with params here
System.out.println("implementation for A2");
}
}
并使用适当的接口创建类:
public abstract class A implements AdditionalStuff {
}
public class A1 extends A implements AdditionalStuffForA1 {
}
public class A2 extends A implements AdditionalStuffForA2 {
}
执行此操作:
List<A> aList = new ArrayList<>();
aList.add(new A1());
aList.add(new A2());
aList.add(new A2());
for (A a : aList) {
a.function(23, 45, "string...");
}
将打印:
implementation for A1
implementation for A2
implementation for A2
可以通过参数(对象...参数)控制其他行为
答案 6 :(得分:0)
抽象或接口实现上自己的方法可以自我验证,从而避免了很多(如果只)在此实现的每个实现中使用一个if。将其添加到@Lup的architecture上。