重构按类型分派处理

本文探讨了在表达式解析引擎中处理不同类型操作符的方法,包括直接类型检查、职责链模式及注册型处理器等策略。
在MeteorTL([url]http://www.meteortl.org[/url])中,多处遇到需要按类型分派处理,如:BinaryOperatorHandler,UnaryOperatorHandler,PropertyHandler,OutputFormatter,StringSequence等,
以BinaryOperatorHandler为例:
当引擎遇到二元操作符会回调BinaryOperatorHandler进行求值,接口如下:

public interface BinaryOperatorHandler extends OperatorHandler {

// 传入操作数,返回求值结果
public Object doEvaluate(Object leftOperand, Object rightOperand)
throws ExpressionException;

}


但有的操作符是重载的,
如:加号(+),在操作数为“数字”和“字符串”时要进行不同的操作,

1.最直接的实现方法是使用instanceof逐个判断,但其可扩展性极差,实现如下:

public class AddBinaryOperatorHandler implements BinaryOperatorHandler {

public Object doEvaluate(Object leftOperand, Object rightOperand)
throws ExpressionException {
if (leftOperand instanceof Integer && leftOperand instanceof Integer)
return new Integer(((Integer)leftOperand).intValue()
+ ((Integer)rightOperand).intValue());
/* 如果要添加一个日期加法,就需要修改代码加入else if
else if (leftOperand instanceof Date && leftOperand instanceof DateNumber)
return new Date(((Date)leftOperand).getTime()
+ ((DateNumber)rightOperand).getTime());*/
else
return String.valueOf(leftOperand) + String.valueOf(rightOperand);
}

}


2.职责链模式,每个Handler持有下一个Handler的引用,实现如下:

public abstract class BinaryOperatorHandlerChain implements BinaryOperatorHandler {

private BinaryOperatorHandler nextHandler;

protected BinaryOperatorHandler getNextHandler() {
return nextHandler;
}

public void setNextHandler(BinaryOperatorHandler nextHandler) {
this.nextHandler = nextHandler;
}

}

public class IntegerAddBinaryOperatorHandler extends BinaryOperatorHandlerChain {

public Object doEvaluate(Object leftOperand, Object rightOperand)
throws ExpressionException {
if (leftOperand instanceof Integer && leftOperand instanceof Integer)
return new Integer(((Integer)leftOperand).intValue()
+ ((Integer)rightOperand).intValue());
return getNextHandler().doEvaluate(leftOperand, rightOperand);
}

}

public class StringAddBinaryOperatorHandler extends BinaryOperatorHandlerChain {

// @overwrite
public void setNextHandler(BinaryOperatorHandler nextHandler) {
throw new ConfigurationException("字符串相加为终结处理,不能有下一Handler!");
}

public Object doEvaluate(Object leftOperand, Object rightOperand)
throws ExpressionException {
return String.valueOf(leftOperand) + String.valueOf(rightOperand);
}

}


3. 用一个包装类,注册相应类型的处理类,实现如下:

public class BinaryOperatorHandlerDispatcher implements BinaryOperatorHandler {

private final Map matchHandlers; //类型为<BinaryOperandMatcher, BinaryOperatorHandler>

private final BinaryOperatorHandler defaultHandler;

public BinaryOperatorHandlerDispatcher(Map matchHandlers, BinaryOperatorHandler defaultHandler) {
this.matchHandlers = matchHandlers;
this.defaultHandler = defaultHandler;
}

public Object doEvaluate(Object leftOperand, Object rightOperand)
throws ExpressionException {
// 在集合中匹配相应类型的处理器
for (Iterator iterator = matchHandlers.entrySet().iterator(); iterator.hasNext();) {
Map.Entry entry = (Map.Entry)iterator.next();
if (((BinaryOperandMatcher)entry.getKey()).isMatch(leftOperand, rightOperand))
return ((BinaryOperatorHandler)entry.getValue()).doEvaluate(leftOperand, rightOperand);
}
// 未找到相应类型的处理器则使用默认处理器
if (defaultHandler != null)
return defaultHandler.doEvaluate(leftOperand, rightOperand);
//否则抛出异常
throw new UnhandleException("没有找到相应处理类!");
}

}

public class BinaryOperandMatcher {

private final Class leftOperandClass;

private final Class rightOperandClass;

public BinaryOperandMatcher(Class leftOperandClass, Class rightOperandClass) {
this.leftOperandClass = leftOperandClass;
this.rightOperandClass = rightOperandClass;
}

// 匹配操作数类型
public boolean isMatch(Object leftOperand, Object rightOperand) {
return isMatchClass(leftOperand, leftOperandClass) && isMatchClass(rightOperand, rightOperandClass);
}

private boolean isMatchClass(Object operand, Class operandClass) {
if (operandClass == null || operand == null)
return operandClass == null && operand == null;
return operandClass.isAssignableFrom(operand.getClass());
}

}

public class IntegerAddBinaryOperatorHandler implements BinaryOperatorHandler {

public Object doEvaluate(Object leftOperand, Object rightOperand)
throws ExpressionException {
assert(leftOperand instanceof Integer && leftOperand instanceof Integer);
return new Integer(((Integer)leftOperand).intValue() + ((Integer)rightOperand).intValue());
}

}

public class StringAddBinaryOperatorHandler implements BinaryOperatorHandler {

public Object doEvaluate(Object leftOperand, Object rightOperand)
throws ExpressionException {
return String.valueOf(leftOperand)
+ String.valueOf(rightOperand);
}

}
``` import numpy as np import pymssql import pandas as pd import math def calculate_workday(): server = '100.00.00.00' database = 'D' username = 'x' password = '@' port = '1433' # 如果使用默认端口号(1433),则可以省略此步骤 # 连接数据库并执行查询 conn = pymssql.connect(server, user=username, password=password, database=database, port=port) query ="SELECT * FROM DLCH.dbo.CH_MainDt WHERE ((YWNRId >= 1 AND YWNRId <= 41) OR (YWNRId >= 85 AND YWNRId <= 97)) ORDER BY CreateTime" # 获取查询结果,将结果写入df csv_data = pd.read_sql_query(query, conn) conn.close() # 新增类型转换步骤(在数据处理前执行) csv_data['YWNRId'] = csv_data['YWNRId'].astype(str) # 保证需要参与计算工期的列为数值 columns_to_convert = ['paraInt1', 'paraInt2', 'paraInt3', 'paraFloat1', 'paraFloat2', 'paraFloat5'] for column in columns_to_convert: csv_data[column] = pd.to_numeric(csv_data[column], errors='coerce') # 判断工期和工作量并将结果存入新的列中 def cal_workday(csv_data): csv_data['工期'] = '协商' csv_data['工作量'] = '' csv_data['工作量'] = csv_data['工作量'].astype(str) # 转化成字符串形式 csv_data = cal_workday(csv_data) # 关键步骤:将计算结果合并回原DataFrame # 输出到CSV csv_data.to_csv('计算结果.csv', index=False, encoding='utf_8_sig') # 支持中文路径 print("文件已成功导出为 计算结果.csv")```YWNRId为int,'paraInt1', 'paraInt2', 'paraInt3', 'paraFloat1', 'paraFloat2', 'paraFloat5'每一列都存有空值,YWNRId=7的业务类型,paraFloat1为存储面积的字段,当面积≤5万平方米,工期为7;面积>5万平方米,每增加5万平方米,增加2个工作日;工期的上限为25个工作日。YWNRId=16的业务类型,paraFloat1为存储面积的字段,现更改工期计算的规则,当面积≤5万平方米,工期为10;5万平方米<面积≤10万平方米,工期为12;10万平方米<面积≤20万平方米,工期为15;面积>20万平方米,每增加5万平方米,增加3个工作日。YWNRId=85的业务类型,工期为3个工作日。YWNRId=11的业务类型,工期为10个工作日。YWNRId=12的业务类型,计算字段为paraInt1,当建(构)筑物幢数≤2,为6工作日;2<建(构)筑物幢数≤5,为9个工作日;6<建(构)筑物幢数≤10为12个工作日;11<建(构)筑物幢数≤20,为15个工作日;建(构)筑物幢数>20,每增加2幢,增加1个工作日。YWNRId=10的业务类型,计算字段为paraFloat1,建筑面积≤20000平方米,为10个工作日;20000平方米<建筑面积≤50000平方米,为12个工作日;建筑面积>50000平方米,为25个工作日YWNRId=1和YWNRId=83的业务类型,计算规则相同,计算字段为paraInt1,建(构)筑物幢数=1,工期为5;2≤建(构)筑物幢数≤10,每增加1幢,增加1个工作日;建(构)筑物幢数>10,工期为25。YWNRId=2和YWNRId=89的业务类型,计算规则相同,计算字段为paraFloat1,建筑面积≤20000平方米,工期为10;20000平方米<建筑面积≤50000平方米,工期为12个工作日;建筑面积>50000平方米,工期为25。YWNRId=3和YWNRId=90的业务类型,计算规则相同,计算字段为paraFloat5,长度≤0.5公里,工期为8;长度>0.5公里,每增加0.5公里,增加2个工作日,上限为37。YWNRId=4和YWNRId=91的业务类型,计算规则相同,计算字段为paraFloat5,长度≤0.5公里,工期为8;长度>0.5公里,每增加0.5公里,增加2个工作日,上限为37。YWNRId=13和YWNRId=92的业务类型,计算规则相同,计算字段为paraFloat5,长度≤0.5公里,工期为5;长度>0.5公里,每增加0.5公里,增加1个工作日,上限为25。YWNRId=9的业务类型,计算字段为paraFloat5,长度≤0.5公里,工期为8;长度>0.5公里,每增加0.5公里,增加2个工作日,上限为37。YWNRId=8的业务类型,计算字段为paraFloat1,面积≤5万平方米,工期为13;面积>5万平方米,每增加5万平方米,增加4个工作日,增加4个工作日,上限为37。YWNRId=86的业务类型,计算字段为paraFloat5,长度≤0.5公里,工期为8;长度>0.5公里,每增加0.5公里,增加2个工作日,上限为37。YWNRId=87的业务类型,工期为3个工作日。YWNRId=41的业务类型,工期为‘协商’。YWNRId=39的业务类型,计算字段为paraFloat1,1平方公里<面积≤15平方公里,工期为7;面积>15平方公里,每增加5平方公里,增加1个工作日。YWNRId=94的业务类型,计算字段为paraFloat1,1平方公里<面积≤15平方公里,工期为5;面积>15平方公里,每增加5平方公里,增加1个工作日。YWNRId=32的业务类型,工期为3个工作日。YWNRId=33的业务类型,工期为3个工作日。YWNRId=27的业务类型,工期为5个工作日。YWNRId=95的业务类型,工期为5个工作日。YWNRId=26的业务类型,工期为5个工作日。YWNRId=96的业务类型,工期为5个工作日。YWNRId=97的业务类型,工期为5个工作日。
03-15
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值