动态网站制作指南 [  QQ表情  ]
[ 投票调查 ]
[ 企业邮箱 ]
[ 网站空间 ]
网络编程 | 站长之家 | 网页制作 | 图形图象 | 操作系统 | 冲浪宝典 | 软件教学 | 网络办公 | 邮件系统 | 网络安全 | 认证考试 | 系统进程
ASP源码 | .Net源码 | PHP源码 | JSP源码 | JAVA源码 | CGI源码 | VB源码 | C++源码 | Delphi源码 | PB源码 | VF源码 | 汇编 | 服务器
Firefox | IE | Maxthon | 迅雷 | 电驴 | BitComet | FlashGet | QQ | QQ空间 | Vista | 输入法 | Ghost | Word | Excel | wps | Powerpoint
asp | .net | php | jsp | Sql | c# | Ajax | xml | Dreamweaver | FrontPages | Javascript | css | photoshop | fireworks | Flash | Cad | Discuz!
当前位置 > 网站建设学院 > 网络编程 > Java教程
Tag:注入,存储过程,分页,安全,优化,xmlhttp,fso,jmail,application,session,防盗链,stream,无组件,组件,md5,乱码,缓存,加密,验证码,算法,cookies,ubb,正则表达式,水印,索引,日志,压缩,base64,url重写,上传,控件,Web.config,JDBC,函数,内存,PDF,迁移,结构,破解,编译,配置,进程,分词,IIS,Apache,Tomcat,phpmyadmin,Gzip,触发器,socket
网络编程:ASP教程,ASP.NET教程,PHP教程,JSP教程,C#教程,数据库,XML教程,Ajax,Java,Perl,Shell,VB教程,Delphi,C/C++教程,软件工程,J2EE/J2ME,移动开发
文章搜索服务
邮件订阅
输入你的邮件地址,
你将不会错过任何关于:
[ Java教程 ]的信息

本月文章推荐
.JavaServer Faces (JSF) vs Stru.
.转:《学不会的JAVA,消不了的忧.
.使用DataStream 读写文件.
.如何在Web工程项目中使用Struts.
.如何设置classpath.
.WAS 5.x中数据源的配置使用及常见.
.基于MIDP1.0实现组合按键.
.查询数据库后返回Iterator.
.网页的元素含义.
.自我参考:Java学习的30个目标.
.Spring+hibernate的单元测试Junit.
.在Eclipse中创建新的重构功能.
.editplus能够编译java嘛? 如何设.
.JDK1.5使用总结 --《Java 1.5 Ti.
.Java语言编程思想面向对象逻辑思.
.基于Socket的Java网络编程集粹.
.EJB技术的体系结构(1).
.Java I/O API之性能分析 (上).
.Java的变量定义与赋值.
.String和stringBuffer类字符串的.

最大化JAVA代码的可重用性

发表日期:2008-1-5 |



——克服传统OO方法在重用方面的缺陷

摘要:不要放弃编写可重用代码的努力!本文介绍了三种对现有代码进行修改以提高其可重用性的方法。

在程序员中似乎存在着一种日益普遍的观点,认为重用只是一个神话。或许是传统的面向对象编程方法中所存在的不足增加了重用的困难。本文介绍了从另外一种不同的途径使重用成为可能的三个步骤。

第一步:将功能实现从类实例的方法中移出

由于缺乏精确性,类继续不是非常理想的代码重用机制。换句话说,假如不继续一个类的数据成员和其他的方法,那么你就无法重用这个类的某个单独的方法。这些额外的不必要的负担使方法重用的代码变得复杂。派生类对其父类的依靠性也以入了额外的复杂性:对父类的改动会对子类造成影响;当修改任意一个类的时候,我们很难记得清哪个方法被覆盖,哪个没有;而且被覆盖的方法是否会调用父类中相应的方法并不非常清楚地显现。

任何执行单一概念任务的方法应该能够成为代码用的首选而独立存在。为了达到这个目标,我们必须会到过程化的编程模式,将代码从类实例的方法中移出,形成具有全局可见性的过程。为了提高这种过程的可重用性,过程代码应该象静态的通用方法一样编写:每个过程只能使用自己的输入参数,只能调用其他全局性的过程完成其工作,不能使用任何非本地的变量。这种对外部依靠的简化降低了过程使用的复杂性,也增加了在其他地方使用此过程的可能性。当然,由于其结构通常会变得更为清楚,即使抛开重用的目的不谈我们也可以从这种代码的组织方式中受益。

在Java中,方法不能脱离类而单独存在。因此,你可以对相关的过程进行组织并使它们成为一个独立的类中的公共静态方法。例如,对于如下所示的一个类:

class Polygon{



public int getPerimeter(){…}

public boolean isConvex(){…}

public Boolean containsPoint(Point p){…}



}

可以将它改写成下面的形式:

class Polygon {



public int getPerimeter() { return pPolygon.computePerimeter(this);}

public boolean isConvex() { return pPolygon.isConvex(this);}

public boolean containsPoint() { return pPolygon.containsPoint(this, p);}



}

在此处,nPolygon应该是这个样子:

class pPolygon {

static public int computePerimeter(Polygon polygon) {...}

static public boolean isConvex(Polygon polygon) {...}

static public boolean containsPoint(Polygon polygon, Point p) {...}



从类的名字pPolygon可以看出,该类所封装的过程主要与Polygon类型的对象有关。名字前面的p表示该类的唯一目的是组织公共静态过程。在Java中,类的名字以小写字母开头不是一种标准的做法,但象pPloygon这样的类事实上并不执行普通类的功能。也就是说,它并不代表着一类对象,它只是语言本身所需要的用于代码组织的实体。

 在上面这个例子中,改动代码的总体影响是使得客户代码不必为了重用其功能而从Polygon继续。Polygon类的功能现在已经由pPolygon类以过程为单位提供。客户代码只使用自己需要的代码,无需关心自身并不需要的功能。

这并不意味着在这种新型的过程化编程模式中,类不服务于更有用的目的。恰恰相反,类执行组织和封装对象数据成员的必要工作。而且它们通过多重接口实现多态性的能力也为代码重用提供了显著的支持,这将在下一个步骤中讨论。然而,由于将功能实现包含在实例方法中无法实现理想的代码重用,所以通过类继续实现代码重用和多态性支持也不应成为最佳的技术选择。

在一本被广为阅读的书《Design Patterns》中曾简要地提及一种略有不同的技术。策略模式(Strategy Pattern)提倡将相关算法的每个成员封装在一个通用的接口下,以便于客户端代码可交换地使用其算法。由于一个算法通常被作为一个或几个独立的过程进行编码,这种封装更注重执行单独任务的过程的重用,而不是执行多种任务的、包含代码和数据的对象的重用。这一步骤体现了相同的基本思想。

然而,将一个算法封装在一个接口下意味着将算法作为实现接口的对象进行编码。这意味着我们仍然依靠于一个与所包装的对象的数据和其他方法相耦合的过程,这样便会使其复用变得复杂。此外还存在这样一个问题,每次需要使用这个算法的时候都必须实例化这些对象,这便会降低程序的性能。值得庆幸的是,设计模式提供了针对这两个问题的解决方法。可以在对策略对象进行编码时应用享元模式(Flyweight Pattern,译者注:还存在一种译法为轻量模式),这样每个对象只会存在一个被共知共享的实例(这针对程序性能的问题),而且每个共享对象在访问间隔中并不维持状态(于是对象将没有数据成员,这针对大多数的耦合问题)。由此产生的享元--策略模式非常类似于在这一步骤中所提到的将功能实现封装在全局可见的、无状态的过程中的技术。(译者注:以上这两段文字读起来可能有些晦涩难解,建议有爱好的读者参阅文中所提到《设计模式》一书,Erich Gamma等著、李英军等译、机械工业出版社出版。)

第二步:将非原始的输入参数类型改为接口类型

在面向对象编程中,代码重用的真正基础在于通过接口参数类型利用多态性,而不是通过类继续,正如Allen Holub在 “Build User Interfaces for Object-Oriented System, Part 2”中所述:

“……你应该通过对接口而不是类编程实现重用。假如一个方法的所有参数都是某个已知接口的引用,这个接口由一些你所不知道的类实现,那么这个方法就能够操作这样一些对象:当编写方法的代码时,这些对象的类甚至还不存在。从技术上讲,可重用的是方法,而不是传递给方法的对象。”

将Holub所讲的方法应用于第一步所得到的结果,只要某块功能代码能够作为一个全局可见的过程而独立存在,你就可以将其每个类类型(class-type)的输入参数改为一个接口类型,这样便能进一步提高其重用的潜力。那么,实现此接口类型的任何类的对象都可以作为参数使用,而不仅仅局限于原始类。由此,这个过程对可能存在的大量的对象类型都成为可用的。

例如,有这样一个全局可见的静态过程

static public boolean contains(Rectangle rect, int x, int y) {…}

这个方法用于检查给定的矩形是否包含某个给定的点。在这个例子中,rect参数的类型可以从Rectangle类改变为接口类型,如下所示:

static public boolean contains(Rectangular rect, int x, int y){…}

Rectangular可以是下面形式的接口:

public interface Rectangular{

       Rectangle getBounds();

}

现在,所有可以被描述为矩形的类(也就意味着实现了Rectangular接口)的对象都可以作为传递给pRectangular.contains()的rect参数。通过放宽所传递的参数类型的限制,我们使方法具有更好的可重用性。

不过,在上面这个例子中,Rectangular接口的getBounds方法返回一个Rectangle类型,你可能会怀疑使用这个接口是否具有真正的价值;换句话说,假如我们知道传入过程的对象会在被调用时返回一个Rectangle,为什么不直接传入Rectangle取代接口类型呢?不这样做的最重要原因与集合有关,假设有这样一个方法:

static public boolean areAnyOverlapping(Collection rects) {…}

这个方法的目的在于检查给定集合中的任意矩形对象是否存在重叠。那么,在方法内部遍历集合中的每个对象时,假如无法将对象造型(cast)成如Rectangular这样的接口类型,那么将如何能够访问对象的矩形区域呢?唯一的选择是将对象造型成为其特定的类型(我们直到它有一个能够返回rectangle的方法),这意味着方法必须事先知道其所要操作的是什么类型。这恰恰是这一步骤力图首先要避免的问题!

第三步:选择低耦合的输入参数接口类型

完成第二步之后,应该选择什么样的接口类型来取代给定的类型呢?答案是能够通过参数完全描述过程的需求,同时又具有最少的额外负担的接口类型。参数对象所要实现的接口越简单,其他特定类实现此接口的机会就越大——由此,其对象可以作为参数使用的类也就越多。通过下面的例子可以很轻易地看到这点:

static public boolean areOverlapping(Window window1, Window window2) {...}

这个方法用于检查两个窗口(假定是矩形窗口)是否重叠,假如这个方法只要求从参数获得两个窗口的矩形坐标,那么简化参数的类型使其能反映这个事实是一种更好的选择:

static public boolean areOverlapping(Rectangular rect1, Rectangular rect2) {...}

以上的代码假设先前的Window类型的对象同样可以实现Rectangular接口。现在对于所有的矩形对象,都可以重用第一个方法所包含的功能了。

你可能多次体验到当一个接口能够完全确定需要通过参数获哪那些内容时,会存在太多不必要的方法。在这种情况下,应该在全局命名空间中定义一个新的公共接口以供其他可能面临同一困境的方法重用。

你可能还会不止一次地发现,在确定需要通过单一过程的一个参数获取哪些内容时,最好创建一个单独的接口。你应该只为这个参数使用此接口。这通常会在你希望如同C语言中的函数指针一样使用参数的情况下出现。例如下面的过程:

static public void sort(List list, SortComparison comp) {...}

此过程使用参数所提供的比较对象comp,通过比较给定列表中的所有对象而对其进行排序,sort对comp的全部要求是调用一个单独的方法进行比较。因此,SortComparison应该是只带有一个方法的接口:

public interface SortComparison {

boolean comesBefore(Object a, Object b);

}

这个接口的唯一目的是为sort提供一个与其完成任务所需功能相联系的钩子(hook),因此SortComparison无法在其他地方重用。

结束语

以上所述的三个步骤用于现有的、按照相对传统的面向对象方法所编写的代码。这些步骤与面向对象编程技术结合就形成了一种可以运用于今后代码编写中的新方法,它可以提高代码的可重用性和内聚性,同时降低了耦合度及复杂性。

很显然,这些步骤无法运用于那些在本质上就不适合于重用的代码。这类代码通常出现在应用程序的表示层(presentation layer)。例如程序中用于创建用户界面的代码,以及将输入事件与完成实际工作的过程相联系的控制代码,都是属于那种其功能在不同的程序中差别很大的代码,这种代码的重用几乎是不可能的。


上一篇:使用MIDP2.0开发游戏(6)设计Clock 人气:418
下一篇:WebLogic UDDI Client API实例学习(一) 人气:455
浏览全部Java的内容 Dreamweaver插件下载 常用网页广告代码全集
  最新网站源码 最新软件下载
2008-9-4 LPLY CMS 网站管理系统 v5.0
2008-9-4 缤纷互动视频交友 v3.01.902
2008-9-4 ADN视频收藏专家 v3.0 bulid 080
2008-9-4 天空网络电影系统SKYUC v2.5.6 简
2008-9-4 Web Wiz Rich Text Editor(文本编
2008-9-4 幻影动漫网视频系统(Ppdong) v1.
2008-9-4 乐维电脑在线DIY配置系统
2008-9-4 老樊文章管理系统SQL版
2008-9-4 ASP.NET 2.53 缩略图水印组件源码
2008-8-23 Mini WinMount V0.4
2008-8-23 Vista优化大师3.11正式版
2008-8-23 Wine 1.13
2008-8-23 KlipFolio 5.0 Build 5899-80
2008-8-23 Windows Sysinternals Desktops
2008-8-23 OneTap Movies1.2破解版
2008-8-23 AnnotaterPDF阅读1.1.503 破解版
2008-8-23 SoundMeter分贝测量仪 v1.0汉化破
2008-8-23 iDrum音乐节拍1.0破解版
  发表评论
姓 名: 验证码:
内 容:
站长工具:网站收录查询 | Google PR查询 | ALEXA排名查询 | CSS在线编辑器 | 广告代码 | Html转换js | js/vbs加密 | md5加密 | 进制转换
实用工具:汉字翻译拼音 | 符号对照表 | 个税计算 | 经典小工具 | 汉字简繁转换 | 普通单位换算 | 公制单位换算 | 生辰老黄历 | 国内电话区号 国家代码与域名缩写 | 文字加密解密 | 健康查询 | 万年历 | 汉字横竖排版 | 手机号码查询 | 计算器 | ip搜索
业务联系 | 广告刊登 | 频道合作 | 投稿荐稿 | 联系方式 | 加入收藏 | RSS订阅
Copyright © 2000-2008 www.knowsky.com All rights reserved | 网络实名:动态网站制作指南 | 沪ICP备05001343号
ホームページ制作 不動産検索システム 求人情報
防水工事·改修工事 フットサル大会 探偵