通过设计模式重构遗留开关盒实例
Refactoring legacy instanceof switch casing via design patterns
我公司的遗留代码受到普遍使用 instanceof switch-casing 的困扰,形式如下:
if(object instanceof TypeA) {
TypeA typeA = (TypeA) object;
...
...
}
else if(object instanceof TypeB) {
TypeB typeB = (TypeB) object;
...
...
}
...
...
更糟糕的是,问题中的几个 TypeX classes 实际上是在第 3 方库中找到的 classes 的包装器。
在第 3 方 classes 上使用访问者设计模式和专用访问者设计模式包装器的建议方法 and here (Visitor DP with 3rd party classes) 似乎是一个很好的方法。
但是,在代码审查期间 session 建议采用这种方法,每次重构 instaceof 所需的样板代码的额外开销问题 switch-casing 导致这种机制被拒绝.
我想解决这个持续存在的问题,我正在考虑采用通用方法解决该问题:
一个实用程序 class,它将使用对访问的 object 的通用引用来包装访问者设计模式。这个想法是一次且仅一次实现访问者实用程序 class 的通用核心,并在需要时为 TypeX object 行为提供特定实现 - 希望甚至通过实现功能的 OO 扩展重用一些实现classes.
我的问题是 - 这里有人做过类似的事情吗?如果没有 - 你能指出任何可能相关的 pros/cons 吗?
编辑:
太多样板代码 = 专门为 instanceof switch-case 的每个实例实施访问者设计模式。这显然是多余的,如果访问者 DP 没有使用泛型实现,将导致大量代码重复。
至于我想到的通用访问者 DP 实用程序:
首先,如所见here.
二、泛型的如下用法(基于反射访问者):
public interface ReflectiveVisitor<GenericReturn,GenericMetaData>
{
public GenericReturn visit(Object o, GenericMetaData meta);
}
public interface ReflectiveVisitable<A,B>
{
public GenericReturn accept(Visitor visitor, GenericMetaData meta);
}
GenericReturn 和 GenericMetaData 是接口,旨在为要实现的特定逻辑提供任何额外需要的元数据,并为访问者 DP returned return 类型提供多功能性。
提前致谢!
编辑:从 instanceof 重构到访问者时的锅炉板编码:
我必须处理的一个常见用例是 instanceof switchcasing,以便执行具体实现的单个 API 调用:
public class BoilerPlateExample
...
if(object instanceof TypeA) {
((TypeA) object).specificMethodTypeA(...)......;
}
else if(object instanceof TypeB) {
((TypeB) object).completeyDifferentTypeBMethod(...)......;
}
...
...
至于访客设计处理这个吗?
public interface Visitor
{
// notice how I just binded my interface to a specific set of methods?
// this interface will have to be generic in order to avoid an influx of
// of dedicated interfaces
public void visit(TypeA typeA);
public void visit(TypeB typeB);
}
public interface Visitable
{
public void accept(Visitor visitor);
}
public class BoilerPlateExampleVisitable<T> implements Visitable
{
// This is basically a wrapper on the Types
private T typeX;
public BoilerPlateExampleVisitable (T typeX) {
this.typeX = typeX;
}
public void accept(Visitor visitor) {
visitor.visit(typeX);
}
}
public class BoilerPlateExampleVisitor implements Visitor
{
public void visit(TypeA typeA) {
typeA.specificMethodTypeA(...)......;
}
public void visit(TypeB typeB) {
typeB.completeyDifferentTypeBMethod(...)......;
}
}
public static final BoilerPlateExampleVisitor BOILER_PLATE_EXAMPLE_VISITOR = new BoilerPlateExampleVisitor();
public static void main(....) {
TypeA object = .....; // created by factory
BoilerPlateExampleVisitable boilerPlateVisitable = VisitableFactory.create(object); // created by dedicated factory, warning due to implicit generics
boilerPlateVisitable.accept(BOILER_PLATE_EXAMPLE_VISITOR);
}
好像是polymorphism。此类代码可能源自一组异构业务对象 classes,例如 Excel ReportX、Zip、TableY 以及打开、关闭、保存等操作。
事实上,这种编程导致 classes 之间的巨大耦合,并且在所有情况的完整性和可扩展性方面存在问题。
在多态性的情况下,某些业务对象的实际包装器应该提供操作(打开、保存、关闭)。
此机制类似于 java swing,其中编辑字段具有其操作列表(剪切、复制、粘贴等),树视图具有一组重叠的操作。根据焦点,实际操作将安装在菜单操作中。
一个声明性规范可能是有序的:说一个XML那个"holds"豆和它们的动作.
如果您有一些 MVC 范例,请考虑以下内容:
每个动作都可以有参数。使用 PMVC(我的想法),除了模型 class 之外的参数 class,因为这些信息具有不同的生命周期,并且是恒定的。
通往这里的道路可能是:
- 具有两个业务对象和两个操作的原型。
- 使用一个包含所有(旧代码)的多态业务对象进行重构。
- 慢慢地一个个class自己的业务对象。
- 第一次从用于清理新架构的多态业务对象中删除。
我会避免使用继承(具有 open/save 的 BaseDocument),因为这可能不适合更异构的现实,并且可能导致并行 class 层次结构(XDoc 与 XContainer 和 XObject)。
实际如何完成仍然是您的工作。 我也很想知道是否存在既定的范例。
询问pseudo-code
人们需要对一些原型进行一些分析——概念证明。但是发现了(动态)capabilities/features.
public interface Capabilities {
<T> Optional<T> as(Class<T> type);
}
将此接口添加到每个案例class,您可以:
void f(Capabilities animal) {
int distance = 45;
animal.as(Flying.class).ifPresent(bird -> bird.fly(distance));
}
基础设施将是:首先,功能和发现的注册可以放在单独的 class。
/**
* Capabilities registration & discovery map, one can delegate to.
*/
public class CapabilityLookup implements Capabilities {
private final Map<Class<?>, Object> capabilitiesMap = new HashMap<>();
public final <T> void register(Class<T> type, T instance) {
capabilitiesMap.put(type, instance);
}
@Override
public <T> Optional<T> as(Class<T> type) {
Object instance = capabilitiesMap.get(type);
return instance == null ? Optional.empty()
: Optional.of(type.cast(instance));
}
}
然后遗留 classes 可以扩充:
/** Extended legacy class. */
public class Ape implements Capabilities {
private final CapabilityLookup lookup = new CapabilityLookup();
public Ape() {
lookup.register(String.class, "oook");
}
@Override
public <T> Optional<T> as(Class<T> type) {
return lookup.as(type); // Delegate to the lookup map.
}
}
/** Extended legacy class. */
public class Bird implements Capabilities {
private final CapabilityLookup lookup = new CapabilityLookup();
public Bird() {
lookup.register(Flying.class, new Flying() {
...
});
lookup.register(Singing.class, new Singing() {
...
});
}
@Override
public <T> Optional<T> as(Class<T> type) {
return lookup.as(type); // Delegate to the lookup map.
}
}
正如您在 Bird
中看到的那样,原始代码将移动到接口的实际 class 中,这里是 Bird,因为实例是在构造函数中创建的。但是可以用 BirdAsFlying
class 代替匿名 class,这是 java 摇摆语中的一种动作 class。
内部 class 具有访问 Bird.this
.
的优势
重构可以逐步完成。将功能添加到所有 "instanceof" 遗留 classes。 if-sequence 通常是一个接口,但也可以是两个,或者一个接口有两个方法。
TL;DR: 假设你有 N classes,每个有 M 个操作。只有当 M 可能增长并且 N 已经很大时,您才需要访问者模式。否则使用多态性。
也许我会推开一扇门,因为你已经想到了,但这里有一些想法。
访客模式
在一般情况下,只有当您想添加新操作而不重构所有 class 时,您才会使用访问者模式 。那是 M 可能增长而 N 已经很大的时候。
对于每个新操作,您都会创建一个新访问者。这位访问者接受了 N classes 并为每个人处理了操作:
public class NewOperationVisitor implements Visitor
{
public void visit(TypeA typeA) {
// apply my new operation to typeA
}
public void visit(TypeB typeB) {
// apply my new operation to typeB
}
...
}
因此,您不必将新操作添加到所有 N classes,但如果添加 class,则必须重构每个访问者。
多态性
现在,如果 M 是稳定的,请避免访问者模式:使用多态性。每个 class 都有一组定义明确的方法(每个操作大约一个)。如果您添加一个 class,只需定义该 class:
的已知操作
public class TypeX implements Operator
{
public void operation1() {
// pretty simple
}
public void operation2() {
// pretty simple
}
}
现在,如果添加一个操作class,您必须重构每个 class,但是添加一个 class 非常容易。
R. C. Martin 在 Clean Code 中解释了这种权衡(6. Objects 和数据结构,Data/Object Anti-Symmetry):
Procedural code [here: the visitor] makes it hard to add new data structures because all the functions must change. OO code makes it hard to add new functions because all the classes must change.
你应该做什么
如@radiodef 评论所述,避免反射和其他技巧。这会比问题更糟。
明确区分真正需要访问者模式的地方和不需要的地方。计数 classes 和操作。我敢打赌,在大多数情况下,您不需要访问者模式。 (您的经理可能是对的!)。如果您在 10% 的情况下需要访问者模式,也许 "additonal overhead of boilerplate code" 是可以接受的。
由于您的几个 TypeX
classes 已经是包装器,您可能需要包装得更好。有时,从下到上循环: "My 3rd party class has those methods: I will wrap the methods I need and forget the others. And I will keep the same names to keep it simple." 相反,您必须仔细定义 TypeX
class 应该提供的服务。 (提示:看看你的 if ... instanceof ...
身体)。然后再次包装第 3 方库以提供这些服务。
真的:避免反射等技巧。
我会怎么做?
您在评论中要求 pseudo-code,但我不能给您,因为我考虑的是方法,而不是程序或算法。
下面是我在这种情况下会做的最小步骤。
在方法
中隔离每个"big instanceof
switch"
这几乎是医学建议!之前:
public void someMethod() {
...
...
if(object instanceof TypeA) {
TypeA typeA = (TypeA) object;
...
...
}
else if(object instanceof TypeB) {
TypeB typeB = (TypeB) object;
...
...
}
...
...
}
之后:
public void someMethod() {
...
...
this.whatYouDoInTheSwitch(object, some args);
...
...
}
并且:
private void whatYouDoInTheSwitch(Object object, some args) {
if(object instanceof TypeA) {
TypeA typeA = (TypeA) object;
...
...
}
else if(object instanceof TypeB) {
TypeB typeB = (TypeB) object;
...
...
}
}
任何体面的 IDE 都会免费做。
如果您处于需要访问者模式的情况下
保持代码不变,但将其记录下来:
/** Needs fix: use Visitor Pattern, because... (growing set of operations, ...) */
private void whatYouDoInTheSwitch(Object object, some args) {
...
}
如果要使用多态
目标是切换自:
this.whatYouDoInTheSwitch(object, other args);
收件人:
object.whatYouDoInTheSwitch(this, other args);
您需要进行一些重构:
一个。为大开关中的每个案例创建一个方法。所有这些方法都应该具有相同的签名,除了 object:
的类型
private void whatYouDoInTheSwitch(Object object, some args) {
if(object instanceof TypeA) {
this.doIt((TypeA) object, some args);
}
else if(object instanceof TypeB) {
this.doIt((TypeB) object, some args);
}
}
同样,任何 IDE 都将免费提供。
乙。使用以下方法创建接口:
doIt(Caller caller, args);
其中 Caller
是您正在重构的 class 类型(包含大开关的类型)。
C。通过将每个 doIt(TypeX objX, some args)
转换为 TypeX
的 doIt(Caller, some args)
方法,使每个 TypeX
实现此接口。基本上,这是一个简单的 find-replace:用 caller
替换 this
,用 this
替换 objX
。但是这可能比其他的.
更耗时
D.现在,您有:
private void whatYouDoInTheSwitch(Object object, some args) {
if(object instanceof TypeA) {
((TypeA) object).doIt(this, some args);
}
else if(object instanceof TypeB) {
((TypeB) object).doIt(this, some args);
}
}
这严格等同于:
private void whatYouDoInTheSwitch(Object object, some args) {
if(object instanceof TypeA) {
object.doIt(this, some args);
}
else if(object instanceof TypeB) {
object.doIt(this, some args);
}
}
因为在运行时,JVM会为正确的class找到正确的方法(这就是多态!)。因此,这也等同于(如果 object 具有枚举类型之一):
private void whatYouDoInTheSwitch(Object object, some args) {
object.doIt(this, some args);
}
E.内联该方法,您在 Caller
class:
public void someMethod() {
...
...
object.doIt(this, some args);
...
...
}
实际上,这只是一个草图,可能会出现很多特殊情况。但它保证相对快速和干净。它可能只对所有方法的选定方法完成。
如果可能,请务必在每一步之后测试代码。并确保为方法选择正确的名称。
我公司的遗留代码受到普遍使用 instanceof switch-casing 的困扰,形式如下:
if(object instanceof TypeA) {
TypeA typeA = (TypeA) object;
...
...
}
else if(object instanceof TypeB) {
TypeB typeB = (TypeB) object;
...
...
}
...
...
更糟糕的是,问题中的几个 TypeX classes 实际上是在第 3 方库中找到的 classes 的包装器。
在第 3 方 classes 上使用访问者设计模式和专用访问者设计模式包装器的建议方法
但是,在代码审查期间 session 建议采用这种方法,每次重构 instaceof 所需的样板代码的额外开销问题 switch-casing 导致这种机制被拒绝.
我想解决这个持续存在的问题,我正在考虑采用通用方法解决该问题:
一个实用程序 class,它将使用对访问的 object 的通用引用来包装访问者设计模式。这个想法是一次且仅一次实现访问者实用程序 class 的通用核心,并在需要时为 TypeX object 行为提供特定实现 - 希望甚至通过实现功能的 OO 扩展重用一些实现classes.
我的问题是 - 这里有人做过类似的事情吗?如果没有 - 你能指出任何可能相关的 pros/cons 吗?
编辑: 太多样板代码 = 专门为 instanceof switch-case 的每个实例实施访问者设计模式。这显然是多余的,如果访问者 DP 没有使用泛型实现,将导致大量代码重复。
至于我想到的通用访问者 DP 实用程序:
首先,如所见here.
二、泛型的如下用法(基于反射访问者):
public interface ReflectiveVisitor<GenericReturn,GenericMetaData>
{
public GenericReturn visit(Object o, GenericMetaData meta);
}
public interface ReflectiveVisitable<A,B>
{
public GenericReturn accept(Visitor visitor, GenericMetaData meta);
}
GenericReturn 和 GenericMetaData 是接口,旨在为要实现的特定逻辑提供任何额外需要的元数据,并为访问者 DP returned return 类型提供多功能性。
提前致谢!
编辑:从 instanceof 重构到访问者时的锅炉板编码:
我必须处理的一个常见用例是 instanceof switchcasing,以便执行具体实现的单个 API 调用:
public class BoilerPlateExample
...
if(object instanceof TypeA) {
((TypeA) object).specificMethodTypeA(...)......;
}
else if(object instanceof TypeB) {
((TypeB) object).completeyDifferentTypeBMethod(...)......;
}
...
...
至于访客设计处理这个吗?
public interface Visitor
{
// notice how I just binded my interface to a specific set of methods?
// this interface will have to be generic in order to avoid an influx of
// of dedicated interfaces
public void visit(TypeA typeA);
public void visit(TypeB typeB);
}
public interface Visitable
{
public void accept(Visitor visitor);
}
public class BoilerPlateExampleVisitable<T> implements Visitable
{
// This is basically a wrapper on the Types
private T typeX;
public BoilerPlateExampleVisitable (T typeX) {
this.typeX = typeX;
}
public void accept(Visitor visitor) {
visitor.visit(typeX);
}
}
public class BoilerPlateExampleVisitor implements Visitor
{
public void visit(TypeA typeA) {
typeA.specificMethodTypeA(...)......;
}
public void visit(TypeB typeB) {
typeB.completeyDifferentTypeBMethod(...)......;
}
}
public static final BoilerPlateExampleVisitor BOILER_PLATE_EXAMPLE_VISITOR = new BoilerPlateExampleVisitor();
public static void main(....) {
TypeA object = .....; // created by factory
BoilerPlateExampleVisitable boilerPlateVisitable = VisitableFactory.create(object); // created by dedicated factory, warning due to implicit generics
boilerPlateVisitable.accept(BOILER_PLATE_EXAMPLE_VISITOR);
}
好像是polymorphism。此类代码可能源自一组异构业务对象 classes,例如 Excel ReportX、Zip、TableY 以及打开、关闭、保存等操作。
事实上,这种编程导致 classes 之间的巨大耦合,并且在所有情况的完整性和可扩展性方面存在问题。
在多态性的情况下,某些业务对象的实际包装器应该提供操作(打开、保存、关闭)。
此机制类似于 java swing,其中编辑字段具有其操作列表(剪切、复制、粘贴等),树视图具有一组重叠的操作。根据焦点,实际操作将安装在菜单操作中。
一个声明性规范可能是有序的:说一个XML那个"holds"豆和它们的动作.
如果您有一些 MVC 范例,请考虑以下内容: 每个动作都可以有参数。使用 PMVC(我的想法),除了模型 class 之外的参数 class,因为这些信息具有不同的生命周期,并且是恒定的。
通往这里的道路可能是:
- 具有两个业务对象和两个操作的原型。
- 使用一个包含所有(旧代码)的多态业务对象进行重构。
- 慢慢地一个个class自己的业务对象。
- 第一次从用于清理新架构的多态业务对象中删除。
我会避免使用继承(具有 open/save 的 BaseDocument),因为这可能不适合更异构的现实,并且可能导致并行 class 层次结构(XDoc 与 XContainer 和 XObject)。
实际如何完成仍然是您的工作。 我也很想知道是否存在既定的范例。
询问pseudo-code 人们需要对一些原型进行一些分析——概念证明。但是发现了(动态)capabilities/features.
public interface Capabilities {
<T> Optional<T> as(Class<T> type);
}
将此接口添加到每个案例class,您可以:
void f(Capabilities animal) {
int distance = 45;
animal.as(Flying.class).ifPresent(bird -> bird.fly(distance));
}
基础设施将是:首先,功能和发现的注册可以放在单独的 class。
/**
* Capabilities registration & discovery map, one can delegate to.
*/
public class CapabilityLookup implements Capabilities {
private final Map<Class<?>, Object> capabilitiesMap = new HashMap<>();
public final <T> void register(Class<T> type, T instance) {
capabilitiesMap.put(type, instance);
}
@Override
public <T> Optional<T> as(Class<T> type) {
Object instance = capabilitiesMap.get(type);
return instance == null ? Optional.empty()
: Optional.of(type.cast(instance));
}
}
然后遗留 classes 可以扩充:
/** Extended legacy class. */
public class Ape implements Capabilities {
private final CapabilityLookup lookup = new CapabilityLookup();
public Ape() {
lookup.register(String.class, "oook");
}
@Override
public <T> Optional<T> as(Class<T> type) {
return lookup.as(type); // Delegate to the lookup map.
}
}
/** Extended legacy class. */
public class Bird implements Capabilities {
private final CapabilityLookup lookup = new CapabilityLookup();
public Bird() {
lookup.register(Flying.class, new Flying() {
...
});
lookup.register(Singing.class, new Singing() {
...
});
}
@Override
public <T> Optional<T> as(Class<T> type) {
return lookup.as(type); // Delegate to the lookup map.
}
}
正如您在 Bird
中看到的那样,原始代码将移动到接口的实际 class 中,这里是 Bird,因为实例是在构造函数中创建的。但是可以用 BirdAsFlying
class 代替匿名 class,这是 java 摇摆语中的一种动作 class。
内部 class 具有访问 Bird.this
.
重构可以逐步完成。将功能添加到所有 "instanceof" 遗留 classes。 if-sequence 通常是一个接口,但也可以是两个,或者一个接口有两个方法。
TL;DR: 假设你有 N classes,每个有 M 个操作。只有当 M 可能增长并且 N 已经很大时,您才需要访问者模式。否则使用多态性。
也许我会推开一扇门,因为你已经想到了,但这里有一些想法。
访客模式
在一般情况下,只有当您想添加新操作而不重构所有 class 时,您才会使用访问者模式 。那是 M 可能增长而 N 已经很大的时候。
对于每个新操作,您都会创建一个新访问者。这位访问者接受了 N classes 并为每个人处理了操作:
public class NewOperationVisitor implements Visitor
{
public void visit(TypeA typeA) {
// apply my new operation to typeA
}
public void visit(TypeB typeB) {
// apply my new operation to typeB
}
...
}
因此,您不必将新操作添加到所有 N classes,但如果添加 class,则必须重构每个访问者。
多态性
现在,如果 M 是稳定的,请避免访问者模式:使用多态性。每个 class 都有一组定义明确的方法(每个操作大约一个)。如果您添加一个 class,只需定义该 class:
的已知操作public class TypeX implements Operator
{
public void operation1() {
// pretty simple
}
public void operation2() {
// pretty simple
}
}
现在,如果添加一个操作class,您必须重构每个 class,但是添加一个 class 非常容易。
R. C. Martin 在 Clean Code 中解释了这种权衡(6. Objects 和数据结构,Data/Object Anti-Symmetry):
Procedural code [here: the visitor] makes it hard to add new data structures because all the functions must change. OO code makes it hard to add new functions because all the classes must change.
你应该做什么
如@radiodef 评论所述,避免反射和其他技巧。这会比问题更糟。
明确区分真正需要访问者模式的地方和不需要的地方。计数 classes 和操作。我敢打赌,在大多数情况下,您不需要访问者模式。 (您的经理可能是对的!)。如果您在 10% 的情况下需要访问者模式,也许 "additonal overhead of boilerplate code" 是可以接受的。
由于您的几个
TypeX
classes 已经是包装器,您可能需要包装得更好。有时,从下到上循环: "My 3rd party class has those methods: I will wrap the methods I need and forget the others. And I will keep the same names to keep it simple." 相反,您必须仔细定义TypeX
class 应该提供的服务。 (提示:看看你的if ... instanceof ...
身体)。然后再次包装第 3 方库以提供这些服务。真的:避免反射等技巧。
我会怎么做?
您在评论中要求 pseudo-code,但我不能给您,因为我考虑的是方法,而不是程序或算法。
下面是我在这种情况下会做的最小步骤。
在方法
中隔离每个"biginstanceof
switch"
这几乎是医学建议!之前:
public void someMethod() {
...
...
if(object instanceof TypeA) {
TypeA typeA = (TypeA) object;
...
...
}
else if(object instanceof TypeB) {
TypeB typeB = (TypeB) object;
...
...
}
...
...
}
之后:
public void someMethod() {
...
...
this.whatYouDoInTheSwitch(object, some args);
...
...
}
并且:
private void whatYouDoInTheSwitch(Object object, some args) {
if(object instanceof TypeA) {
TypeA typeA = (TypeA) object;
...
...
}
else if(object instanceof TypeB) {
TypeB typeB = (TypeB) object;
...
...
}
}
任何体面的 IDE 都会免费做。
如果您处于需要访问者模式的情况下
保持代码不变,但将其记录下来:
/** Needs fix: use Visitor Pattern, because... (growing set of operations, ...) */
private void whatYouDoInTheSwitch(Object object, some args) {
...
}
如果要使用多态
目标是切换自:
this.whatYouDoInTheSwitch(object, other args);
收件人:
object.whatYouDoInTheSwitch(this, other args);
您需要进行一些重构:
一个。为大开关中的每个案例创建一个方法。所有这些方法都应该具有相同的签名,除了 object:
的类型private void whatYouDoInTheSwitch(Object object, some args) {
if(object instanceof TypeA) {
this.doIt((TypeA) object, some args);
}
else if(object instanceof TypeB) {
this.doIt((TypeB) object, some args);
}
}
同样,任何 IDE 都将免费提供。
乙。使用以下方法创建接口:
doIt(Caller caller, args);
其中 Caller
是您正在重构的 class 类型(包含大开关的类型)。
C。通过将每个 doIt(TypeX objX, some args)
转换为 TypeX
的 doIt(Caller, some args)
方法,使每个 TypeX
实现此接口。基本上,这是一个简单的 find-replace:用 caller
替换 this
,用 this
替换 objX
。但是这可能比其他的.
D.现在,您有:
private void whatYouDoInTheSwitch(Object object, some args) {
if(object instanceof TypeA) {
((TypeA) object).doIt(this, some args);
}
else if(object instanceof TypeB) {
((TypeB) object).doIt(this, some args);
}
}
这严格等同于:
private void whatYouDoInTheSwitch(Object object, some args) {
if(object instanceof TypeA) {
object.doIt(this, some args);
}
else if(object instanceof TypeB) {
object.doIt(this, some args);
}
}
因为在运行时,JVM会为正确的class找到正确的方法(这就是多态!)。因此,这也等同于(如果 object 具有枚举类型之一):
private void whatYouDoInTheSwitch(Object object, some args) {
object.doIt(this, some args);
}
E.内联该方法,您在 Caller
class:
public void someMethod() {
...
...
object.doIt(this, some args);
...
...
}
实际上,这只是一个草图,可能会出现很多特殊情况。但它保证相对快速和干净。它可能只对所有方法的选定方法完成。
如果可能,请务必在每一步之后测试代码。并确保为方法选择正确的名称。