一次责任链模式的使用
优化前
原来的代码大概长这样:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25public String generate(String templateId, List<String> componentList, List<Path> uploadFileList ......)
{
if (StringUtils.isNotBlank(templateId))
{
// service a process template...
}
if (CollectionUtils.isNotEmpty(componentList))
{
// service b process components...
}
if (CollectionUtils.isNotEmpty(uploadFileList))
{
// service c process upload files...
}
// 省略其他处理逻辑
if (CollectionUtils.isNotEmpty(uploadFileList))
{
return "some result A";
}
return "some result B";
}
总而言之,就是根据传入的参数,分别做某些事情。如果需求改变了,需要新增一些功能,则一方面增加方法入参,一方面在合适的代码位置加入新逻辑。
这样下去,方法变得越来越大,维护起来比较困难。因此决定优化以下。
经过考虑,我决定采用行为模式中的责任链模式来优化。以下是优化后的代码的大概样子。
优化后
首先,定义一个上下文类,该类保存所有service需要处理的参数。1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
public class GeneratorContext
{
private String templateId;
private String targetFileDirectory;
private List<Path> localFilePaths = Lists.newArrayList();
private List<String> componentList = Lists.newArrayList();
private List<Path> uploadFileList = Lists.newArrayList();
private String generateResult;
}
注意,这里有一个问题,就是在一开始的代码中,如果有上传文件,返回结果A,否则返回结果B(一个比喻,实际代码可能不是这样)。在采用责任链模式改写的过程中,一直无法很好地获取个个责任者返回的值。因此,在上下文信息类中保存了generateResult,表示返回值,由各个责任者指定值。
接下来定义抽象的责任类1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27public abstract class AbstractGenerator
{
private AbstractGenerator nextGenerator;
public AbstractGenerator setNextGenerator(AbstractGenerator nextGenerator)
{
this.nextGenerator = nextGenerator;
return this.nextGenerator;
}
public void generateProject(GeneratorContext context)
{
if (needMyHelp(context))
{
generateMyPart(context);
}
if (this.nextGenerator != null)
{
this.nextGenerator.generateProject(context);
}
}
protected abstract void generateMyPart(GeneratorContext context);
protected abstract boolean needMyHelp(GeneratorContext context);
}
然后是该各个具体的责任者,继承自该抽象类:
1 | "baseGenerator") ( |
1 | "componentGenerator") ( |
1 | "uploadGenerator") ( |
在实际的开发中,还可以定义一个统一的异常,用于异常管理,在generateMyPart()方法中抛出,由上层捕获处理。1
2
3
4
5
6
7
8
9
10
11
12public class GeneratorException extends RuntimeException
{
public GeneratorException(final String message)
{
super(message);
}
public GeneratorException(final String message, final Throwable cause)
{
super(message, cause);
}
}
接下来是构造责任链:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
public class GeneratorChainBuilder
{
"baseGenerator") (name =
private AbstractGenerator baseGenerator;
"componentGenerator") (name =
private AbstractGenerator componentGenerator;
"uploadGenerator") (name =
private AbstractGenerator uploadGenerator;
public AbstractGenerator buildChain()
{
baseGenerator.setNextGenerator(componentGenerator).setNextGenerator(uploadGenerator);
return baseGenerator;
}
}
接下来是service类,定义service类,封装责任链:1
2
3
4public interface GeneratorService
{
void generatorProject(GeneratorContext context);
}
1 |
|
最后是使用者:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23public class GeneratorController
{
private GeneratorService generatorService;
public String generate(@RequestParam ...)
{
// 可以有一些预处理
// 构造上下文
GeneratorContext context = new GeneratorContext();
// 根据入参,调用context的setter方法,设置上下文
context.setTemplateId("1");
context.setLocalFilePaths(targetFilePaths);
context.setComponentList(componentList);
// ..省略其他setter
generatorService.generatorProject(context);
return context.getGenerateResult();
}
}
此后,如果要加入新的功能,只需新建责任者,继承自AbstractGenerator类,实现相关方法,并在责任链构造器中在合适的顺序位置加入该新的责任者即可。
如果后面的责任者不需要进行处理,也就无法设置上下文信息中的result值,返回的result值只有需要处理的责任者才可设置,这样就解决了前面提到的返回值的问题。
这里其实还可以优化,就是每个责任者持有一个int类型的字段,表示其处理先后顺序,然后autowired注入到一个map或者list中,根据该字段进行排序,然后依次处理,其实这样也有点像之前写到的“工厂模式”了。
Read More
[1]Chain of Responsibility Design Pattern in Java
[2]责任链模式
[3]模板方法模式
[4]Spring注解——同一接口有多个实现类,如何注入?@Resource、@Autowired、@Qualifier