`
javatar
  • 浏览: 1699730 次
  • 性别: Icon_minigender_1
  • 来自: 杭州699号
社区版块
存档分类
最新评论

重构按类型分派处理

    博客分类:
  • HTTL
 
阅读更多
在MeteorTL(http://www.meteortl.org)中,多处遇到需要按类型分派处理,如: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);
	}

}
分享到:
评论
3 楼 wwlhp 2008-01-12  
chain和dispatcher的思路是相同的,只是controlling handler对各种子类handler实例的组织结构不同而已。但都面临着一个问题,如何将子类handler实例注册到总控handler?
2 楼 javatar 2007-10-18  
如果匹配方式稳定,用Dispatcher方式是比较好的选择,但职责链可以处理更多特殊情况,因为Handler类可以随时调用nextHandler进行处理。
1 楼 huangyh 2007-10-16  
由具体的Handler负责返回下一个Handler,是不是不大合适,这样很容易出现循环链路。是不是用 BinaryOperatorHandlerDispatcher  来负责 Handler 顺序维护?

相关推荐

    Best Practice in Design Patten

    随着新的请求类型被添加进来,条件分派器会逐渐变得庞大而笨拙。 2. 缺乏灵活性和可维护性。代码膨胀使得更改或维护逻辑变得困难。 为了改进代码结构,文档中提出了提取方法(Extract Method)的改进策略。提取...

    Mycat从入门到精通之Mycat架构+Catlet分析.pptx

    - **动态加载Catlet**:Catlet是Mycat中的可插拔组件,可以动态加载并处理特定类型的SQL语句。 - **SQLJobHandler**:负责处理SQL任务的具体逻辑。 - **工作流程**: - 创建SQLJob对象,包含具体的SQL语句及其上...

    Python编程思想 [Bruce.Eckel编程思想系列丛书].Thinking_In_Python.pdf

    本书讲解了装饰器的基本结构,以及如何利用装饰器来实现动态类型选择,如根据不同的输入动态选择不同的处理方式。 #### 迭代器:解耦算法与容器 迭代器模式是设计模式之一,用于顺序访问集合对象,而无需暴露其...

    基于层次消息总线的体系结构

    HMB风格的核心是消息总线,它作为系统中的连接件,负责消息的分派、传递、过滤以及处理结果的返回。消息总线的存在使得系统具有高度的扩展性和适应性,同时也为软件架构设计提供了一个统一的框架。 ##### 2.2 构件...

    软件架构与设计模式2.ppt

    - **分类**:模式可以按解决的问题类型进行分类,如结构型模式、行为型模式和创建型模式。 3. **常用模式** - **从混沌到结构**:通过模式的应用,可以从无序的状态构建出有序的系统结构。 - **分布式基础设施**...

    写Java程序最容易犯的21种错误

    15. **中间人(Middle Man)**:如果一个类大部分方法都是简单的分派,可能需要去除这个中间层,直接连接调用者和实际执行者。 16. **不适当的亲密关系(Inappropriate Intimacy)**:类之间过度交互,破坏了封装。限制...

    Eclipse权威开发指南2.pdf

    5.6.4 断开项目与CVS的连接或为项目重分派一个CVS资源库..... 154 5.7 练习概述...... 154 5.8 本章小结...... 155 5.9 参考文献...... 155 第6章 Eclipse环境管理 157 6.1 Eclipse安装实例概览...... 158 6.1.1 ...

    2021-2022计算机二级等级考试试题及答案No.3899.docx

    - **详细解析**:给定二叉树的前序遍历和中序遍历序列,可以通过一定的算法来重构该二叉树,并进而得出其后序遍历的结果。在本例中,根据给定的前序遍历`ABDEGCFH`和中序遍历`DBGEACHF`,可以推导出后序遍历结果为`...

    Eclipse权威开发指南3.pdf

    5.6.4 断开项目与CVS的连接或为项目重分派一个CVS资源库..... 154 5.7 练习概述...... 154 5.8 本章小结...... 155 5.9 参考文献...... 155 第6章 Eclipse环境管理 157 6.1 Eclipse安装实例概览...... ...

    Eclipse权威开发指南1.pdf

    5.6.4 断开项目与CVS的连接或为项目重分派一个CVS资源库..... 154 5.7 练习概述...... 154 5.8 本章小结...... 155 5.9 参考文献...... 155 第6章 Eclipse环境管理 157 6.1 Eclipse安装实例概览...... ...

    二十三种设计模式【PDF版】

    在真正可复用的面向对象编程中,GoF 的《设计模式》为我们提供了一套可复用的面向对象技术,再配合 Refactoring(重构方法), 所以很少存在简单重复的工作,加上Java 代码的精炼性和面向对象纯洁性(设计模式是 java 的...

Global site tag (gtag.js) - Google Analytics