本文紧接
使用重构移除丑陋的if else代码(4)
上篇文章谈到如何能够彻底把这个switch也移除掉呢?很简单,我们只需要在getSystemStatePerformer()方法被调用之前先创建所有
performer匿名类的实例,然后在该方法被调用时直接返回对应的实力。 如何具体实现呢? 用Map, 请看代码:
package de.jingge.refactoring;
import static de.jingge.refactoring.SystemState.*;
import java.awt.Image;
import java.awt.image.BufferedImage;
import java.lang.reflect.Method;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
/**
*
* @author gejing@gmail.com
*/
public class SystemStatePerformerFactory {
private static SystemStatePerformerFactory INSTANCE = new SystemStatePerformerFactory();
private Map<SystemState, SystemStatePerformer> performers;
private SystemStatePerformerFactory() {
}
public static SystemStatePerformerFactory getInstance() {
return INSTANCE;
}
private synchronized Map<SystemState, SystemStatePerformer> getPerformers()
throws Exception {
if (performers == null) {
performers = new HashMap<SystemState, SystemStatePerformer>();
// call all @FactoryMethod using reflection
for (Method m : getClass().getDeclaredMethods()) {
if (m.getAnnotation(FactoryMethod.class) != null) {
SystemStatePerformer p = (SystemStatePerformer) m.invoke(
this, new Object[]{});
performers.put(p.getState(), p);
}
}
// make it readonly
performers = Collections.unmodifiableMap(performers);
}
return performers;
}
public SystemStatePerformer getSystemStatePerformer(SystemState state) throws Exception{
return getPerformers().get(state);
}
@FactoryMethod
private SystemStatePerformer createLoggedInPerformer() {
return new SystemStatePerformer(LOGGEDIN, getImage("loggedin.gif")) {
@Override
public void perform() {
// do something after logging in is successful,
// for example: show welcome dialog, open the last edit document, etc.
}
};
}
@FactoryMethod
private SystemStatePerformer createLoggedOutPerformer() {
return new SystemStatePerformer(LOGGEDOUT, getImage("loggedout.gif")) {
@Override
public void perform() {
// do something after logging out is successful,
// for example: free used resource, dispose GUI components, etc. }
}
};
}
@FactoryMethod
private SystemStatePerformer createIdlePerformer() {
return new SystemStatePerformer(IDLE, getImage("idle.gif")) {
@Override
public void perform() {
// do something after the user is idle,
// for example: save the application state temporarily, lock the application, etc.
}
};
}
private Image getImage(String string) {
return new BufferedImage(10, 10, BufferedImage.TYPE_4BYTE_ABGR);
}
}
从代码中可以看出,当getPerformers()方法被第一次调用时,我们会为每一个performer匿名类创建一个实例,并且将它们纳入Map的管
理之中,以后每次调用的时候,直接从Map里面提取对应某个状态的performer就可以了, switch可以舍弃了。
@FactoryMethod这个注释是我自己写的,使用它主要是为了避免每次新增加一个create***Performer()方法后,都必须修改
getSystemStatePerformer()。
@FactoryMethod的代码如下:
package de.jingge.refactoring;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.METHOD})
public @interface FactoryMethod {
}
到这里整个重构已经结束了, 我们已经将if else, switch完全从代码里剔除了。
读过Refactoring to Patterns这本书的朋友可能会觉得,这里所作的一些和书中第七章最后一节Replace
Conditional Dispatcher with Command完全一样。
Well,第一眼看上去确实很像,但是看完我写的所有代码后,再仔细想一想,两者还是有区别的(Refactoring to Patterns这本书写的非常好,对此书,我可以说是爱不释手,还曾经写过一篇书评。事实上,我这篇文章正式基于这本书的):
1. Factory + annonymous类而不是每一个状态一个具体的实体类。
这样处理问题, 类的数量大大减少,类关联的复杂程度也大大减少,维护起来很方便。
2. performer并不单单是一个command,它拥有状态,并且可以处理更多的逻辑。
全文完。