解释器模式:当系统面临的某些大量且具有一定规律性的问题重复出现,如果我们将这些问题的相似点定义一套规则(语言),再写一个解释器解释这些问题实例,这就是解释器模式
如下场景案例:某公司多个部门绩效考核,但规则都不同。现在要求开发一个绩效运算系统,要求输入计算规则和员工实例立刻返回最终绩效。
可以想象的方案是,因为每个部门绩效考核标准不同,那么入参也不相同。
具体的实施方案也就是每个部门单独一个计算绩效的方法,固定形参列表。
再优化一点就是每个部门自己管理一个类,自己管理自己的绩效计算方法。这样即使有变动那么变更自己的类实现即可。
/**
* A部门
* */
public class PartA {
//这份方法可以获得员工绩效,可以看到当部门绩效方法变更时,需要改变其实现方法
public int getPerformance(int a,int b,int c){
int result = a+b-c;
return result;
}
}
但解释器设计模式可以让各个部门计算绩效时只需要准备好自己计算公式的字符串就可以返回随时计算绩效的实例对象。
再将员工实例数据录入绩效计算就可以返回绩效,计算公式更改时直接更改输入的字符串即可
/**
* 绩效系统
* */
public class PerformanceSystem {
char[] rule;
public PerformanceSystem(String rule){
this.rule = rule.toCharArray();
}
//计算最终结果
public int getResult(LinkedList<String> lists){
//检查是否符合规范
if(!checkRule(lists)){
return -1;
}
int value = 0;
for(int i = 0;i<lists.size();i++){
if(lists.get(i).equals("+")){
value += Integer.valueOf(lists.get(++i));
}else if(lists.get(i).equals("-")){
value -= Integer.valueOf(lists.get(++i));
}else {
value = Integer.valueOf(lists.get(i));
}
}
return value>0?value:-1;
}
//检查输入参数是否符合规范,要求符号位必须相同,其余位必须时数字0-9
public boolean checkRule(LinkedList<String> lists) {
for(int i = 0;i<lists.size();i++){
if(lists.get(i).matches("[+-]")){
//此时参数是符号位
if(rule[i]!=lists.get(i).toCharArray()[0]){
//符号位不等
return false;
}
}else {
//此时参数是元素位
char[] ch=lists.get(i).toCharArray();
for(char chi:ch){
if(chi<48||chi>57){
//元素中存在字符不是数字
return false;
}
}
}
}
//全通过了没有问题,说明输入参数符合公式
return true;
}
}
/**
* 绩效解释器,负责解析传进来的字符串拆分并传入绩效系统进行计算
* */
public class PerformanceInterpreter {
PerformanceSystem performanceSystem;
public PerformanceInterpreter(String rule){
performanceSystem = new PerformanceSystem(rule);
}
//根据实际参数计算最终绩效,入参为实际输入的参数
public int excute(String instance) {
//将字符串拆解成一个个元素
LinkedList<String> lists = getLinkedList(instance);
//根据拆解结果计算最终绩效
int result = performanceSystem.getResult(lists);
return result>0?result:-1;
}
//拆解传入的字符串表达式
private LinkedList<String> getLinkedList(String instance) {
String result = "";
LinkedList<String> lists = new LinkedList<>();
for(char ch:instance.toCharArray()){
if(ch != '+'&&ch!= '-'){
result = result+ch;
}else{
lists.add(result);
result = "";
lists.add(String.valueOf(ch));
}
}
lists.add(result);
return lists;
}
}
/**
* A部门
* */
public class PartA {
//这份方法可以获得员工绩效,可以看到当部门绩效方法变更时,需要改变其实现方法
private String rule ;
private PerformanceInterpreter interpreter;
//便于后期更改规则
public void setRule(String rule){
this.rule = rule;
this.interpreter = new PerformanceInterpreter(this.rule);
}
public PartA(String rule){
this.rule = rule;
this.interpreter = new PerformanceInterpreter(this.rule);
}
//按要求输入参数,返回绩效结果
public int excute(String instance){
return interpreter.excute(instance);
}
}
可以看到的是,代码的确复杂了。但是当规则发生变化时,只需要调用setRule(String rule)方法将新规则传进去即可
而当部门扩展时,只需要将绩效解释器组合到新的部门类中,把规则字符串传进去就可以了,不需要自定义新的代码。
另外,字符串的注入可以通过配置文件的形式。可以做到不修改代码实现绩效计算