该帖已经被评为精华帖
|
|
---|---|
作者 | 正文 |
发表时间:2003-11-07
先来看一下 JDK 1.0 中的事件模型。 1、在 JDK 1.0 中,所有的事件处理由 GUI 组件(Window、Menu、Button、etc.)本身负责。这些组件都有一个 action() 方法,传进来一个 Event 对象。这样要实现特殊的事件处理,就要为这些组件生成子类,然后覆盖掉 action 方法。对于 Container 类的对象是覆盖掉 handleEvent() 方法。如果子类的 handleEvent() 写得有问题,比如没有调用父类的 handleEvent(),就会造成有些事件无法得到处理的问题。 2、通过 action() 或 handleEvent() 方法传进来 Event 对象究竟是什么事件,不知道,需要再写一个长长的 switch 或者 if...else if...else 来判断。这不是面向对象的开发方式。 3、性能较差。JDK 1.0 的事件模型采用冒泡模型处理事件。在多个深度嵌套的组件中产生事件时,这些事件会冒泡到最外层容器中,由容器集中处理所有事件,这个冒泡过程会极大增加程序的冗余度。 4、将对事件所做的逻辑处理代码与 GUI 组件本身的显示代码混杂在一起。对于开发大的系统非常不利。 JDK 1.1 通过将继承关系修改为组合关系彻底改变了这一切。 JDK 1.1 中每个事件需要在 GUI 组件中注册一个 Listener,这个 Listener 和 GUI 组件是组合的关系。当有事件发生,GUI 组件调用 Listener 的一个方法(如 actionPerformed())将发生的事件传递给 Listener,由 Listener 在自己的代码片中处理,完全解决了 JDK 1.0 存在的上述问题。 1、不必再生成子类,因为现在使用的是组合而不是继承。 2、不用写 switch 或 if...else if...else 判断 Event 的类型,因为只会传给那个特定的 Listener 它所需要的特定 Event。 3、事件不用再冒泡,提高了性能。 4、逻辑处理的代码与显示的代码完全分离,实现了更好的封装。 更大的好处是增加了灵活性,使得为组件增加新的事件处理代码只需要修改很少的代码,实现了更大程度的重用。 声明:ITeye文章版权属于作者,受法律保护。没有作者书面许可不得转载。
推荐链接
|
|
返回顶楼 | |
发表时间:2003-11-08
我觉得你有一味打击继承,提倡组合的倾向
继承与组合各有各的用处,这要看在什么场合中了 |
|
返回顶楼 | |
发表时间:2003-11-08
jinbo 写道 我觉得你有一味打击继承,提倡组合的倾向
继承与组合各有各的用处,这要看在什么场合中了 这正是我们需要讨论的问题。不要撂下一句话就走啊,呵呵。 面向对象开发以接口为中心展开设计早已经是不争的事实。尤其是各种开发框架,充分体现了 Design by Contract 的思想。这个 Contract 由什么来表达?主要就是由接口来表达。接口可大可小,可以封装一个子系统,也可以只封装一个简单的类。以前我做过长期的电信协议开发,电信协议分层分得很清楚,相邻层之间通过格式严格定义的原语来进行通信。每个协议层可以接受的原语(数据和指令)就是这个协议层对外所表现的接口,而接收到特定的原语后所执行的操作(还涉及到发送相关的原语)和发生的状态迁移则是协议层本身的内部行为。 仔细分析 GOF 23 种设计模式,在叹服其设计的精巧之外,你会发现大多数模式都是以接口为中心展开讨论的(核心是组合而非继承),继承只是起到了辅助的作用,而且继承的层次一般不会超过两层,不会出现 MFC 中继承很多层的情况。 接口的思想不仅仅体现在 OOP 中,数据库设计同样是接口设计。如果数据库没有设计好,依靠高超的编程能力仍然无法解决复杂的业务问题。这就是我强调首先要做好数据库设计的原因。数据库设计就是针对接口做开发。首先把接口和协议定义好,然后再做与实现相关的工作,这是面向对象所教给我们的正确的思考方法。 我的观点是在我读了《设计模式》这些书之后自然产生的推论,如果有错误,只能说明 GOF 等人给我带来的毒害太深,不过我目前对他们还是很迷信的。 |
|
返回顶楼 | |
发表时间:2003-11-08
现在我的感觉是:
需要用模板模式的地方用继承,但只从抽象类继承,这主要是为了使用回调接口 工具类使用有限的具体继承 这是因为工具类的适用面比较窄,适度的使用具体继承能减轻工作量,这也是遵守20/80原则,不必在这个问题域追求多完美的设计,因为在这上面的投资只能换来一个特定问题的解决方法。当然,这是指一些助手类。总之就是,小规模的问题,用用具体继承也无妨 其余用接口,尽量做到面向接口编程 使用接口唯一的缺点是编码量变大,我正在考虑看看能否用代码生成技术减轻这个负担,因为好多代码都是重复的,ibaits用的就是这种策略 |
|
返回顶楼 | |
发表时间:2003-11-08
无明 写道 使用接口唯一的缺点是编码量变大,我正在考虑看看能否用代码生成技术减轻这个负担,因为好多代码都是重复的,ibaits用的就是这种策略
编码量变大是不必担心的。接口仅仅是系统的一个骨架,一个复杂的系统仅仅有这样一个骨架是绝对不够的。那样灵活性是做到了,但是易用性又无法满足了。好在框架的设计者在开发框架时已经充分考虑了这个问题。所以一些常用的接口都会开发出实现这些接口的适配器类。这些适配器类就是通用的解决方案。如果你需要特殊的解决方案可以继承这些适配器类,然后覆盖掉不符合要求的方法。 Java 里面这样的例子是很多的。AWT 中就有大量这样的 Adapter 类。 |
|
返回顶楼 | |
发表时间:2003-11-08
Java的UI部分我几乎没涉及:(
如果是接口->Adapter->覆盖方法的做法的话,那设计者的意图恐怕就是尽量缩小问题域,在一个很狭窄的地方使用具体继承 接口继承——>类型的继承 具体继承——>方法的继承 |
|
返回顶楼 | |
发表时间:2003-11-09
无明 写道 Java的UI部分我几乎没涉及:(
JDK 1.1 以后的事件模型发展到现在也没有什么变化。Java 的事件模型与 GUI(AWT/Swing)是完全无关的,只是在 GUI 应用中用的比较多。完全可以脱离开 GUI 实现自己的事件类型和事件监听器类型。 JavaBean 是我见过的最容易理解的组件模型,比起 M$ ActiveX 那些破烂货要容易理解得多,而且也灵活的多。JavaBean+Java 事件模型完全起到了一巧破千斤的效果。从面向对象的角度 Java 其实是最适合做 GUI 开发的语言,之所以没有普及只是受限于性能问题。不过目前的主流机器(P4 CPU,256M 以上内存)上已经没有任何问题了。使用 Java 来开发 IDE 已经是一个潮流,听说 C++ Builder 下一版本是用 Java 开发的。 |
|
返回顶楼 | |
发表时间:2003-11-09
有点跑题了,不如开新贴讨论一下Java的事件模型:
http://forum.hibernate.org.cn/viewtopic.php?p=5878#5878 |
|
返回顶楼 | |
发表时间:2003-11-11
接口的使用在设计模式中说得很多,但我觉得他们的说法是针对继承被过度使用而说的,比如就有人问过我在以前的项目中类有多少层。 类的层次多少可以用过比较设计是否合理么?8)
但继承在某些场合还是有必要的,比如需要强制要求子类必须执行某些操作,或符合某些约定等等。 JAVA中全部的类必须由Object中继承就是继承的一个典型应用,这也是接口无法解决的应用了 |
|
返回顶楼 | |
发表时间:2003-11-11
jinbo 写道 类的层次多少可以用过比较设计是否合理么?
我认为是可以的。这可以作为一个简单的衡量标准。继承可以做的事采用接口、组合配合适当的设计模式都是可以做的。你可以写一段完全使用继承的代码,我用设计模式帮你改写。 继承的层次越多,系统与具体实现的耦合越紧,越难以实现重用。我的看法是最好不要使用超过 3 层的继承关系。 继承的缺点是前人在做过大量开发实践后发现的。就象 goto 的缺点一样,有人争论在某些场合使用 goto 有好处我也不反对。这是一个普遍规律和特殊规律的关系。 jinbo 写道 JAVA中全部的类必须由Object中继承就是继承的一个典型应用,这也是接口无法解决的应用了
我从来没有说过接口可以解决所有的问题。接口解决的是体系结构的设计问题,只是搭出一个系统的骨架,具体的实现(系统的血肉)是与接口无关的。实现的时候要慎重使用继承,尽量多采用组合和设计模式。 |
|
返回顶楼 | |