﻿<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:trackback="http://madskills.com/public/xml/rss/module/trackback/" xmlns:wfw="http://wellformedweb.org/CommentAPI/" xmlns:slash="http://purl.org/rss/1.0/modules/slash/"><channel><title>BlogJava-零空间-文章分类-JAVA应用</title><link>http://www.blogjava.net/chjhai/category/10969.html</link><description>专注于java与手机领域</description><language>zh-cn</language><lastBuildDate>Mon, 12 Mar 2007 04:19:13 GMT</lastBuildDate><pubDate>Mon, 12 Mar 2007 04:19:13 GMT</pubDate><ttl>60</ttl><item><title>用AJAX+J2EE实现一个网上会议室系统 </title><link>http://www.blogjava.net/chjhai/articles/46559.html</link><dc:creator>零空间</dc:creator><author>零空间</author><pubDate>Wed, 17 May 2006 02:21:00 GMT</pubDate><guid>http://www.blogjava.net/chjhai/articles/46559.html</guid><wfw:comment>http://www.blogjava.net/chjhai/comments/46559.html</wfw:comment><comments>http://www.blogjava.net/chjhai/articles/46559.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/chjhai/comments/commentRss/46559.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/chjhai/services/trackbacks/46559.html</trackback:ping><description><![CDATA[
		<div>　　今年大家都在炒作Web2.0，其中的一门技术Ajax也是跟着火了起来，因此前面我写了一篇名为<a href="http://www.easyjf.com/html/20060417/32219102-1533704.htm?ejid=2538093638804337" target="_blank"><font color="#0000ff">《忽悠一下AJAX》</font></a>的文章，简单地分析了一下Ajax的技术的实质。虽然笔者不太喜欢跟风，但Ajax有一些地方还是比较有用的。前段时间做了EasyJF开源团队的网上会议系统，就用到了Ajax技术，下面把设计思路发出来跟大家分享一下。</div>
		<div> </div>
		<div>
				<strong>一、系统实现的功能</strong>
		</div>
		<div> </div>
		<div>　　本会议室系统主要用于EasyJF开源团队的成员网上会议使用，会议系统模拟传统的会议形式，可以同时开设多个不同主题的会议室，每个会议室需要提供访问权限控制功能，会议中能够指定会议发言模式（分为排队发言、自由发言两种），系统能自动记录每个会议室的发言信息，可以供参会人员长期查阅。<br />会议系统的用户支持游客帐号参加会议，同时也提供跟其它用户系统的接口，比如EasyJF官网中的开源论坛系统。<br />会议系统暂时使用文字聊天的方式，并提供语音及视频的接口。</div>
		<div> </div>
		<div>
				<strong>二、技术体系</strong>
				<br />
		</div>
		<div> </div>
		<div>　　服务器端使用Java语言，MVC使用EasyJWeb框架；<br />　　客户端使用AJAX技术与服务器端交互数据；<br />　　会议历史信息储存格式使用文本格式，方便系统安装运行，也便于管理。</div>
		<div> </div>
		<div>
				<strong>三、会议室服务器端设计</strong>
				<br />
		</div>
		<div> </div>
		<div>　　会议室服务器端是整个会议系统的核心部分，服务器端程序设计的好坏影响到整个系统的质量。<br />　　首先，根据会议室要实现的功能进行抽象分析。一个会议室对象，应该包括会议主题、会议简介、参会人数限制、公告、会议室类型、访问权限设定、房间密码、当前参会的人员、当前发言的人员、排队等待发言的人员等参数信息。我们把他封装一个Java对象当中。如下面的ChatRoom代码所示：<br />public class ChatRoom{<br /> private String cid;//主键<br /> private String title;//会议室主题<br /> private String intro;//会议室简介<br /> private String announce;//会议室公告<br /> private String owner;//会议室创建人<br /> private Integer maxUser;//最大在线人数<br /> private Integer intervals;//最大刷新时间间隔<br /> private String vrtype;//访问权限<br /> private String vrvalue;//访问值<br /> private Integer status;//会议室状态<br /> private Date inputTime;<br />}</div>
		<div> </div>
		<div>　　需要一个管理会议室的类，与会议有关的操作（如启动会议、关闭会议）等都直接找他。该类还应该即有自动定时检测用户在线情况（防止用户意外退出）、把内存中的会议历史发言信息保存到文本文件中等功能。这里可以考虑使用一个ChatService类提供这些功能：<br />public class ChatService implements Runnable {<br />private static final Map service=new HashMap();//会议室服务,系统中的当前会议室存放到该表集合中<br />private static final int maxServices=10;//可以同时开的最大会议室数<br />private static final SimpleDateFormat df=new SimpleDateFormat("yyyy-MM-dd");<br />private final List msgs;//会议发言信息Chat<br />private final List users;//在线用户,ChatUser<br />private final List talkers;//排队发言人数Talker<br />private final List manager;//会议室管理员<br />private Talker currentTalker;//当前发言人<br />public ChatService()<br />{<br /> this.msgs=new ArrayList();<br /> this.users=new ArrayList();<br /> this.talkers=new ArrayList();<br /> this.manager=new ArrayList();<br /> this.maxUser=1000;//最大1000人同时<br /> this.interval=1000*60*5;//5分钟以前的信息<br />}<br />}</div>
		<div> </div>
		<div>　　会议发言信息也需要封装成一个类，表示发言人、接收人、内容、发言时间、类型等，大致如下面的Chat类：<br />public class Chat  {<br />private String cid;<br />private String sender;<br />private String reciver;<br />private String content;<br />private Date vdate;<br />private Integer types;<br />private Integer status;<br />}</div>
		<div> </div>
		<div>　　还有表示参加会议的人的信息，包括参会人名称、IP地址、状态等，如下面的ChatUser类所示：<br />public class ChatUser {<br />private String ip;<br />private String port;<br />private String userName;<br />private Date lastAccessTime;<br />private Integer status;<br />}</div>
		<div> </div>
		<div>　　另外还需要一个表示当前发言人的Talker类，表示当前的发言人，发言开始时间，发言预计结束时间等。</div>
		<div>　　在服务器端的设计中，会议室信息服务器应该能以多线程的方式运行，即启动一个会议就新开一个线程，每个会议线程维护自己的会议状态，如参会人、发言人，保存会议历史发言信息以及清空内存中的数据等操作。</div>
		<div> </div>
		<div> </div>
		<div>
				<strong>四、客户端设计</strong>
		</div>
		<div> </div>
		<div>　　会议室客户端包括两个部分，一个部分是会议室的管理界面，主要包会议室的“添删改查”及“启动”或“关闭”会议服务的操作。这部分我们直接使用EasyJWeb Tools中的添删改查业务引擎AbstractCrudAction可以快速实现。界面也比较简单，直接使用EasyJWeb Tools代码生成工具引擎生成即可。会议室管理的客户端是传统的Java Web技术，因此没有什么要考虑的。<br />　　客户端的第二个部分也即会议系统的主要部分，该部分主要有两个界面，第一个页面是会议室进入的选择页面。也即把已经启动的会议室列出来，用户选择一个会议室进入，这个页面也是使用传统的Java Web技术。第二个页面是进入会议室后的主界面，这个界面是整个会议系统的主要界面，所有参与会议的操作都在这里运行的。这个界面需要不断的与服务器端交互传输数据，传输的内容包括用户的发言、其它人给用户的发言、会议室的状态等。有的传输信息需要即时响应（如用户发言），有的信息可以设置成定时响应（如会议室状态）。<br />　　Java Web程序中与服务器端交互数据主要有两种方式，一种是直接刷新页面，另外一种是使用Socket直接跟Web服务器端口通讯。由于Socket编程相对复杂，我们选择第一种直接刷新页面的方式，这种方式又可以分为几种，包括传统的Form提交，传统的自动刷新网页取得数据以及使用ActiveXObject对象(如xmlhttp)直接与服务器交互数据，也即AJAX方式。由于使用AJAX方式用户感觉不到页面在刷新，表现起来好于手动或自动刷新页面的方式，因此我们决定选择AJAX方式实现客户端与服务器端进行数据交互。</div>
		<div>　　用户发言的时候，直接使用xmlhttp对象Post数据到服务器。为了能不断接收到别人的发言信息，需要定时不断的从服务器端读取数据，因此，需要在客户端启动一个定时器，每隔一定的时候自动使用xmlhttp对象到服务器端下载别人的发言信息，并显示到会议室信息主界面中。另外还要定时刷新参会的人数、会议室当前发言人、会议室的公告等会议状态信息，这也可以通过从客户端启动一个定时器，通过xmlhttp对象与服务器交互得到。<br />　　另外还有一些操作，锁定会议室、踢人、指定发言人的发言时间、给会议室加密码等功能，也通过xmlhttp的方式与服务器传输命令实现。</div>
		<div> </div>
		<div>
				<strong>五、核心代码说明</strong>
		</div>
		<div>
				<br />
				<strong>1、服务器端核心代码</strong>
				<br />　　在EasyJF开源团队的会议系统中，由于是以EasyJF官网的论坛系统、后台管理等是集成一起的。服务器ChatService与ChatRoom共同合并到了一个ChatService.java类中，实现会议室管理及会议服务功能。ChatService类的部分主要代码如下：<br />package com.easyjf.chat.business;</div>
		<div>public class ChatService implements Runnable {<br />private static final Map service=new HashMap();//会议室服务,系统中的当前会议室存放到该表集合中<br />private static final int maxServices=10;//可以同时开的最大会议室数<br />private static final SimpleDateFormat df=new SimpleDateFormat("yyyy-MM-dd");<br />private final List msgs;//会议发言信息Chat<br />private final List users;//在线用户,ChatUser<br />private final List talkers;//排队发言人数Talker<br />private final List manager;//会议室管理员<br />private Talker currentTalker;//当前发言人<br />private String cid;//会议室id<br />private String title;//会议室主题<br />private String intro;//会议室简介<br />private String owner;//会议室创建人<br />private int maxUser;//最大在线人数<br />private int interval;//最大刷新时间间隔<br />private String vrtype;//访问权限<br />private String vrvalue;//访问值<br />private String announce;<br />private String password;//房间进入密码<br />private int status;//会议室状态<br />private String filePath;<br />//private Thread thread;<br />private boolean isStop=false;<br />public ChatService()<br />{<br /> this.msgs=new ArrayList();<br /> this.users=new ArrayList();<br /> this.talkers=new ArrayList();<br /> this.manager=new ArrayList();<br /> this.maxUser=1000;//最大1000人同时<br /> this.interval=1000*60*5;//5分钟以前的信息<br />}<br />/**<br /> * 停止所有会议室<br /> *<br /> */<br />public  static void clear()<br />{<br /> if(!service.isEmpty())<br /> {<br />  Iterator it=service.values().iterator();<br />  while(it.hasNext())<br />  {<br />   ChatService chat=(ChatService)it.next();<br />   chat.stop();<br />  }<br /> }<br />  service.clear();<br />}<br />/**<br /> * 创建一个会议室<br /> * @param name 会议室ID<br /> * @return<br /> */<br />public static ChatService create(String name)<br />{<br />ChatService ret=null;<br />if(service.containsKey(name))<br />{<br /> ChatService s=(ChatService)service.get(name);<br /> s.stop();<br /> service.remove(name);<br />}<br />if(service.size()&lt;maxServices)<br />{<br /> ret=new ChatService(); <br /> service.put(name,ret);<br />}<br />return ret;<br />}<br />/**<br /> * 停止某个会议室<br /> * @param name 会议室ID<br /> * @return<br /> */<br />public static boolean close(String name)<br />{<br /> ChatService chatRoom=ChatService.get(name);<br /> if(chatRoom!=null)<br />  {<br />  chatRoom.stop();<br />  service.remove(name);<br />  }<br /> return true;<br />}<br />/**<br /> * 获得一个会议室信息<br /> * @param name 会议室ID<br /> * @return<br /> */<br />public static ChatService get(String name)<br />{<br /> if(service.containsKey(name))return (ChatService)service.get(name);<br /> else return null;<br />}</div>
		<div>public void run() {<br /> // TODO Auto-generated method stub<br /> //this.thread=Thread.currentThread();<br /> while(!isStop)<br /> {<br /> //System.out.println("开始监控一个会议室!"+this.title);<br /> this.flash();<br /> try{<br /> Thread.sleep(5000);<br /> }<br /> catch(Exception e)<br /> {<br />  e.printStackTrace();  <br /> } <br /> }<br /> //System.out.println("结束!");<br />}<br />public void stop()<br />{<br /> this.flashAll();<br /> isStop=true;<br />}<br />//会议室中有人发言<br />public boolean talk(Chat chat)<br />{<br /> boolean ret=false;<br /> if(canTalk(chat.getSender()))<br />  {  <br />  this.msgs.add(chat);<br />      ret=true;<br />  }<br /> return ret;<br />}</div>
		<div>public boolean exit(ChatUser user)<br />{     <br />  talk(geneSystemMsg(user.getUserName()+"退出了会议室！"));<br />  return this.users.remove(user);<br />}<br />}<br />//刷新信息，保存会议信息<br />public void flash()<br />{<br /> flashChatMsg();<br /> flashChatUser();<br />}<br />}</div>
		<div> </div>
		<div> </div>
		<div>
				<strong>2、MVC处理部分的Action代码</strong>
		</div>
		<div> </div>
		<div>
				<br />　　在EasyJF的会议系统中，由于使用EasyJWeb作为MVC框架，因此处理Ajax比较简单，下面是会议室系统的核心Action主要代码。<br />package com.easyjf.chat.action;<br />public class ChatAction extends AbstractCmdAction {<br /> private ChatService chatRoom;<br /> public Object doBefore(WebForm form, Module module) {<br /> // TODO Auto-generated method stub<br />  if(chatRoom==null)chatRoom=ChatService.get((String)form.get("cid"));<br />  return super.doBefore(form, module);<br /> }<br /> public Page doInit(WebForm form, Module module) {<br />  // TODO Auto-generated method stub  <br />  return doMain(form,module);<br /> } <br /> //用户登录进入会议室<br /> public Page doMain(WebForm form, Module module) {   <br />  if(chatRoom!=null){<br />  ChatUser user=getChatUser();  <br />  if(!chatRoom.join(user))form.addResult("msg","不能加入房间，可能是权限不够！");<br />  form.addResult("chatRoom",chatRoom);<br />  form.addResult("user",user);<br />  }<br />  else<br />  {<br />   form.addResult("msg","会议未启动或者会议室不存在！");<br />  }  <br />  return module.findPage("main");<br /> } <br /> //处理用户发言信息<br /> public Page doSend(WebForm form, Module module) {  <br />  if(chatRoom==null)return new Page("err","/err.html","thml");//返回会议室不存在的错误<br />  Chat chat=(Chat)form.toPo(Chat.class);<br />  chat.setCid(chatRoom.geneId());<br />  chatRoom.talk(chat);<br />  return doRecive(form,module);<br /> } <br /> //用户接收发言信息<br /> public Page doRecive(WebForm form, Module module) {  <br />  if(chatRoom==null)return new Page("err","/err.html","thml");//返回会议室不存在的错误<br />  String lastReadId=CommUtil.null2String(form.get("lastReadId"));<br />  //System.out.println(lastReadId);<br />  form.addResult("list", chatRoom.getNewestMsg(getChatUser(),lastReadId));  <br />  return module.findPage("msgList");<br /> }<br /> //用户刷新会议状态信息<br /> public Page doLoadConfig(WebForm form, Module module) {  <br />  if(chatRoom==null)return new Page("err","/err.html","thml");//返回会议室不存在的错误  <br />  form.addResult("userList", chatRoom.getUsers());<br />  form.addResult("talkerList", chatRoom.getTalkers());<br />  return module.findPage("config");<br /> }<br /> //用户退出<br /> public Page doExit(WebForm form, Module module) {  <br />  if(chatRoom==null)return new Page("err","/err.html","thml");//返回会议室不存在的错误<br />  chatRoom.exit(getChatUser());<br />  form.addResult("msg","退出成功");<br />  ActionContext.getContext().getSession().removeAttribute("chatUser");<br />  return new Page("msg","/chat/xmlMsg.xml",Globals.PAGE_TEMPLATE_TYPE);<br /> }</div>
		<div> </div>
		<div> </div>
		<div>
				<strong>3、客户端AJAX部分核心代码</strong>
		</div>
		<div> </div>
		<div>
				<br />　　EasyJF会议系统中，服务器发送给客户端的都是格式化的xml文档数据。下面是核心的AJAX函数及发送接收会议信息的客户端代码。<br />function newXMLHttpRequest() {<br />  var xmlreq = false;<br />  if (window.XMLHttpRequest) {   <br />    xmlreq = new XMLHttpRequest();<br />  } else if (window.ActiveXObject) {    <br />    try {      <br />      xmlreq = new ActiveXObject("Msxml2.XMLHTTP");<br />    } catch (e1) {      <br />      try {       <br />        xmlreq = new ActiveXObject("Microsoft.XMLHTTP");<br />      } catch (e2) {      <br />      }<br />    }<br />  }<br />  return xmlreq;<br />}<br />//处理返回信息<br />//xmlHttp返回值,<br />//method:方法名 方法必须带一个参数如doRecive(xNode);<br />function handleAjaxResult(req,method) { <br />  return function () {  <br />    if (req.readyState == 4) {     <br />      if (req.status == 200) {<br />      // 将载有响应信息的XML传递到处理函数<br />    var objXMLDoc=new ActiveXObject("Microsoft.XMLDOM");<br />       objXMLDoc.loadXML(req.responseText);     <br />       eval("if(objXMLDoc.firstChild)"+method+"(objXMLDoc.firstChild.nextSibling);"); <br />      } else {       <br />        //alert("HTTP error: "+req.status);<br />      }<br />    }<br />  }<br />}<br />//执行客户端Ajax命令<br />//url 数据post地址<br />//postData 发送的数据包<br />//handleMethod　处理返回的方法<br />function executeAjaxCommand(url,postData,handleMethod)<br />{<br />   var req = newXMLHttpRequest(); <br />   req.onreadystatechange =handleAjaxResult(req,handleMethod);    <br />   req.open("POST", url, true); <br />   req.setRequestHeader("Content-Type","application/x-www-form-urlencoded");<br />   req.setRequestHeader("charset","utf-8");  <br />   req.send(postData);<br />}<br />//用户发言<br />unction doSend()<br />{<br />  <br />   if(!check())return false;<br />   var msg=EditForm.content.value;<br />   var reciver=EditForm.reciver.value;   <br />   var url="/chat.ejf?easyJWebCommand=send&amp;cid="+roomId+"&amp;lastReadId="+lastReadId;<br />   var postData="sender="+myName+"&amp;reciver="+reciver+"&amp;content="+msg;<br />   clearTimeout(reciveTime);<br />   executeAjaxCommand(url,postData,"recive");<br />   EditForm.content.value="";<br />}<br />//接收发言信息<br />function doRecive()<br />{   <br />   var reciver=EditForm.reciver.value;   <br />   var url="/chat.ejf?easyJWebCommand=recive&amp;cid="+roomId+"&amp;lastReadId="+lastReadId;<br />   executeAjaxCommand(url,"","recive");  <br />}<br />//处理接收到的发言信息<br />function recive(list)<br />{<br />    var id="";   <br />    for(var oNode=list.firstChild;oNode;oNode=oNode.nextSibling) // 依次分析每个节点<br /> {<br />    chatContent.innerHTML+=showMsg(oNode);<br />    id=oNode.getAttribute("cid");<br /> }<br />    if(id!="") lastReadId=id; <br />    chatContent.scrollTop=chatContent.scrollHeight;<br />    reciveTime=setTimeout("doRecive();",5000);  <br />}</div>
		<div> </div>
		<div>
				<br />
				<strong>六、系统演示</strong>
				<br />
		</div>
		<div> </div>
		<div>　　大家可以到EasyJF开源团队的官方网站看程序演示效果，地址是：</div>
		<div>
				<br />　　　<a href="http://www.easyjf.com/chatRoom.ejf?easyJWebCommand=show&amp;ejid=2538093638804337" target="_blank"><font color="#3300ff">http://www.easyjf.com/chatRoom.ejf?easyJWebCommand=show&amp;ejid=2538093638804337</font></a></div>
		<div>
				<br />
				<strong>结束语</strong>
		</div>
		<div>
				<strong>
						<br />
				</strong>　　Ajax从技术上讲主要就是javascript、dhtml、css、xmldom、xmlhttp等一些我们很早就接触了的技术。而xmldom及xmlhttp也没有什么东西，写程序的时候把参考文档打开Copy就OK，dhtml及javascript涉及的东西就多了，不能只是看参考文档，需要把他真正消化，并能灵活动用，这就需要大家都练习了。笔者建议大家不要滥用Ajax。对于高手建议多研究一些业务及系统级算法设计等，对于新手嘛，把基本的技术(客户端的包括dhtml、css、javascript、xml等，J2EE服务器端的设计模式、UML建模、Servlet、JDBC或ORM系统、XML、EJB及一些框架、工具等)学好才是硬道理。</div>
		<div> </div>
<img src ="http://www.blogjava.net/chjhai/aggbug/46559.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/chjhai/" target="_blank">零空间</a> 2006-05-17 10:21 <a href="http://www.blogjava.net/chjhai/articles/46559.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>使用JIRA搭建企业问题跟踪系统(转自Judy Shen的专栏)</title><link>http://www.blogjava.net/chjhai/articles/46440.html</link><dc:creator>零空间</dc:creator><author>零空间</author><pubDate>Tue, 16 May 2006 09:18:00 GMT</pubDate><guid>http://www.blogjava.net/chjhai/articles/46440.html</guid><wfw:comment>http://www.blogjava.net/chjhai/comments/46440.html</wfw:comment><comments>http://www.blogjava.net/chjhai/articles/46440.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/chjhai/comments/commentRss/46440.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/chjhai/services/trackbacks/46440.html</trackback:ping><description><![CDATA[&nbsp;&nbsp;&nbsp;&nbsp; 摘要: 使用																																														JIRA																																												搭建企业问题跟踪系统																																										Judy Shen						...&nbsp;&nbsp;<a href='http://www.blogjava.net/chjhai/articles/46440.html'>阅读全文</a><img src ="http://www.blogjava.net/chjhai/aggbug/46440.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/chjhai/" target="_blank">零空间</a> 2006-05-16 17:18 <a href="http://www.blogjava.net/chjhai/articles/46440.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Java编程规则</title><link>http://www.blogjava.net/chjhai/articles/45447.html</link><dc:creator>零空间</dc:creator><author>零空间</author><pubDate>Wed, 10 May 2006 06:36:00 GMT</pubDate><guid>http://www.blogjava.net/chjhai/articles/45447.html</guid><wfw:comment>http://www.blogjava.net/chjhai/comments/45447.html</wfw:comment><comments>http://www.blogjava.net/chjhai/articles/45447.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/chjhai/comments/commentRss/45447.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/chjhai/services/trackbacks/45447.html</trackback:ping><description><![CDATA[　　本附录包含了大量有用的建议，帮助大家进行低级程序设计，并提供了代码编写的一般性指导： <br /><br />(1) 类名首字母应该大写。字段、方法以及对象（句柄）的首字母应小写。对于所有标识符，其中包含的所有单词都应紧靠在一起，而且大写中间单词的首字母。例如：<br />ThisIsAClassName<br />thisIsMethodOrFieldName<br />若在定义中出现了常数初始化字符，则大写static final基本类型标识符中的所有字母。这样便可标志出它们属于编译期的常数。<br />Java包（Package）属于一种特殊情况：它们全都是小写字母，即便中间的单词亦是如此。对于域名扩展名称，如com，org，net或者edu等，全部都应小写（这也是Java 1.1和Java 1.2的区别之一）。<br /><br />(2) 为了常规用途而创建一个类时，请采取“经典形式”，并包含对下述元素的定义：<br /><br />equals()<br />hashCode()<br />toString()<br />clone()（implement Cloneable）<br />implement Serializable<br /><br />(3) 对于自己创建的每一个类，都考虑置入一个main()，其中包含了用于测试那个类的代码。为使用一个项目中的类，我们没必要删除测试代码。若进行了任何形式的改动，可方便地返回测试。这些代码也可作为如何使用类的一个示例使用。<br /><br />(4) 应将方法设计成简要的、功能性单元，用它描述和实现一个不连续的类接口部分。理想情况下，方法应简明扼要。若长度很大，可考虑通过某种方式将其分割成较短的几个方法。这样做也便于类内代码的重复使用（有些时候，方法必须非常大，但它们仍应只做同样的一件事情）。<br /><br />(5) 设计一个类时，请设身处地为客户程序员考虑一下（类的使用方法应该是非常明确的）。然后，再设身处地为管理代码的人考虑一下（预计有可能进行哪些形式的修改，想想用什么方法可把它们变得更简单）。<br /><br />(6) 使类尽可能短小精悍，而且只解决一个特定的问题。下面是对类设计的一些建议：<br />■一个复杂的开关语句：考虑采用“多形”机制<br />■数量众多的方法涉及到类型差别极大的操作：考虑用几个类来分别实现<br />■许多成员变量在特征上有很大的差别：考虑使用几个类<br /><br />(7) 让一切东西都尽可能地“私有”??private。可使库的某一部分“公共化”（一个方法、类或者一个字段等等），就永远不能把它拿出。若强行拿出，就可能破坏其他人现有的代码，使他们不得不重新编写和设计。若只公布自己必须公布的，就可放心大胆地改变其他任何东西。在多线程环境中，隐私是特别重要的一个因素??只有private字段才能在非同步使用的情况下受到保护。<br /><br />(8) 谨惕“巨大对象综合症”。对一些习惯于顺序编程思维、且初涉OOP领域的新手，往往喜欢先写一个顺序执行的程序，再把它嵌入一个或两个巨大的对象里。根据编程原理，对象表达的应该是应用程序的概念，而非应用程序本身。<br /><br />(9) 若不得已进行一些不太雅观的编程，至少应该把那些代码置于一个类的内部。<br /><br />(10) 任何时候只要发现类与类之间结合得非常紧密，就需要考虑是否采用内部类，从而改善编码及维护工作（参见第14章14.1.2小节的“用内部类改进代码”）。<br /><br />(11) 尽可能细致地加上注释，并用javadoc注释文档语法生成自己的程序文档。<br /><br />(12) 避免使用“魔术数字”，这些数字很难与代码很好地配合。如以后需要修改它，无疑会成为一场噩梦，因为根本不知道“100”到底是指“数组大小”还是“其他全然不同的东西”。所以，我们应创建一个常数，并为其使用具有说服力的描述性名称，并在整个程序中都采用常数标识符。这样可使程序更易理解以及更易维护。<br /><br />(13) 涉及构建器和异常的时候，通常希望重新丢弃在构建器中捕获的任何异常??如果它造成了那个对象的创建失败。这样一来，调用者就不会以为那个对象已正确地创建，从而盲目地继续。<br /><br />(14) 当客户程序员用完对象以后，若你的类要求进行任何清除工作，可考虑将清除代码置于一个良好定义的方法里，采用类似于cleanup()这样的名字，明确表明自己的用途。除此以外，可在类内放置一个boolean（布尔）标记，指出对象是否已被清除。在类的finalize()方法里，请确定对象已被清除，并已丢弃了从RuntimeException继承的一个类（如果还没有的话），从而指出一个编程错误。在采取象这样的方案之前，请确定finalize()能够在自己的系统中工作（可能需要调用System.runFinalizersOnExit(true)，从而确保这一行为）。<br /><br />(15) 在一个特定的作用域内，若一个对象必须清除（非由垃圾收集机制处理），请采用下述方法：初始化对象；若成功，则立即进入一个含有finally从句的try块，开始清除工作。<br /><br />(16) 若在初始化过程中需要覆盖（取消）finalize()，请记住调用super.finalize()（若Object属于我们的直接超类，则无此必要）。在对finalize()进行覆盖的过程中，对super.finalize()的调用应属于最后一个行动，而不应是第一个行动，这样可确保在需要基础类组件的时候它们依然有效。<br /><br />(17) 创建大小固定的对象集合时，请将它们传输至一个数组（若准备从一个方法里返回这个集合，更应如此操作）。这样一来，我们就可享受到数组在编译期进行类型检查的好处。此外，为使用它们，数组的接收者也许并不需要将对象“造型”到数组里。<br /><br />(18) 尽量使用interfaces，不要使用abstract类。若已知某样东西准备成为一个基础类，那么第一个选择应是将其变成一个interface（接口）。只有在不得不使用方法定义或者成员变量的时候，才需要将其变成一个abstract（抽象）类。接口主要描述了客户希望做什么事情，而一个类则致力于（或允许）具体的实施细节。<br /><br />(19) 在构建器内部，只进行那些将对象设为正确状态所需的工作。尽可能地避免调用其他方法，因为那些方法可能被其他人覆盖或取消，从而在构建过程中产生不可预知的结果（参见第7章的详细说明）。<br /><br />(20) 对象不应只是简单地容纳一些数据；它们的行为也应得到良好的定义。<br /><br />(21) 在现成类的基础上创建新类时，请首先选择“新建”或“创作”。只有自己的设计要求必须继承时，才应考虑这方面的问题。若在本来允许新建的场合使用了继承，则整个设计会变得没有必要地复杂。<br /><br />(22) 用继承及方法覆盖来表示行为间的差异，而用字段表示状态间的区别。一个非常极端的例子是通过对不同类的继承来表示颜色，这是绝对应该避免的：应直接使用一个“颜色”字段。<br /><br />(23) 为避免编程时遇到麻烦，请保证在自己类路径指到的任何地方，每个名字都仅对应一个类。否则，编译器可能先找到同名的另一个类，并报告出错消息。若怀疑自己碰到了类路径问题，请试试在类路径的每一个起点，搜索一下同名的.class文件。<br /><br />(24) 在Java 1.1 AWT中使用事件“适配器”时，特别容易碰到一个陷阱。若覆盖了某个适配器方法，同时拼写方法没有特别讲究，最后的结果就是新添加一个方法，而不是覆盖现成方法。然而，由于这样做是完全合法的，所以不会从编译器或运行期系统获得任何出错提示??只不过代码的工作就变得不正常了。<br /><br />(25) 用合理的设计方案消除“伪功能”。也就是说，假若只需要创建类的一个对象，就不要提前限制自己使用应用程序，并加上一条“只生成其中一个”注释。请考虑将其封装成一个“独生子”的形式。若在主程序里有大量散乱的代码，用于创建自己的对象，请考虑采纳一种创造性的方案，将些代码封装起来。<br /><br />(26) 警惕“分析瘫痪”。请记住，无论如何都要提前了解整个项目的状况，再去考察其中的细节。由于把握了全局，可快速认识自己未知的一些因素，防止在考察细节的时候陷入“死逻辑”中。<br /><br />(27) 警惕“过早优化”。首先让它运行起来，再考虑变得更快??但只有在自己必须这样做、而且经证实在某部分代码中的确存在一个性能瓶颈的时候，才应进行优化。除非用专门的工具分析瓶颈，否则很有可能是在浪费自己的时间。性能提升的隐含代价是自己的代码变得难于理解，而且难于维护。<br /><br />(28) 请记住，阅读代码的时间比写代码的时间多得多。思路清晰的设计可获得易于理解的程序，但注释、细致的解释以及一些示例往往具有不可估量的价值。无论对你自己，还是对后来的人，它们都是相当重要的。如对此仍有怀疑，那么请试想自己试图从联机Java文档里找出有用信息时碰到的挫折，这样或许能将你说服。<br /><br />(29) 如认为自己已进行了良好的分析、设计或者实施，那么请稍微更换一下思维角度。试试邀请一些外来人士??并不一定是专家，但可以是来自本公司其他部门的人。请他们用完全新鲜的眼光考察你的工作，看看是否能找出你一度熟视无睹的问题。采取这种方式，往往能在最适合修改的阶段找出一些关键性的问题，避免产品发行后再解决问题而造成的金钱及精力方面的损失。<br /><br />(30) 良好的设计能带来最大的回报。简言之，对于一个特定的问题，通常会花较长的时间才能找到一种最恰当的解决方案。但一旦找到了正确的方法，以后的工作就轻松多了，再也不用经历数小时、数天或者数月的痛苦挣扎。我们的努力工作会带来最大的回报（甚至无可估量）。而且由于自己倾注了大量心血，最终获得一个出色的设计方案，成功的快感也是令人心动的。坚持抵制草草完工的诱惑??那样做往往得不偿失。<br /><br />(31) 可在Web上找到大量的编程参考资源，甚至包括大量新闻组、讨论组、邮寄列表等。<br /><img src ="http://www.blogjava.net/chjhai/aggbug/45447.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/chjhai/" target="_blank">零空间</a> 2006-05-10 14:36 <a href="http://www.blogjava.net/chjhai/articles/45447.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item></channel></rss>