首页 >> 读书频道 >> 电脑 >> Java 库的建立方法及其实例
 
· JSP程序员成长之路之一
· JSP程序员成长之路之二
· 一架天平和12个球
· JSP中实现全文检索
· win2k下搭建jsp环
· 缓冲技术提高JSP程序的
· JSP编程进度条设计实例
· JSP编程进度条设计实例
· JSP编程进度条设计实例
· JSP编程进度条设计实例
· JSP连接各类数据库大全
· JSP连接各类数据库大全
 
· 美容养颜手册
· 加油金顺剧情分集介绍完整
· 红楼梦:120回全本[清
· 素质教育在美国
· 全唐诗卷四十六
· 韩剧《布拉格恋人》剧情介
· 夜航船[作者:明·张岱]
· 局外人[作者:韩·可爱淘
· 现场流行病学
· 源氏物语[日本:紫式部]
· 武林寓言故事
· 2006高考录取规则
 
· (出租)中动商场部分及写
· (出租)中动动漫基地&#
· 喜剧学院
· 《善德女王》剧情介绍
· 魔女18号 剧情
· 丑女无敌剧情介绍
· 魔女幼熙剧情介绍
· 龙游天下剧情介绍
· 震撼世界的七日剧情介绍
· 静静的白桦林剧情介绍
· 心情日记—老公今天我想对
· 旗舰剧情介绍
欢迎来到月影社区!如果您觉得这里不错,请推荐给您的朋友们。月影社区:http://wf66.com/

Java 库的建立方法及其实例


查看有无更新版本

关键字:JSP 2006-9-4

 

正文:
任何一种面向对象语言都有它的库。任何一种面向对象的语言也都离不开库的支持。用我们熟悉的 面向对象语言为例子,C++有STL,Java有API函数,具体到开发工具,Visual C++提供了MFC, Borland C++提供了OWL。也有很多第三方提供的库。我们在开发应用程序的时候,也发觉我们也 许需要某些特定的库来完成特定的功能。那么,如何编写自己的库呢?
利用Java的面向对象特性,如封装,继承,和一些设计模式,我们可以用标准的方法来建立自己的 库。需要明白的一点:在你需要完成某个功能的时候,不要用专有的、特定的方法去编写代码,而 要全盘考虑,用通用的方法来完成,这样,在积累了一定数量的库以后,你就能重用这些库来完成 新的功能,而不用每回都重头编写代码。这也是面向对象语言提供给我们的好处。也可以用J2EE的 规范为例子,J2EE提供了一个CBT(Component Based Transaction),所有的组件都尊崇J2EE规范,在 CBT中运行,这样,编写开发并且重用标准的通用的组件库,可以缩短开发周期节约成本,并且可 以在任何符合J2EE规范的应用程序服务器(APPLICATION SERVER)中运行,并且可以继承,扩展已 有的组件库完成新的任务或者适应新的变化。
在本文中,我将先讨论如何建立自己的库,需要根据哪些标准,然后给出一个简单的例子。在第二 部分中,我将通过一个功能比较完善的库来做进一步的讨论。
什么是库?库是一个可以重用的组件,它采用通用的设计,完成通用的任务,可以节约开发者的时 间,缩短开发周期节约开发成本。一个设计完善的库,并不只是为了完成某一个特定的任务,而是 可以完成各种不同的任务。设计一个库是困难的。写一个算法并不难,但是设计库的时候需要一种 比较好的结构,它能够被用在各种需要的环境下,完成各种不同的任务,但是还不能影响使用它的 程序代码结构。
为什么要重用代码?重头开发一个新的软件,工作量是非常巨大的,不论你用什么工具什么语言。 而代码重用能够节约大部分时间,而把时间花在新的功能的开发上。从一定的意义上来说,写一个 新的软件是利用了现有的代码,重新拼装以实现新的功能。从另外一个角度上来讲,即使你没有打 算把你写的代码变成一个通用的库并分发给其他人使用,从设计的角度来讲,采用一种全盘的通用 的设计方法也能让你对所要完成的任务有更好的理解,并且优化你的设计过程,从而优化你的代码 结构。
采用开发库并且让别人来使用它的方式,能够帮助你在使用它的时候发现它的设计上的缺陷或者代 码中的错误,并帮助你改正它。比方说,你写了一个库让别人来使用,你不得不考虑通用的设计, 因为你并不能预见别人将在什么环境下使用和使用的目的。在其他人使用你的库的过程中,可能会 遇到一些问题,有的可能是你的文档写得不够清楚明白,有的也可能是你程序上的错误,也有可能 是使用者觉得在结构上使用起来不方便或者不正确。那么你可以继续作一些修改工作,在保持结构 和接口不变化的情况下,做一些调整。
在设计库的时候,你需要以一个使用者的眼光来看问题,考虑如何设计和实现它。你需要明白,
1、需要解决的问题是什么?需要达到一个什么目的?
2、使用者关心的问题是什么?使用者需要得到一个什么结果?
3、使用者不需要关心的问题是什么?什么细节是可以对使用者隐藏的?
下面,我们用一个简单的例子来说明如何设计和实现一个有用处的库。
设计一个网络服务程序,我们需要考虑几点:
1、监听一个端口
2、接受连接
3、读取或者写入连接的流
4、处理输入的数据,并且返回一个结果
对于我们将要实现的库来说,需要完成的是前三点,而最后一点我们留给使用者去实现,这也是使 用者需要完成和关心的地方。
库的主要类叫做Server, 测试的类叫做EchoServer. EchoServer实现了一个简单的服务,从客户端读 取数据,并且返回同样的数据。
设计原则一:封装
一个好的库必须是一个紧凑的关系紧密的整体,而不是一个分散的关系松散的对象的集合。
package是Java提供的一种类库的封装机制。一个package是一个Java类文件的集合,存放在同一个目 录中。package有专有的名字空间。
专有的名字空间的一个好处是,你不用担心名称的冲突。因为,如果你的类的名称和别人的类的名 称冲突,但是他们不在同一个package中,利用这一点可以避免名字的冲突。
每一个package都有一个字符串来代表,比如java.lang, 或者javax.swing.plaf.basic.实际上每一个类的 全名都是由package的名字加上类的名字来代表的,这样就避免了名字的冲突,比 如,java.lang.Object或者javax.swing.plaf.basic.BasicMenuBarUI.
注意,有一个特殊的package叫做default package。如果你不声明你的类属于任何一个package,那么 它就被假定属于default package.
每一个package的名字都对应一个目录。比如,java.lang.Object 存放在java/lang/Object.java中,每一 个.对应一个/. default package存放的目录是当前目录。
声明一个package.
// Server.java
package mylib;
public class Server implements Runnable
{
// ...
如果有import语句,必须放在package语句的后面。
当然你也可以引入别的package. 例如:
import mylib.Server;
// ...
Server server = new Server( portNum );
Java允许你决定package中的哪些类对外部是可见的。public类可以被包外的代码使用,而private类 则不行。
比如,让Server类能被外部的代码使用:
// Server.java
package mylib;
import java.io.*;
import java.net.*;
public class Server implements Runnable
{
如果你不想让类被外部的代码使用,可以用缺省的属性,去掉public. 例如:
// Reporter.java
package mylib;
class Reporter implements Runnable
{
设计原则二:继承
在我们的例子中,Server是主要的类。如果你看这个类的代码,就能看到,它本身其实什么也不 做。主循环用来监听连接。当连接建立以后,它把处理连接的任务交给一个叫做handleConnection() 的函数。
// subclass must supply an implementation
abstract public void handleConnection( Socket s );
因为没有实现这一函数,所以这个类被声明为abstract,使用者必须实现这个函数。
// This is called by the Server class when a connection
// comes in. "in" and "out" come from the incoming socket
// connection
public void handleConnection( Socket socket ) {
try {
InputStream in = socket.getInputStream();
OutputStream out = socket.getOutputStream();
// just copy the input to the output
while (true)
out.write( in.read() );
} catch( IOException ie ) {
System.out.println( ie );
}
}
可以说,这一继承的过程叫做定制。因为在Server类中,并没有定义该函数的动作,而是把这个定 义的过程留给使用者,让他们来完成所需要的特定的功能。
另外一个定制函数:cleanUp().
在设计类的时候,往往你能考虑到使用者需要的功能,例如上面的handleConnection().但是,也需要 考虑另外一种定制,例如在这里,在Server退出后台运行方式的时候,调用了这个cleanUp()函数, 在Server类中的实现为空,什么都不做,这把机会留给使用者,使用者可以用这个函数来做一些清 除工作,这种函数也可以称之为"钩子"。
设计原则三:调试
没有人能够做到写出一个绝对完美的程序,没有任何的错误。所以,调试是不可缺少的。有时候, 使用者可能会遇到一个问题,从而需要知道在库的代码中发生了什么问题。这个错误可能是库代码 的问题,也可能是使用者的代码在库代码中引起的问题。
如果你提供了库的源代码,使用者可以用debugger来调试错误。但是,你不能完全依赖于调试器。 在库代码中加入打印调试信息的语句,是一个好习惯。它可以帮助使用者明白,什么地方发生了错 误。
下面的例子说明了这一技术。使用者的代码使用Server.setDebugStream(),指定一个PrintStream对 象。然后,调试信息就被输出到这个流中。
// set this to a print stream if you want debug info
// sent to it; otherwise, leave it null
static private PrintStream debugStream;
// call this to send the debugging output somewhere
static public void setDebugStream( PrintStream ps ) {
debugStream = ps;
}
当使用者使用了调试的流的时候,你的库代码可以打印错误:
// send debug info to the print stream, if there is one
static public void debug( String s ) {
if (debugStream != null)
debugStream.println( s );
}
下面,来完整的看一看这个具体的例子:
EchoServer
// $Id$
import java.io.*;
import java.net.*;
import mylib.*;
public class EchoServer extends Server
{
public EchoServer( int port ) {
// The superclass knows what to do with the port number, we
// don't have to care about it
super( port );
}
// This is called by the Server class when a connection
// comes in. "in" and "out" come from the incoming socket
// connection
public void handleConnection( Socket socket ) {
try {
InputStream in = socket.getInputStream();
OutputStream out = socket.getOutputStream();
// just copy the input to the output
while (true)
out.write( in.read() );
} catch( IOException ie ) {
System.out.println( ie );
}
}
protected void cleanUp() {
System.out.println( "Cleaning up" );
}
static public void main( String args[] ) throws Exception {
// Grab the port number from the command-line
int port = Integer.parseInt( args[0] );
// Have debugging info sent to standard error stream
Server.setDebugStream( System.err );
// Create the server, and it's up and running
new EchoServer( port );
}
}
mylib.Server
// $Id$
package mylib;
import java.io.*;
import java.net.*;
abstract public class Server implements Runnable
{
// the port we'll be listening on
private int port;
// how many connections we've handled
int numConnections;
// the Reporter that's reporting on this Server
private Reporter reporter;
// set this to true to tell the thread to stop accepting
// connections
private boolean mustQuit = false;
public Server( int port ) {
// remember the port number so the thread can
// listen on it
this.port = port;
// the constructor starts a background thread
new Thread( this ).start();
// and start a reporter
reporter = new Reporter( this );
}
// this is our background thread
public void run() {
ServerSocket ss = null;
try {
// get ready to listen
ss = new ServerSocket( port );
while( !mustQuit ) {
// give out some debugging info
debug( "Listening on "+port );
// wait for an incoming connection
Socket s = ss.accept();
// record that we got another connection
numConnections++;
// more debugging info
debug( "Got connection on "+s );
// process the connection -- this is implemented
// by the subclass
handleConnection( s );
}
} catch( IOException ie ) {
debug( ie.toString() );
}
debug( "Shutting down "+ss );
cleanUp();
}
// the default implementation does nothing
abstract public void handleConnection( Socket s );
// tell the thread to stop accepting connections
public void close() {
mustQuit = true;
reporter.close();
}
// Put any last-minute clean-up stuff in here
protected void cleanUp() {
}
// everything below provides a simple debug system for
// this package
// set this to a print stream if you want debug info
// sent to it; otherwise, leave it null
static private PrintStream debugStream;
// we have two versions of this ...
static public void setDebugStream( PrintStream ps ) {
debugStream = ps;
}
// ... just for convenience
static public void setDebugStream( OutputStream out ) {
debugStream = new PrintStream( out );
}
// send debug info to the print stream, if there is one
static public void debug( String s ) {
if (debugStream != null)
debugStream.println( s );
}
}
mylib.Reporter
// $Id$
package mylib;
class Reporter implements Runnable
{
// the Server we are reporting on
private Server server;
// our background thread
private Thread thread;
// set this to true to tell the thread to stop accepting
// connections
private boolean mustQuit = false;
Reporter( Server server ) {
this.server = server;
// create a background thread
thread = new Thread( this );
thread.start();
}
public void run() {
while (!mustQuit) {
// do the reporting
Server.debug( "server has had "+server.numConnections+" connections" );
// then pause a while
try {
Thread.sleep( 5000 );
} catch( InterruptedException ie ) {}
}
}
// tell the background thread to quit
public void close() {
mustQuit = true;
}
}
下面,我们以一个具体的有实际用处的类库来进一步讨论库的设计方法。这个库是jregex. (jregex.sourceforge.net)。这是一个用Java实现的兼容Perl 5.6的正则表达式的库。有很多这样的库, 比如gnu.regexp,com.stevesoft.pat, 还有J2SE SDK 1.4中新增加的regex.为什么选用jregex呢?是因为 它是目前源代码公开的regex库中兼容Perl 5.6的正则表达式,而且刚刚更新过源代码,并且是稳定 版,另外一个就是,它的内核算法选用了NFA(Not Finite Automata)。
要了解一个包,在看源代码之前先应该看的就是它的API文档。那么,看文档的第一步应该看什么 呢?当然是树形结构。
Class Hierarchy
class java.lang.Object
class jregex.Matcher (implements jregex.MatchResult)
class jregex.Optimizer
class jregex.util.io.PathPattern
class jregex.Pattern (implements jregex.REFlags, java.io.Serializable)
class jregex.PerlSubstitution (implements jregex.Substitution)
class jregex.Replacer
class jregex.RETokenizer (implements java.util.Enumeration)
class java.lang.Throwable (implements java.io.Serializable)
class java.lang.Exception
class java.lang.RuntimeException
class java.lang.IllegalArgumentException
class jregex.PatternSyntaxException
class jregex.util.io.WildcardFilter (implements java.io.FilenameFilter)
Interface Hierarchy
interface jregex.MatchIterator
interface jregex.MatchResult
interface jregex.REFlags
interface jregex.Substitution
interface jregex.TextBuffer
interface jregex.Replacer.WriterWrap

Java 库的建立方法及其实例

[ 1 ]
Java 库的建立方法及其实例 num

打印本页 关闭

关于我们版权声明本站导航友情连结作品演示 TOP↑