一个简单的计算器可以分为3部分。1是校验部分,校验表达式的合法性,这一部分可以通过这责任链来依次校验;2是表达式的解析部分,将表达式中的数据和符号拆分出来;3是运算部分,这一部分直接使用之前写的命令模式的相关代码。
通过责任链将所有的步骤串起来,切步骤中的节点可以根据自己的想法进行替换,排序,十分灵活。
package behavioralpattern.patterncase.caseone.handler;
/**
* @author tx
* @version 1.0
* @date 2024/1/16 9:26
* @description: 责任链抽象层
*
* 表达式合法校验,可以使用责任链模式 合法返回ture,
* 不合法返回false和失败的原因 在抽象层使用模板,
* 规定好流程,具体的流程细节由子类实现。
*/
public abstract class AbsHandler {
private AbsHandler handler;
public void setNext(AbsHandler handler) {
this.handler = handler;
}
// 具体的处理逻辑,交给子类来实现
protected abstract Resp hand(Resp resp);
// 启动方法
public final void start(Resp resp) {
// --清空缓存--
resp.cleanCache();
// 先执行当前的处理逻辑
resp = hand(resp);
// 判断处理结果,根据结果判断是否执行下一步
// if (!resp.ok()) {
// // 中断处理
// return;
// }
// 继续执行
if(handler!=null){
handler.start(resp);
}
}
}
package behavioralpattern.patterncase.caseone.handler;
import java.util.Stack;
/**
* @author tx
* @version 1.0
* @date 2024/1/16 9:27
* @description: 处理对象
*/
public class Resp {
//是否校验通过
private boolean ok = true;
// 失败的消息
private final StringBuffer msg = new StringBuffer();
// 校验的数据
private String data;
// 中间数据缓存 数字
public Stack<String> nums = new Stack<>();
// 中间数据缓存 符号
public Stack<Character> opts = new Stack<>();
public Resp(String data) {
this.data = data;
}
// 清空缓存
public void cleanCache() {
nums.clear();
opts.clear();
}
public boolean ok() {
return ok;
}
public Resp setOk(boolean ok) {
this.ok = ok;
return this;
}
public String msg() {
return msg.toString();
}
public Resp setMsg(String msg) {
this.msg.append("\n");
this.msg.append("err:");
this.msg.append(msg);
return this;
}
public String data() {
return data;
}
public Resp setData(String data) {
this.data = data;
return this;
}
// 方便结果显示
@Override
public String toString() {
return "Resp{" +
"ok= " + ok +
", msg= \" " + msg + " \"" +
", data= \" " + data +
" \" }";
}
}
package behavioralpattern.patterncase.caseone.handler;
import behavioralpattern.patterncase.caseone.Utils;
/**
* @author tx
* @version 1.0
* @date 2024/1/16 9:31
* @description: 空串校验,并去除字符串中的空格
*/
public class CheckEmpty extends AbsHandler {
@Override
protected Resp hand(Resp resp) {
String s = Utils.get(resp);
// 去除所有空格
String replace = s.replace(" +", "");
// 判断是不是空串
if (replace == "") {
resp.setOk(false).setMsg("字符串为空字符串");
}
return Utils.set(resp, replace);
}
}
package behavioralpattern.patterncase.caseone.handler;
import behavioralpattern.patterncase.caseone.Utils;
/**
* @author tx
* @version 1.0
* @date 2024/1/16 9:36
* @description: 校验字符的合法性,是否只包含 "0123456789 . + - * \/ ( )"
*/
public class CheckChars extends AbsHandler{
@Override
protected Resp hand(Resp resp) {
String s = Utils.get(resp);
String legal = "0123456789.+-*/()";
for (char c : s.toCharArray()) {
if (!legal.contains(String.valueOf(c))) {
resp.setMsg("字符不合法"+c).setOk(false);
}
}
return resp;
}
}
package behavioralpattern.patterncase.caseone.handler;
import behavioralpattern.patterncase.caseone.Utils;
/**
* @author tx
* @version 1.0
* @date 2024/1/16 9:35
* @description: 符号合法性校验
*/
public class CheckOpt extends AbsHandler {
@Override
protected Resp hand(Resp resp) {
// 符号前后得有数字或是()
String s = Utils.get(resp);
for (int i = 0; i < s.length(); i++) {
char one = s.charAt(i);
if (Utils.checkOpt(one)) {
if (i > 0 && i < s.length() - 1) {
char before = s.charAt(i - 1);
char after = s.charAt(i + 1);
if(!Utils.checkNum(before) && before!=')'){
if(before!='('){
resp.setMsg("操作符之前不能 不是数字或者')':"+(i+1)).setOk(false);
}
}
if(!Utils.checkNum(after) && after!='('){
resp.setMsg("操作符之后不能 不是数字或者'(':"+(i+1)).setOk(false);
}
}
if(i==0){
if(one=='*' || one=='/'){
resp.setMsg("/ 和 * 不能在开头:"+(i+1)).setOk(false);
}
}
if(i==s.length()-1){
if(Utils.checkOpt(one)){
// 不能以符号结尾
resp.setMsg("不能以符号结尾:"+(i+1)).setOk(false);
}
}
}
}
return resp;
}
}
package behavioralpattern.patterncase.caseone.handler;
import behavioralpattern.patterncase.caseone.Utils;
/**
* @author tx
* @version 1.0
* @date 2024/1/16 9:40
* @description: 小数点校验
*/
public class CheckPoint extends AbsHandler{
@Override
protected Resp hand(Resp resp) {
String s = Utils.get(resp);
for (int i = 0; i < s.length(); i++) {
char c = s.charAt(i);
if(c=='.'){
// 点的要求,前后都得是数字
if(i==0||i==s.length()-1){
resp.setOk(false).setMsg("小数点使用不符合规范:"+(i+1));
}
if(i>0&&i<s.length()-1){
char before = s.charAt(i - 1);
char after = s.charAt(i+1);
if(!Utils.checkNum(before)&&!Utils.checkNum(after)){
resp.setOk(false).setMsg("小数点使用不符合规范:"+(i+1));
}
}
}
}
return resp;
}
}
package behavioralpattern.patterncase.caseone.handler;
import behavioralpattern.commandpattern.command.*;
import behavioralpattern.patterncase.caseone.Utils;
import java.math.BigDecimal;
import java.util.HashMap;
import java.util.Map;
/**
* @author tx
* @version 1.0
* @date 2024/1/16 10:00
* @description:
* 计算节点,最后一个节点
* 结合命令模式进行计算
*/
public class CalculateHandler extends AbsHandler{
private static final Map<Character, Command> commands = new HashMap<>();
static {
commands.put('+',new AddC());
commands.put('-',new SubC());
commands.put('*',new MulC());
commands.put('/',new DivC());
}
private void exec(Resp resp){
// 获取运算命令
Character opt = resp.opts.pop();
Command command = commands.get(opt);
// 获取2个数值
String towN = resp.nums.pop();
String oneN = resp.nums.pop();
// 进行运算,将结果重新放入数值列表中。
BigDecimal execute = command.execute(new BigDecimal(oneN), new BigDecimal(towN));
resp.nums.push(execute.toString());
}
@Override
protected Resp hand(Resp resp) {
// 前面的处理校验都通过了才进行计算
if(resp.ok()){
String s = Utils.get(resp);
int len = s.toCharArray().length;
// 循环获取字符,通过i和cur截取出数值
int i = 0,cur = 0;
for (; i < len; i++) {
char one = s.charAt(i);
if(Utils.checkOpt(one)||Utils.checkBracket(one)){
// 获取数值
if(i!=cur){
resp.nums.push(s.substring(cur,i));
}
// + - 单独处理,可能是正负号
if(one=='-'||one=='+'){
if(i==0||(s.charAt(i-1)=='(')){
continue;
}
}
cur = i+1;
// 遇到 ) 进行计算,遇到优先级高的,先计算
// 先判断是不是 )
if(one==')'){
if (resp.opts.peek()!='(') {
exec(resp);
}
// 弹出 (
resp.opts.pop();
} else if (Utils.checkOpt(one)) {
if (!resp.opts.isEmpty()&&
(resp.opts.peek()=='*'||resp.opts.peek()=='/')) {
exec(resp);
}
resp.opts.push(one);
}else {
resp.opts.push(one);
}
}
}
// 获取数值
if(i!=cur){
resp.nums.push(s.substring(cur,i));
}
while (!resp.opts.isEmpty()){
exec(resp);
}
resp.setData(resp.nums.peek());
}
return resp;
}
}
package behavioralpattern.patterncase.caseone.handler;
import behavioralpattern.commandpattern.command.*;
import behavioralpattern.patterncase.caseone.Utils;
import java.math.BigDecimal;
import java.util.HashMap;
import java.util.Map;
/**
* @author tx
* @version 1.0
* @date 2024/1/16 10:00
* @description:
* 计算节点,最后一个节点
* 结合命令模式进行计算
*/
public class CalculateHandler extends AbsHandler{
private static final Map<Character, Command> commands = new HashMap<>();
static {
commands.put('+',new AddC());
commands.put('-',new SubC());
commands.put('*',new MulC());
commands.put('/',new DivC());
}
private void exec(Resp resp){
// 获取运算命令
Character opt = resp.opts.pop();
Command command = commands.get(opt);
// 获取2个数值
String towN = resp.nums.pop();
String oneN = resp.nums.pop();
// 进行运算,将结果重新放入数值列表中。
BigDecimal execute = command.execute(new BigDecimal(oneN), new BigDecimal(towN));
resp.nums.push(execute.toString());
}
@Override
protected Resp hand(Resp resp) {
// 前面的处理校验都通过了才进行计算
if(resp.ok()){
String s = Utils.get(resp);
int len = s.toCharArray().length;
// 循环获取字符,通过i和cur截取出数值
for (int i = 0,cur = 0; i < len; i++) {
char one = s.charAt(i);
if(Utils.checkOpt(one)||Utils.checkBracket(one)){
// 获取数值
if(i!=cur){
resp.nums.push(s.substring(cur,i));
}
cur = i+1;
// 遇到 ) 进行计算,遇到优先级高的,先计算
// 先判断是不是 )
if(one==')'){
if (resp.opts.peek()!='(') {
exec(resp);
}
// 弹出 (
resp.opts.pop();
} else if (Utils.checkOpt(one)) {
if (!resp.opts.isEmpty()&&
(resp.opts.peek()=='*'||resp.opts.peek()=='/')) {
exec(resp);
}
resp.opts.push(one);
}else {
resp.opts.push(one);
}
}
}
while (!resp.opts.isEmpty()){
exec(resp);
}
resp.setData(resp.nums.peek());
}
return resp;
}
}
定义一个模板,留一个接口供子类选择和组合使用那些节点,定义模板方法获取运行结果。
package behavioralpattern.patterncase.caseone.handlerconf;
import behavioralpattern.commandpattern.command.*;
import behavioralpattern.patterncase.caseone.handler.AbsHandler;
import behavioralpattern.patterncase.caseone.handler.Resp;
import java.util.HashMap;
import java.util.Map;
/**
* @author tx
* @version 1.0
* @date 2024/1/16 9:45
* @description:
* 计算器模板的抽象层
*/
public abstract class AbsCalculatorTemplate {
// 聚合处理校验责任链
private AbsHandler absHandler;
public AbsCalculatorTemplate() {
this.absHandler = setHandler();
}
// 留个接口给子类配置
protected abstract AbsHandler setHandler();
// 进行运算获取结果
public final String execute(Resp r){
absHandler.start(r);
System.out.println(r);
if (r.ok()){
return r.data();
}
return r.msg();
}
}
package behavioralpattern.patterncase.caseone.handlerconf;
import behavioralpattern.patterncase.caseone.handler.*;
/**
* @author tx
* @version 1.0
* @date 2024/1/16 10:30
* @description:
* 计算器本体
*/
public class Calculator extends AbsCalculatorTemplate{
@Override
protected AbsHandler setHandler() {
// 构造责任链,返回给父类使用
// 校验是否为空串,并去除其中的空格
AbsHandler checkEmpty = new CheckEmpty();
// 校验字符是否合法
AbsHandler checkChars = new CheckChars();
// 校验符号使用是否合法
AbsHandler checkOpt = new CheckOpt();
// 校验小数点使用是否合法
AbsHandler checkPoint = new CheckPoint();
// 校验括号使用是否合法
AbsHandler checkBracket = new CheckBracket();
// 计算节点
AbsHandler calculateHandler = new CalculateHandler();
// 串起来
checkEmpty.setNext(checkChars);
checkChars.setNext(checkOpt);
checkOpt.setNext(checkPoint);
checkPoint.setNext(checkBracket);
checkBracket.setNext(calculateHandler);
return checkEmpty;
}
}
package behavioralpattern.patterncase.caseone;
import behavioralpattern.patterncase.caseone.handler.*;
import behavioralpattern.patterncase.caseone.handlerconf.AbsCalculatorTemplate;
import behavioralpattern.patterncase.caseone.handlerconf.Calculator;
/**
* @author tx
* @version 1.0
* @date 2024/1/16 9:16
* @description:
* 综合示例 命令模式+模板模式+责任链模式
*/
public class CaseOne {
public static void main(String[] args) {
// 构造参数对象
// 表达式
String expression = "(1+1.5)*(2*(5-1)/2)*(1)";
//括号不匹配
Resp stringResp = new Resp(expression);
// 创建一个计算器
AbsCalculatorTemplate calculator = new Calculator();
String execute = calculator.execute(stringResp);
}
}
详细代码见gitee