- 浏览: 487398 次
- 性别:
- 来自: 上海
文章分类
最新评论
-
gapper:
多谢!!!
软件项目解决方案模板 -
lxyizy521:
感谢你无私的分享,正头疼文档的事情呢。
软件项目解决方案模板 -
flyisland:
不错的资料收集的心得,多谢分享!
如何从小工到专家——Dreyfus模型应用 -
a254124185:
Java编码规范及实践 -
clj2008tom:
LZ好久没更新了,呵呵
graphviz 在redhat as4 下的安装
参考资料:
http://en.wikipedia.org/wiki/Double_dispatch
http://en.wikipedia.org/wiki/Multiple_dispatch
http://hi.baidu.com/blue_never_died/blog/item/2d19403474fd3b4e251f149a.html
几个源代码搜索引擎
Koder有firefox搜索条扩展。
分派过程就是确定一个方法调用的过程,双分派就是根据运行时多个对象的类型确定方法调用的过程。
想象这样一个客户服务的场景,一般客户支持有一级支持和二级支持。一级支持一般解决比较简单的问题,如果问题解决不了,就会由二级支持来解决。
定义一般问题:
package com.baskode.test.doubledispatch; public class Problem { }
定义特殊问题:
package com.baskode.test.doubledispatch; public class SpecialProblem extends Problem { }
定义一级支持:
package com.baskode.test.doubledispatch; public class Supporter { void solve(Problem problem){ System.out.println("一级支持解决一般问题!"); } void solve(SpecialProblem problem){ System.out.println("一级支持解决特殊问题"); } }
定义资深支持:
package com.baskode.test.doubledispatch; public class SeniorSupporter extends Supporter{ void solve(Problem problem){ System.out.println("资深支持解决一般问题!"); } void solve(SpecialProblem specProblem){ System.out.println("资深支持解决特殊问题!"); } }
下面是测试类:
package com.baskode.test.doubledispatch; import org.junit.After; import org.junit.Before; import org.junit.Test; public class DoubleDispatchTest { @Before public void setUp() throws Exception { } @After public void tearDown() throws Exception { } /** * 函数重载 */ @Test public void functionOverload(){ Problem problem = new Problem(); SpecialProblem specProblem = new SpecialProblem(); Supporter supporter = new Supporter(); supporter.solve(problem); supporter.solve(specProblem); } /** * 单次动态分派 */ @Test public void singleDynamicDispatch(){ Problem problem = new Problem(); SpecialProblem specProblem = new SpecialProblem(); Supporter supporter = new SeniorSupporter(); supporter.solve(problem); supporter.solve(specProblem); //资深支持解决一般问题! //资深支持解决特殊问题! //能够正确路由 } @Test public void someError(){ Problem problem = new Problem(); Problem specProblem = new SpecialProblem(); Supporter supporter = new SeniorSupporter(); supporter.solve(problem); supporter.solve(specProblem); //资深支持解决一般问题! //资深支持解决一般问题! //出错了,与我们意图不一样 } }
先看singleDispatch和someError方法,区别就在下面一句:
singleDynamicDispatch
SpecialProblem specProblem = new SpecialProblem();
someError
Problem specProblem = new SpecialProblem();
对于singleDynamicDispatch其实进行了两次分派,首先编译时分别绑定了solve(Problem)方法和solve(SpecialProblem),然后solve方法的多态路由到SeniorSupporter.solve(Problem)和SeniorSupporter.solve(SpecialProblem)。这时执行结果是正确的。
对与someError方法,因为两个Problem编译时的类型都是Problem,所以静态绑定都是solve(Problem)方法。
所以运行结果不是我们所期望的。
解决这个问题,就是想办法在运行时根据Problem和Supporter的具体类型进行分派。
在Problem中增加如下方法,在方法调用时将自身传入。
package com.baskode.test.doubledispatch; public class Problem { void solve(Supporter supporter){ supporter.solve(this); } }
在SpecialProblem,增加如下方法,在方法调用时,将自身传入:
package com.baskode.test.doubledispatch; public class SpecialProblem extends Problem { void solve(Supporter supporter){ supporter.solve(this); } }
看看现在的测试代码:
package com.baskode.test.doubledispatch; import org.junit.After; import org.junit.Before; import org.junit.Test; public class DoubleDispatchTest { @Before public void setUp() throws Exception { } @After public void tearDown() throws Exception { } /** * 函数重载,静态分派,编译时 */ @Test public void functionOverload(){ Problem problem = new Problem(); SpecialProblem specProblem = new SpecialProblem(); Supporter supporter = new Supporter(); supporter.solve(problem); supporter.solve(specProblem); } /** * 单次分派,运行时确定Supporter类型为S */ @Test public void singleDynamicDispatch(){ Problem problem = new Problem(); SpecialProblem specProblem = new SpecialProblem(); Supporter supporter = new SeniorSupporter(); supporter.solve(problem); supporter.solve(specProblem); //资深支持解决一般问题! //资深支持解决特殊问题! //能够正确路由 } @Test public void someError(){ Problem problem = new Problem(); Problem specProblem = new SpecialProblem(); Supporter supporter = new SeniorSupporter(); supporter.solve(problem); supporter.solve(specProblem); //资深支持解决一般问题! //资深支持解决一般问题! //出错了,与我们意图不一样 } @Test public void doubleDispatch(){ Problem problem = new Problem(); Problem specProblem = new SpecialProblem(); Supporter supporter = new SeniorSupporter(); problem.solve(supporter); specProblem.solve(supporter); //资深支持解决一般问题! //资深支持解决特殊问题! //Now,It's right! } }
现在,通过调用:
problem.solve(supporter); specProblem.solve(supporter);
来实现两次动态分派,第一次是problem中solve方法的多态,第二次是supporter中solve方法的多态。
参观者模式 (Vistor)也使用了类似的方式。
我们经常用的JUnit,也是采用这种方式实现TestCase和TestResult的灵活扩展。
package junit.framework; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.lang.reflect.Modifier; /** * A test case defines the fixture to run multiple tests. To define a test case<br> * 1) implement a subclass of TestCase<br> * 2) define instance variables that store the state of the fixture<br> * 3) initialize the fixture state by overriding <code>setUp</code><br> * 4) clean-up after a test by overriding <code>tearDown</code>.<br> * Each test runs in its own fixture so there * can be no side effects among test runs. * Here is an example: * <pre> * public class MathTest extends TestCase { * protected double fValue1; * protected double fValue2; * * protected void setUp() { * fValue1= 2.0; * fValue2= 3.0; * } * } * </pre> * * For each test implement a method which interacts * with the fixture. Verify the expected results with assertions specified * by calling <code>assertTrue</code> with a boolean. * <pre> * public void testAdd() { * double result= fValue1 + fValue2; * assertTrue(result == 5.0); * } * </pre> * Once the methods are defined you can run them. The framework supports * both a static type safe and more dynamic way to run a test. * In the static way you override the runTest method and define the method to * be invoked. A convenient way to do so is with an anonymous inner class. * <pre> * TestCase test= new MathTest("add") { * public void runTest() { * testAdd(); * } * }; * test.run(); * </pre> * The dynamic way uses reflection to implement <code>runTest</code>. It dynamically finds * and invokes a method. * In this case the name of the test case has to correspond to the test method * to be run. * <pre> * TestCase test= new MathTest("testAdd"); * test.run(); * </pre> * The tests to be run can be collected into a TestSuite. JUnit provides * different <i>test runners</i> which can run a test suite and collect the results. * A test runner either expects a static method <code>suite</code> as the entry * point to get a test to run or it will extract the suite automatically. * <pre> * public static Test suite() { * suite.addTest(new MathTest("testAdd")); * suite.addTest(new MathTest("testDivideByZero")); * return suite; * } * </pre> * @see TestResult * @see TestSuite */ public abstract class TestCase extends Assert implements Test { /** * the name of the test case */ private String fName; /** * No-arg constructor to enable serialization. This method * is not intended to be used by mere mortals without calling setName(). */ public TestCase() { fName= null; } /** * Runs the test case and collects the results in TestResult. */ public void run(TestResult result) { result.run(this); } 。。。。。。 }
package junit.framework; import java.util.Enumeration; import java.util.Vector; /** * A <code>TestResult</code> collects the results of executing * a test case. It is an instance of the Collecting Parameter pattern. * The test framework distinguishes between <i>failures</i> and <i>errors</i>. * A failure is anticipated and checked for with assertions. Errors are * unanticipated problems like an <code>ArrayIndexOutOfBoundsException</code>. * * @see Test */ public class TestResult extends Object { protected Vector fFailures; protected Vector fErrors; protected Vector fListeners; protected int fRunTests; private boolean fStop; public TestResult() { fFailures= new Vector(); fErrors= new Vector(); fListeners= new Vector(); fRunTests= 0; fStop= false; } /** * Adds an error to the list of errors. The passed in exception * caused the error. */ public synchronized void addError(Test test, Throwable t) { fErrors.addElement(new TestFailure(test, t)); for (Enumeration e= cloneListeners().elements(); e.hasMoreElements(); ) { ((TestListener)e.nextElement()).addError(test, t); } } /** * Adds a failure to the list of failures. The passed in exception * caused the failure. */ public synchronized void addFailure(Test test, AssertionFailedError t) { fFailures.addElement(new TestFailure(test, t)); for (Enumeration e= cloneListeners().elements(); e.hasMoreElements(); ) { ((TestListener)e.nextElement()).addFailure(test, t); } } /** * Registers a TestListener */ public synchronized void addListener(TestListener listener) { fListeners.addElement(listener); } /** * Unregisters a TestListener */ public synchronized void removeListener(TestListener listener) { fListeners.removeElement(listener); } /** * Returns a copy of the listeners. */ private synchronized Vector cloneListeners() { return (Vector)fListeners.clone(); } /** * Informs the result that a test was completed. */ public void endTest(Test test) { for (Enumeration e= cloneListeners().elements(); e.hasMoreElements(); ) { ((TestListener)e.nextElement()).endTest(test); } } /** * Gets the number of detected errors. */ public synchronized int errorCount() { return fErrors.size(); } /** * Returns an Enumeration for the errors */ public synchronized Enumeration errors() { return fErrors.elements(); } /** * Gets the number of detected failures. */ public synchronized int failureCount() { return fFailures.size(); } /** * Returns an Enumeration for the failures */ public synchronized Enumeration failures() { return fFailures.elements(); } /** * Runs a TestCase. */ protected void run(final TestCase test) { startTest(test); Protectable p= new Protectable() { public void protect() throws Throwable { test.runBare(); } }; runProtected(test, p); endTest(test); } /** * Gets the number of run tests. */ public synchronized int runCount() { return fRunTests; } /** * Runs a TestCase. */ public void runProtected(final Test test, Protectable p) { try { p.protect(); } catch (AssertionFailedError e) { addFailure(test, e); } catch (ThreadDeath e) { // don't catch ThreadDeath by accident throw e; } catch (Throwable e) { addError(test, e); } } /** * Checks whether the test run should stop */ public synchronized boolean shouldStop() { return fStop; } /** * Informs the result that a test will be started. */ public void startTest(Test test) { final int count= test.countTestCases(); synchronized(this) { fRunTests+= count; } for (Enumeration e= cloneListeners().elements(); e.hasMoreElements(); ) { ((TestListener)e.nextElement()).startTest(test); } } /** * Marks that the test run should stop. */ public synchronized void stop() { fStop= true; } /** * Returns whether the entire test was successful or not. */ public synchronized boolean wasSuccessful() { return failureCount() == 0 && errorCount() == 0; } }
以下是Spring中的代码,XmlWebApplicationContext:
实现BeanDefinitionReader和ApplicationContext的灵活扩展。
protected void loadBeanDefinitions(DefaultListableBeanFactory beanFactory) throws IOException { // Create a new XmlBeanDefinitionReader for the given BeanFactory. XmlBeanDefinitionReader beanDefinitionReader = new XmlBeanDefinitionReader(beanFactory); // Configure the bean definition reader with this context's // resource loading environment. beanDefinitionReader.setResourceLoader(this); beanDefinitionReader.setEntityResolver(new ResourceEntityResolver(this)); // Allow a subclass to provide custom initialization of the reader, // then proceed with actually loading the bean definitions. initBeanDefinitionReader(beanDefinitionReader); loadBeanDefinitions(beanDefinitionReader); }
发表评论
-
如何在公司中引入新思路——fearless change
2009-09-28 00:21 1413我前面的博客也提到,在一个公司中,引入一个新的想法,获得成功并 ... -
Code Review Patterns
2009-06-23 09:57 1508整理了一下Code Review中 ... -
团队分析与设计(TeamAnalysisDesignPattern)
2009-04-11 14:31 14441)Problem 问题域比较复杂,团队中没有人能 ... -
极限会议模式(ExtremeMeeting)
2009-03-17 13:38 1892名字自己随便取的,如有雷同,纯属巧合。 1. Proble ... -
5W问题分析模式
2009-03-10 08:41 01. Problem 当遇到问题,手足无措时。 2. So ... -
影响分析模式(InfluenceAnalysisPattern)
2009-03-06 23:58 12561. Problem 解决问题,进行决策和面对改变时, ... -
全局目标导向模式(GlobalTargetOrientedPattern)
2009-03-05 23:08 9641. Problem 一个团队在做事情的过 ... -
通讯录模式(AddressListPattern)
2009-03-02 22:10 1526模式是实践的抽象,今天我来总结一下通讯录模式。 1. Pr ... -
导航者模式(NavigatorPattern)
2009-02-28 10:40 01. Problem 人是容易犯错的,而且但线条的。 ... -
有人的地方就有江湖
2009-01-30 08:54 2342有人的地方就有 ... -
设计模式快速参考-参观者模式
2008-12-06 07:27 1672参观者模式主要对一组固定结构的对象进行访问,一般和组合模式一起 ... -
设计模式快速参考-模板方法模式
2008-12-06 07:21 1093abstract class TravelTemplate ... -
设计模式快速参考-策略模式
2008-12-06 07:17 1207//密钥对生成接口 interface IKeyPairGen ... -
设计模式快速参考-观察者模式
2008-12-06 07:13 1314//主题,这里是快餐店 class SnackShop{ ... -
设计模式快速参考-命令模式
2008-12-06 07:10 1310interface ICommand{ void e ... -
设计模式快速参考-代理模式
2008-12-06 07:07 1246class FileDownloader( publ ... -
设计模式快速参考-外观模式
2008-12-06 07:03 1077为一组类提供简单的外部接口,使外部调用者不需要和所 ... -
设计模式快速参考-组合模式
2008-12-06 07:00 1079abstract class Hardware{ } cla ... -
设计模式快速参考-适配器模式
2008-12-06 06:49 1267interface Powerable{ 110v ... -
设计模式快速参考-单例模式
2008-12-06 06:46 1226class Singleton{ private Si ...
相关推荐
Java、C#等仅仅支持单分派(singledispatch)而不支持双分派(double dispatch)。【相关概念,参考《设计模式.5.11访问者模式》p223】对于消息a.foo(b),假设有父类X及其两个子类X1、X2,a声明为X类型变量;有父类Y...
然而,为了深入理解这一模式,我们需要探讨一个相关概念——【双分派(Double Dispatch)】。 双分派是指在运行时,不仅根据对象的类型决定调用哪个方法,还根据方法参数的类型决定调用哪个具体实现。这与单分派...
而Visitor模式,也谈doubledispatch(双分派),这种模式可以在不改变已有对象结构的前提下增加新的操作。 总之,设计模式作为软件开发中的一种重要工具,不仅可以提高开发效率,还能使得代码结构更加清晰,易于扩展...
com.javapatterns.doubledispatch 专题:单分派与多分派 com.javapatterns.facade 门面模式 com.javapatterns.factorymethod 工厂方法模式 com.javapatterns.flyweight 享元模式 com.javapatterns.immutable ...
接下来,我们转向双事件处理线程(Double-Edged Event Dispatch Thread,简称EDT)。在Java GUI中,所有的UI更新和事件处理都必须在EDT上进行,以确保线程安全和界面的正确显示。当用户与组件交互时,事件被放入事件...
9. 文档的结构:文档包含了引言、总序、设计模式的解析、在开发中体验设计模式、深入理解State模式、对doubledispatch的探讨、为什么使用设计模式的思考以及附录等部分。 通过这些知识点,我们可以理解到C++设计...
- **Double Dispatch**:双分派是一种设计模式,允许方法选择基于两个接收者的类型进行。 #### 状态(State) - **Common State**:共享状态是在多个对象之间共享的信息,需要谨慎管理以避免副作用。 - **Variable ...
- **4.3 也谈double dispatch(双分派) :: Visitor模式**:探讨双分派在Visitor模式中的实现细节。 - **4.4 为什么使用设计模式——从Singleton模式谈起**:通过Singleton模式探讨设计模式的重要性。 #### 5. 附录 ...
- **4.3 也谈double dispatch(双分派):: Visitor模式**:通过解释双分派的概念,进一步阐述了Visitor模式的工作原理及其优势。 - **4.4 为什么使用设计模式——从Singleton模式谈起**:通过分析Singleton模式的...
例如,通过具体的案例来理解State模式的应用,或者探讨Double Dispatch(双分派)在Visitor模式中的实现。此外,还可以从Singleton模式出发,探讨为什么我们需要设计模式,以及它们如何帮助我们解决实际问题。 ####...
C#中,可以使用双分派(double dispatch)来实现访问者。 以上23种设计模式在C#编程中具有广泛的实践价值,熟练掌握这些模式将极大地提升开发效率和代码质量。通过学习压缩包中的资料,开发者可以更深入地理解这些...
- **也谈Double Dispatch(双分派):Visitor模式** - **概念介绍**:讨论双分派机制及其在Visitor模式中的实现。 - **为什么使用设计模式——从Singleton模式谈起** - **概念介绍**:解释为什么设计模式在软件开发...
为了减少类间的依赖,可以通过多种方式实现规格模式,例如使用组合模式来组合多个规格,或者通过双分派(Double Dispatch)机制来避免硬编码的if-else语句。 #### 结论 综上所述,《领域驱动设计:逐步指南》全面地...
在探讨double dispatch(双分派)机制时,可以通过Visitor模式来深入理解其原理;在讨论为什么使用设计模式时,可以从Singleton模式出发,探讨其在不同场景下的优劣。 #### 5. 附录:关于设计模式的思考 设计模式...
设计模式精解-GoF 23 种设计模式解析附 C++实现源码 目 录 0 引言 ............................................................................................................................................