关于作者

姓名:

性别:其他

出生日期:1982-05-01

地区:河南-郑州

联系电话:

QQ:9321434婚否:保密
用户名:kumaws
笔名:库马
地区: 河南-郑州
行业:其他

日历  

快速登录

+ 用户名:
+ 密 码:

在线留言



broland传奇

最新评论

访问统计:
文章个数:36
评论个数:0
留言条数:0




Powered by BlogDriver 2.1

II度空间

 

F o r M y s e l f~~~~~~~~~~~~~~~~~~~~~~

文章

珍惜这份情感!
当曾经已经过去,我们留下的只是回忆,不要忘记曾经的那份爱,现在我们很幸福,过去不再属于未来。 曾经的她现在已是你的回忆,不会忘记,也不能忘记,我会帮你记起她!

- 作者: 库马 2007年11月4日, 星期日 10:15  回复(0) |  引用(0) 加入博采

深沉的爱——《甜蜜蜜》

 甜蜜蜜

     故事的开端是为了生活出来赚钱的两个相逢人,一直喜欢张曼玉的女人品味和魅力,从她的眼神嘴巴脸颊都流露着成熟女人的魅力。精美的爱情总会打动人,每次看别又一番味道,从16岁看到现在,应该不下10遍。

        和很多朋友谈论过这部电影,一起回顾每个情节,每次的相恋,无论是否现在受伤,深沉的去爱吧,等待和追寻吧,不要放弃你的爱!

      我在热恋中,可我还是喜欢《甜蜜蜜》 ,想和他一块分享!

- 作者: 库马 2007年11月3日, 星期六 16:33  回复(0) |  引用(0) 加入博采

什么是JSP
一、 什么是JSP
JSP(JavaServer Pages)是由Sun Microsystems公司倡导、许多公司参与一起建立的一种动态网页技术标准,其网址为http://www.javasoft.com/products/jsp。 在传统的网页HTML文件(*htm,*.html)中加入Java程序片段(Scriptlet)和JSP标记(tag),就构成了JSP网页(*.jsp)。Web服务器在遇到访问JSP网页的请求时,首先执行其中的程序片段,然后将执行结果以HTML格式返回给客户。程序片段可以操作数据库、重新定向网页以及发送 email 等等,这就是建立动态网站所需要的功能。所有程序操作都在服务器端执行,网络上传送给客户端的仅是得到的结果,对客户浏览器的要求最低,可以实现无Plugin,无ActiveX,无Java Applet,甚至无Frame。 本文将介绍利用JSP技术开发动态网页的方法,还将简要分析JSP技术和 Microsoft 公司的 ASP 技术的不同之处。
二、 如何安装和启动
为了实验JSP技术,首先需要建立运行环境,这个过程相当简单: 1、在 http://java.sun.com/jdk/处下载JDK(Java 2 SDK、Standard Edition、v 1.2.2)。 2、在http://java.sun.com/products/jsp/处下载JSWDK(JavaServer Web Development Kit 1.0.1)。Linux用户可以在ttp://jakarta.apache.org/处下载Tomcat 3.0。 3、安装 以Windows NT环境为例,JDK的安装是首先运行下载得到的jdk1_2_2-win.exe,然后修改系统环境参数,在PATH参数中加入[x:]\jdk1.2.2\bin以及增加新的环境参数 CLASSPATH=[x:]\jdk1.2.2\lib\tools.jar,其中[x:]是安装JDK的硬盘符(c:、d: 等)。 JSWDK的安装仅需将jswdk1_0_1-win.zip带目录释放到硬盘根目录下(c:\、d:\ 等),然后就可以在硬盘上找到\jswdk-1.0.1\目录。将来如果不想保留JSWDK,删除这个目录就可以了,没有任何系统文件和注册表遗留问题。更详细的安装过程以及Solaris/Unix和Linux下JDK、Tomcat的安装可以参考下载得到的文件包中的安装说明。 4、启动 以Windows NT环境为例,在\jswdk-1.0.1\目录下执行startserver.bat,就可启动JSWDK中一个支持JSP网页技术的Web服务器。为了不与现有的Web服务器(例如IIS、PWS等)冲突,JSWDK的Web服务器使用了8080端口。 在浏览器的地址栏中键入http://localhost:8080或者http://127.0.0.1:8080后,如果能看到 JSWDK 的欢迎页就说明JSP实验环境已经建成,可进入下一步实验。 要关闭Web服务器则运行stopserver.bat。三、 JSP简单示例 JSWDK中包含的Web服务器的文档目录在缺省状态下为\jswdk-1.0.1\webpages,主文档在缺省状态下为index.html和index.jsp。也就是说访问http://localhost:8080等于访问\jswdk-1.0.1\webpages\index.html。 用文本编辑器,如Windows中的记事本(Notepad),创建一个文本文件hi.jsp,保存在\jswdk-1.0.1\webpages\目录下,其内容如下:
在浏览器的地址栏中键入http://localhost:8080/hi.jsp,JSWDK中的Web服务器会执行JSP 文件中用括起来的Java程序语句,其中out.print是将文字输出到网页,语句的作用是将Java Scriptlet中变量或表达式的值输出到网页,执行结果如图1。 图1 将变量Msg赋值为中文字符串,用输出,或者用out.print输出中文字符串,则在英文版NT4及Redhat 6.1下实验运行结果正常,而在中文NT 4.0和中文98下,则反而会出现乱码。四、 统一的网站界面 JSP支持服务器端的文件包含,即可以在一个JSP文件中插入多个其他文件,用来实现统一的网站界面。修改上述hi.jsp并另存为mypage.jsp:
用可视化HTML编辑器,例如FrontPage、Dreamweave等设计网站的框架结构,将设计好的框架结构文件分割成两个部分,上面一半保存为top.htm, 下面一半保存为bot.htm,代码如下面所示:
在浏览器的地址栏中键入http://localhost:8080/mypage.jsp,得到结果如图2。 图2 这样网站的界面就能统一起来,而设计者可以集中精力在功能模块上处理用户登录、连接数据库、发送email等等。每个JSP文件都有如下结构: 维护网站的界面也相对比较容易,只要修改top.htm和bot.htm,就能影响到所有网页。 五、 服务器参数设置 JSWDK的Web服务器参数保存在\jswdk-1.0.1\webserver.xml中,用Windows写字板打开并编辑这个文件就可以修改缺省设置值。本节内容主要针对JSWDK,Linux下Tomcat的设置方法略有不同。 JSWDK缺省的文档目录是\jswdk-1.0.1\webpages,在此目录下可以建立子目录,例如\jswdk-1.0.1\webpages\test,就能在浏览器中用http://localhost/test访问这个目录,为了使得这个子目录能执行JSP程序,还必须在webserver.xml中的节加入: 并且,还必须建立\jswdk-1.0.1\webpages\test\WEB-INF目录,并从\jswdk-1.0.1\webpages\WEB-INF目录中复制过来以下四个文件:mappings.properties、mime.properties、servlets.properties以及webapp.properties。完成这些过程,才能通知JSWDK的Web服务器执行http://localhost/test 中的JSP程序。 六、 JavaBean JSP网页吸引人的地方之一就是能结合JavaBean技术来扩充网页中程序的功能。 JavaBean是一种Java类 (class),通过封装属性和方法成为具有某种功能或者处理某个业务的对象。JavaBean被组织成为package(数据包)以便进行管理,实际上就是把一组JavaBean一起放在某某目录中,每个类的定义前加上package某某,本例中为test。目录test必须放在系统环境CLASSPATH包含的目录下,系统才能找到其中的JavaBean。JSWDK在缺省状态下将\jswdk-1.0.1\webpages\WEB-INF\jsp\beans\ 加入CLASSPATH。建立自己的JavaBean和package时,就放在这个目录中也不失为一种简易的方法。下面介绍一个简单的JavaBean框架。用文本编辑器创建一个文本文件helloWorld.java,并保存在\jswdk-1.0.1\webpages\WEB-INF\jsp\beans\test目录下,其内容如下: package test; public class helloWorld { public String name = "My first bean"; public String getHi() { return "Hello from " + name; } } helloWorld.java编辑好后,在DOS状态下,进入目录\jswdk-1.0.1\webpages\WEB-INF\jsp\beans\,用JDK的javac命令编译helloWorld.java如下: javac helloWorld.java 注意,Java是区分大小写的,在程序中,编译命令行中字母的大小写都不能写错。编译成功就表示建立了一个JavaBean。下面看如何在JSP中使用这个JavaBean。用文本编辑器创建一个文本文件hi-bean.jsp,并保存在\jswdk-1.0.1\webpages\test目录下,其内容如下:
在JSP网页中,使用 语法来创建JavaBean对象,并命名为helloBean。读者可从这个简单的例子中看出设置、获取JavaBean属性,以及调用JavaBean方法的做法。在浏览器的地址栏中键入http://localhost:8080/test/hi-bean.jsp,得到结果如图3所示。注意,如果修改和重新编译了JavaBean程序,则需要关闭和重新启动JSWDK的Web服务器以后修改的结果才会有效。如果仅仅修改JSP文件,则不用重新启动JSWDK的Web服务器. 虽然,这仅仅完成了一个非常简单的JavaBean框架,但是遵循这个框架可以设计出多种多样的JavaBean。例如,从JSP中访问数据通常就是通过JavaBean来实现的。 七、 数据库连接数据库连接对动态网站来说是最为重要的部分,Java中连接数据库的技术是JDBC(Java Database Connectivity)。很多数据库系统带有JDBC驱动程序,Java程序就通过JDBC驱动程序与数据库相连,执行查询、提取数据等等操作。Sun公司还开发了JDBC-ODBC bridge,用此技术Java程序就可以访问带有ODBC驱动程序的数据库,目前大多数数据库系统都带有ODBC驱动程序,所以Java程序能访问诸如Oracle、Sybase、MS SQL Server和MS Access等数据库。下面介绍如何用Access实现一个动态FAQ(常见问题及答案)网站。首先建立一个Access数据库faq.mdb,其中的表faqs有字段id(自动增量型,并设为主关键字)、subject(文字型,长度200)、answers(备注型)。这个表中可以存放一些编程知识的常见问题及答案,如图4。图 4 然后,在Control Panel(控制面板)的ODBC Datasource模块中加入System DSN,取名faq,并指向faq.mdb。创建一个JavaBean,名为faq.java,并保存在\jswdk-1.0.1\webpages\WEB-INF\jsp\beans\test目录下。faq.java 的内容如下: package test; import java.sql.*; public class faq { String sDBDriver = "sun.jdbc.odbc.JdbcOdbcDriver"; String sConnStr = "jdbcdbc:faq"; Connection conn = null; ResultSet rs = null; public faq() { try { Class.forName(sDBDriver); } catch(java.lang.ClassNotFoundException e) { System.err.println("faq(): " + e.getMessage()); } } public ResultSet executeQuery(String sql) { rs = null; try { conn = DriverManager.getConnection(sConnStr); Statement stmt = conn.createStatement(); rs = stmt.executeQuery(sql); } catch(SQLException ex) { System.err.println("aq.executeQuery: " + ex.getMessage()); } return rs; } } 用上一节介绍的方法编译faq.java以后,在\jswdk-1.0.1\webpages\test目录下创建JSP文件faq.jsp,其内容如下:
这是我的FAQ!
在浏览器的地址栏中键入http://localhost:8080/test/faq.jsp,faq.jsp调用JavaBean,从数据库中读出内容并输出,得到结果如图5所示. 限于篇幅,本文不能列举JSP-JavaBean-JDBC/ODBC-数据库的复杂例子,读者可以从本文最后所推荐的网址中找到并下载到数据库连接范例。 八、 技术分析 Microsoft 公司的 ASP 技术也是动态网页开发技术。JSP和ASP从形式上非常相似,ASP程序员一眼就能认出以及。但是深入探究下去会发现它们很多的差别,其中最主要的有以下三点: 1、 JSP的效率和安全性更高 ASP以源码形式存放,以解释方式运行,每次ASP网页调用都需要对源码进行解释,运行效率不高。另外,IIS的漏洞曾使得许多网站源程序大曝光,包括笔者以前用ASP开发的网站,ASP程序全部被人下载了去。 JSP在执行以前先被编译成字节码 (byte code),字节码由Java虚拟机(Java Virtual Machine)解释执行,比源码解释的效率高;服务器上还有字节码的Cache机制,能提高字节码的访问效率。第一次调用JSP网页可能稍慢,因为它被编译成Cache,以后就快得多了。同时,JSP源程序不大可能被下载,特别是JavaBean程序完全可以放到不对外的目录中。 2、 JSP的组件 (Component) 方式更方便 ASP通过COM来扩充复杂的功能,如文件上载、发送email以及将业务处理或者复杂计算分离出来成为独立可重复利用的模块。JSP通过JavaBean实现了同样的功能扩充。在开发方面,COM的开发远比JavaBean复杂和繁琐,学会ASP不难,但学会开发COM可不简单。而JavaBean就简单多了,从本文上述示例中可以看出开发JavaBean很方便。在维护方面,COM必须在服务器上注册,如果修改了COM程序,就必须重新注册,甚至必须关机和重新启动。JavaBean则不需要注册,放在CLASSPATH包含的目录中就行了。如果JavaBean进行了修改,则JSWDK和Tomcat现在还需要关闭和重新运行(但不是关机),但开发者已经许诺将在以后的版本中做到不需要关闭服务器。另外JavaBean是完全的OOP,可以针对不同的业务处理功能方便地建立一整套可重复利用的对象库,例如用户权限控制、email自动回复等等。 3、 JSP的适应平台更广 ASP目前仅适用于NT和IIS。虽然Unix下有ChiliSoft的插件来支持ASP,但是ASP本身的功能有限,必须通过ASP+COM的组合来扩充,Unix下的COM实现起来非常困难。 JSP则不同,几乎所有平台都支持Java,JSP+JavaBean可以在所有平台下通行无阻。NT下IIS通过一个插件,例如JRUN(http://www3.allaire.com/products/jrun/)或者ServletExec(http://www.newatlanta.com/),就能支持JSP。著名的Web服务器Apache已经能够支持JSP。由于Apache广泛应用在NT、Unix和Linux上,因此JSP有更广泛的运行平台。虽然现在NT操作系统占了很大的市场份额,但是在服务器方面Unix的优势仍然很大,而新崛起的Linux更是来势不小。从一个平台移植到另外一个平台,JSP和JavaBean甚至不用重新编译,因为Java字节码都是标准的与平台无关的。笔者将在NT下实验的JSP网页原封不动地拿到Linux下就运行起来了,感觉非常满意。九、 结论综上所述,JSP可谓是构建动态网站的一个利器,故推荐给读者,祝愿你们掌握JSP,开发出优秀的网站。ASP程序员也请试一下,JSP里也有session、request、response/out等对象,亲自试试看如何。 附文这里是关于JSP的重要参考资料,有兴趣的读者可以进一步阅读。 http://java.sun.com/products/jsp/faq.html http://www.esperanto.org.nz/jsp/jspfaq.html http://www.zdnet.com/pcweek/stories/news/0,4153,410709,00.html http://developer.netscape.com/viewsource/kuslich_jsp /kuslich_jsp.html http://web2.java.sun.com/products/jsp/jsp-asp.html http://www.asptoday.com/articles/19991022.htm

- 作者: 库马 2007年01月16日, 星期二 17:41  回复(0) |  引用(0) 加入博采

Wiki建站综述

wiki这个新颖的网站形式,受到众多关注。由于wiki的开放编辑,内容可以逐步积累、完善,并且知识关联可以不断更新、发展,很多站长希望能充分利用wiki的特性并做出好的网站。

本文将就wiki建站方面的需要考虑的知识做一个汇总,以期更好的普及和发展wiki应用。

目录

[隐藏]

WIKI适合做什么?

wiki是一种特别的内容管理系统,多人协作模式、内容逐步积累、网状知识链接是其鲜明特色。根据这些特点,wiki在很多应用方面都能发挥作用。wiki的知识关联特性也很适合个人笔记的资料整理。

在内容协作上,wiki非常适合做百科、专题知识库等,例如软件使用手册、旅游参考、互联网技术等。

这里给出几个成功的wiki站点,用以说明这些特点:

另外,wiki在企业中建立背景知识库是很好的方案,用于项目开发的共识沟通也很常见。

不同应用中的wiki应用考虑

wiki的特性很多,应该根据实际情况进行取舍、改造或集成,而不一定全部利用所有特性。

  • 内容协作需要参与者的共识,过分个性化的内容不利于发挥wiki的协作性。例如:个人感悟、游记、评论等内容不适合作为wiki内容协作的主题,blog等个性化应用及集成更适合此类应用。
  • wiki不是剪贴板,对于单纯网摘类的应用而言wiki的撰写和协作过于复杂,其他cms管理系统也是很好的选择。
  • wiki的内容更新并不是很快,因此不适合制作股票信息等变化太快的内容。
  • wiki是一个实用体系而非权威体系,其文章准确性难于做到非常专业。对于严谨的学术体系,封闭用户群写作有助于避免低水平参与者的干扰。

WIKI与CMS的取舍

CMS软件比较成熟,对于有强大编辑团队、有高质量文章来源的正规网站更合适;wiki则充分体现了草根互动特性,它在内容积累、知识连接方面有无可比拟的优势,但界面和管理方面却明显不成熟。

WIKI还需要BBS吗?

简单而言,bbs更适合热点话题、情感交流、灌水,同时粘贴有版权的资料一般不会受限。而wiki有一点正式发布的味道,对上述领域并不擅长,因此特定情况下可考虑wiki与bbs的搭配使用。

如何搭建一个wiki网站?

建立一个wiki网站很简单,只需要选择一个wiki程序,把它安装到服务器上即可(服务器空间可购买)。如果希望大家都能访问该网站,那么还需要购买一个域名并绑定到该服务器空间上。总体算下来,一个wiki网站每年的这些花费可以少到几百元。

目前很多wiki程序都是开源免费的。在PHPASPJAVAPython等环境下,都有现成的wiki引擎程序。由于wiki的开放特性与开源社区一脉相承,所以目前最好的wiki程序基本都运行于开源的PHP环境下。

这里对三个wiki程序做出推荐:(更多选择请参考wiki引擎专题

最后,建议大家选择一些wiki社区进行交流,以获得更多帮助。例如天下维客组织的QQ群22134343/3680101等。

wiki程序 企业用wiki程序 php的wiki程序 java的wiki程序 perl的wiki程序 asp的wiki程序
MediaWiki MoinMoin TWiki TiddlyWiki wiki程序的流行度 wiki建站综述

如何进行wiki的基础建设

让网友知道做什么

明确网站发展目标
明确目标是所有网站必须首先解决的问题,让大家知道这个目标!
网站目标分为短期目标、中长期目标。如果太远的事情看不见,那么先确定一个小的近期目标吧。随着发展再进行远期目标调整和完善。
网站目标的描述尽量具体化,避免空泛话语造成理解不同。
树立网站内容范例
在描述目标之后,最好给出网站的内容范本,使大家明白网站将会需要什么样的文章,什么样的内容是符合网站风格。
在没有内容范例的情况下,网友的贡献往往五花八门,不利于以后的统一。
建设初步的帮助系统
总体而言,wiki网站的复杂性高于blogbbs等网站,因此有必要建立帮助系统。
搭建全面的帮助系统工作量较大,建议在建站之初选择最重要的指导来制作基础帮助系统。

让大家感到贡献有意义

让目标和内容得到认可
wiki更偏重于内容建设,有价值的文章才可能得到贡献者认可。
价值较小的选题容易导致随意性书写,影响贡献积极性和网站发展方向。
合理的版权
wiki的内容来自于网友共建,私有版权将会引发争议乃至反对。
只有版权合理,wiki网站才会被网友接受。目前多数wiki网站采用开放的自由版权GFDL,例如维基百科全书天下维客等
在内容编纂中,同样要尊重他人的版权,否则可能招致恶意编辑,例如维客中国事件。
贡献不会被浪费
wiki网站采用开放性编辑,有可能好的文章被无意或故意破坏掉。这导致了一定的维护量。
网站应该做出努力,让参与者感受到所贡献内容受到关注、维护,而不会被随意破坏掉。
同时,网站需要努力来扩大影响,使参与者的贡献发挥更大影响力。

如何进行wiki的初期启动

站长带头贡献

wiki网站的内容依赖于社群合作,站长的带头贡献有助于激发其他成员的贡献热情

网站推广

搜索引擎进行网站收录、做适当的友情链接等工作会有效扩大网站的外界联系,参见网站推广条目。

降低贡献门槛

写出好文章并不是件容易的事,wiki的文章比bbs发帖更具正式性,其难度更是远超过内容转贴。很多网友在这上面望而却步。

为此,wiki网站应该想办法降低文章写作的难度。例如列出一些容易书写的条目标题,鼓励用户参与一句话修改等。工作角色的明确化、单一化都是降低入门难度的有效措施。

wiki网站的商业模式

wiki作为新的网站形式,受到众多关注,其网友自发贡献式的内容创建可能有效降低内容建设成本,因此很多人在探讨公开性wiki网站的商业前景问题。

勿庸置疑,维基百科这样大规模的网站,目前已经到了靠流量广告就能良性发展的阶段。因此,网络广告的模式是一种现实存在。如果网站的内容够丰富并引来流量,是第一种商业模式。

wiki作为辅助性手段,减轻网站其他方面的成本,也是成功的尝试。例如amazon和ebay的商品评论wiki中,让用户经验互相传播而有效降低了服务成本。这是第二种方式。

与传统业务相结合,促进现实业务的发展,这是第三种方式。例如单词魔咒网站,用互联网业务增强了用户黏性并改善了服务。

在纯互联网业务方面,单纯wiki网站的商业模式仍在继续探索之中。除了捐助、网络广告这两个形式,其他还没有更多确实的成功范例。如何开展付费知识、会员服务,如何嫁接其他有收入的业务,都在探索之中。

提醒与建议

  • 问题:wiki的文本编辑器很难用么?
  • 回答:比起所见即所得编辑器来,文本编辑器是不够方便。然而在bbs,大家并没有因为文本编辑而放弃发链接和贴图。维基百科的迅速成长,也说明文本编辑并非阻碍用户加入的重大障碍。
  • 提醒:wiki模式中有很多事情都在进行探索,某些特征是否能够实现还尚未可知。
  • 建议:“扣动扳机”,有想法就行动,实践中得来的经验远比坐而空想来的重要!
  • 提醒:用wiki建站并不轻松,基础内容建设和人气积累方面并无捷径。参见wiki建站的基础瓶颈
  • 建议:请在一个领域先做出样子。知识是相互关联的,一个专题做好后,更多内容就有了关联发展的机会。
  • 提醒:单纯复制其他网站的文章并不能成功复制其模式,比如复制中文维基百科并不能将其贡献者拉到本站来。
  • 建议:wiki站长努力思考自己网站定位和发展特色,将网站内容与服务的客户具体化。
  • 提醒:目前的wiki程序并不是很完善,很多特性不够易用,用于商业就更需要进行特性开发了。(举例而言,最流行的mediawiki的后台管理不完善,尤其是用户权限管理方面;其界面美化也需要一定工作量。)
  • 建议:wiki擅长内容建设,何妨先做内容,其后再完善细节?技术是为了应用而服务的,这个主次不能颠倒。
  • 提醒:wiki采用开放编辑,这可能导致潜在的破坏和spam行为,因此需要考虑配备人手以防止破坏。
  • 建议:尽管目前很多wiki程序的权限管理不完善,但多数情况下不推荐封闭用户群来防范。对于小的wiki站点,破坏者的捣乱没有成就感,发广告的价值也不大,因而管理工作量很小;对于大的站点,社群已经完善,就会有人手来帮助完成管理工作了。因此对这个问题不必太过担心。

- 作者: 库马 2007年01月16日, 星期二 15:05  回复(0) |  引用(0) 加入博采

什么是RSS?RSS及其发展历程
RSS及其发展历程简介 (时代营销 平文胜 2003-10-10)

  RSS是一种描述和同步网站内容的格式,是目前使用最广泛的XML应用。RSS应用在国外已经非常普遍,从个人博客(Blog)栏目、企业站点到世界级的门户都提供基于RSS的服务,如IBM公司站点的中文新闻RSS http://www.ibm.com/news/cn/zh/index.rss ,YAHOO站点的http://news.yahoo.com/rss ,微软MSDN站点的http://msdn.microsoft.com/aboutmsdn/rss.asp 等等。

  1、 RSS的历史

  那么RSS究竟代表什么呢?比较普遍的有两种说法,一种是“Rich Site Summary”或“RDF Site Summary”,另一种是“Really Simple Syndication”,之所以有这些分歧,需要从RSS发展的历史说起。

  最初的0.90版本RSS是由Netscape公司设计的,目的是用来建立一个整合了各主要新闻站点内容的门户,但是0.90版本的RSS规范过于复杂,而一个简化的RSS 0.91版本也随着Netscape公司对该项目的放弃而于2000年暂停。

  不久,一家专门从事博客写作软件开发的公司UserLand接手了RSS 0.91版本的发展,并把它作为其博客写作软件的基础功能之一继续开发,逐步推出了0.92、0.93和0.94版本。随着网络博客的流行,RSS作为一种基本的功能也被越来越多的网站和博客软件支持。

  在UserLand公司接手并不断开发RSS的同时,很多的专业人士认识到需要通过一个第三方、非商业的组织,把RSS发展成为一个通用的规范,并进一步标准化。于是2001年一个联合小组在0.90版本RSS的开发原则下,以W3C新一代的语义网技术RDF(Resource Description Framework)为基础,对RSS进行了重新定义,发布RSS1.0,并将RSS定义为“RDF Site Summary”。但是这项工作没有与UserLand公司进行有效的沟通,UserLand公司也不承认RSS 1.0的有效性,并坚持按照自己的设想进一步开发出RSS的后续版本,到2002年9月发布了最新版本RSS 2.0,UserLand公司将RSS定义为“Really Simple Syndication”。

  目前RSS已经分化为RSS 0.9x/2.0和RSS 1.0两个阵营,由于分歧的存在和RSS 0.9x/2.0的广泛应用现状,RSS 1.0还没有成为标准化组织的真正标准。

  2、 RSS目前的版本和推荐

  到目前为止,RSS共有七种版本,推荐使用的是RSS 1.0和RSS 2.0,对于一些基本的站点同步,也可以选用RSS 0.91。

  3、 RSS的语法介绍

  一个RSS文件就是一段规范的XML数据,该文件一般以rss,xml或者rdf作为后缀。下面我们选择http://msdn.microsoft.com/visualc/rss.xml中的一部分作为例子简单说(略)

  4、 RSS的联合(Syndication)和聚合(Aggregation)

  发布一个RSS文件(一般称为RSS Feed)后,这个RSS Feed中包含的信息就能直接被其他站点调用,而且由于这些数据都是标准的XML格式,所以也能在其他的终端和服务中使用,如PDA、手机、邮件列表等。而且一个网站联盟(比如专门讨论旅游的网站系列)也能通过互相调用彼此的RSS Feed,自动的显示网站联盟中其他站点上的最新信息,这就叫着RSS的联合。这种联合就导致一个站点的内容更新越及时、RSS Feed被调用的越多,该站点的知名度就会越高,从而形成一种良性循环。

  而所谓RSS聚合,就是通过软件工具的方法从网络上搜集各种RSS Feed并在一个界面中提供给读者进行阅读。这些软件可以是在线的WEB工具,如http://my.netscape.com ,http://my.userland.com , http://www.xmltree.com ,http://www.moreover.com ,http://www.oreillynet.com/meerkat 等,也可以是下载到客户端安装的工具

  5、 RSS的未来发展

  随着越来越多的站点对RSS的支持,RSS已经成为目前最成功的XML应用。RSS搭建了信息迅速传播的一个技术平台,使得每个人都成为潜在的信息提供者。相信很快我们就会看到大量基于RSS的专业门户、聚合站点和更精确的搜索引擎。

参考文献:
1、 RSS 0.9 Specification http://www.purplepages.ie/RSS/netscape/rss0.90.html
2、 RSS 1.0 Specification http://web.resource.org/rss/1.0/spec
3、 RSS 2.0 Specification http://blogs.law.harvard.edu/tech/rss

- 作者: 库马 2007年01月15日, 星期一 16:36  回复(0) |  引用(0) 加入博采

三国最背的人物---刘巴
      当年,刘备得到孔明之后,曾说过他得到孔明是「如鱼得水」,这样的君臣关系,羨煞了后世百代。
  三顾茅庐的传奇,世人已经熟到不能再熟。但是,如果以为诸葛亮是刘备寻访贤才的过程中,最为辛苦的一个,那你就错了。
  另一位奇才,追他追得更辛苦,刘备追遍了荊州益州,差点要杀到交趾去;追他的过程中,有时高兴得要开宴会,有时气得想干脆把他砍死算了。
  而且,追到孔明之后,随便刘备爱怎么睡就怎么睡,(三国的君臣常同眠以增进感情,这里所说的睡就是睡的意思,不要想太多!)这个人身在蜀营,还是冷若冰霜,好像蜀国的人都欠他一样。
  他就是超可爱的刘巴。
  刘巴,字子彻,零陵烝阳(今湖南邵东)人。祖父刘曜,苍梧太守。父刘祥,江夏太守、荡寇将军。公元l90年,刘巴祸避零陵,为郡主记主薄。公元208年,曹操南下荆州,刘巴北上投奔曹操。赤壁战后,奉曹操之命回江南招降。刘备深恨刘巴。诸葛亮劝刘巴留下,刘巴不从。因无法复命曹操,刘巴便南下交州,改姓张,辗转进入益州,投刘璋麾下。公元211年,刘备取益州,刘巴归附备,为左将军西曹掾。刘备称帝的第二年,刘巴病逝。
  此人的才干,连诸葛亮都自叹不如,挖角最力的也是诸葛亮。为了把他请出來,刘备阵营几乎是全部动员,这位架子奇大的刘巴,何许人也?
  刘巴字子初,是荊州世家名人,少年时就很有才赶,不过却是打从他出名开始,就以「讨厌刘备」出名。偏偏他跟刘备有缘到了极点,不管他怎么闪,都会遇到刘备。
  他十八岁时,在荊州担任郡署戶曹吏主记主簿。当时刘备正好来荊州投奔刘表。
  刘巴何时开始讨厌刘备,我们不知道。只知道这时他已经十分有名气,刘备叫刘表的甥儿周不疑去向他求学,刘巴一听是刘备介紹的,拼命推辞,说自己承当不起,大大谦虚了一番。本來这只能证明他很谦虚,不能证明他讨厌刘备,但是不久之后,刘备就发现原來他真的是讨厌自己的。
  在赤壁之战前夕,刘备被曹操打得落花流水,开始逃难,荊州的士族都跟著刘备走,只有刘巴一个人往北上,去找曹操。这下可表明他宁愿去当汉奸(汉朝的奸臣)也不要跟着刘备。
  曹操对他的投奔又惊又喜,任命他做掾(助理),后來曹操叫他去招抚长沙、零陵等地,这是委以极大的重任。刘巴說:「我不去。」曹操很奇怪,我要重用你,你居然不肯?当然就问原因了。刘巴臭着脸說:「刘备在荊州,我不要去!」原來长沙等地就在荊州以南。
  曹操似乎没有听懂這句话的意义,笑着说:「安啦!万一你遇到刘备,我派六军去保护你!」
  「你说的喔!」有了这句保证,刘巴才上路了。
  想不到,他真的很衰,赤壁之战曹操惨败,诸葛亮指导刘备的战略就是去夺长沙、零陵等郡。
  刘备入主零陵,听说刘巴也在这里,非常地高兴。神经少一条的刘备还以为上次他沒跟自己南下,是被曹操抓去的关系。当刘备很热情地准备去找刘巴敘敘旧,才发现刘巴逃走了,而且逃得很远,逃到交趾(越南)。
  刘备再怎么迟钝,也终于发现人家真的不想理自己。贤才是都有点架子没错,但是当初他去三顾茅庐时,孔明虽然也躲了他几次,至少沒有逃走啊!(亮:「我是來不及跑。」)刘备觉得很沒面子,好像受到蛮大的伤害。
  如果他知道刘巴有多讨厌他,他可能会更伤心。刘巴逃到越南还不夠,怕刘备通过渠道找到他,刘巴还改名换姓。
  老天好像有意跟刘巴闹,逃到交趾改姓张的刘巴,在交趾的太守士燮手下做事,士燮是拥吴派,也是三国时代少数沒有卷入斗争的领导者。或许是刘巴給他的意见与他的作风不合,兩人处得不好,刘巴便离开了。经由牂牁道时,被益州郡守拘留,(我猜是他报假名,跟证件不合之类的问题)差点要被杀掉。(注:这个益州郡,与益州沒有关系,是在云南省。)所幸太守的主簿觉得刘巴似乎是个不简单的人物(不愧是三国时代,乡下地方的一个科長都有水镜先生的识人功力),便將他送去见见益州牧刘璋。
  熟悉三国史的人大概都已经知道将会发生什么事了。
  刘璋本來是亲曹派,派张松去对曹操表明态度。不料因为张松其貌不扬,曹操對他冷冷淡淡,憋了一肚子气回來的张松便劝刘璋和刘备合起來对付曹操。刘璋沒什么主见,也就同意了。(曹操正值赤壁战败,莫名其妙又少了个盟友,真是,人在走霉的时候,什么都不顺......)
  这时刘巴被抓到刘璋面前,刘璋以前就听过他的大名,大喜过望,马上问他对自己有什么好的意见?刘巴只给他一个意见:「不要接纳刘备。」
  刘璋不听,益州果然被刘备并吞。刘巴要再度展开他的「远离刘备之旅」,却被堵住,刘备这回卯起來不让他跑了。孔明写信給刘巴说:「你躲不掉的!天命如此,刘备就是你的真命天子,认命吧!给我出來!」刘巴回信说:「我是替刘璋办事的,事情沒办好,你应该放我回家才对,讲那个什么话!」
  总之,孔明死要活要,还是把刘巴要出來了。
  刘巴大概是放弃挣扎,只好答应为刘备效命。但是「你可以得到我的身体,不能得到我的心」,刘巴还是继续讨厌刘备。
  所谓「嫌乌及屋」,他对张飞、关羽当然也沒有好脸色。那个跟他老哥一样少了一根神经的张飞,居然还兴沖沖地跑到刘巴家睡觉。可能是听说刘巴讨厌刘备,张飞对他很好奇吧?也可能张飞还说过:「他的假名也姓张,我想他可能比较喜欢我!」之类很得意的话,也想体验一下大哥跟孔明同榻而寢、如鱼得水的感觉,便也去跟刘巴挤同一张床。
  刘巴沒想到除了帮刘备处理公事之外,还要陪他老弟睡......(我想这个谁都想不到的),睡就让他睡,我不讲话可以吧?张飞在刘巴家赖了一整天,东问西问,刘巴都沒开口吐出一个字,(可能会是不好听的字),张飞终于发现(你早在进门到他的脸见色就该发现!)刘巴不欢迎自己(正确地說是很讨厌!)。张飞气得哇哇叫,孔明赶快居中调解,刘巴还是爱理不理地说:「我干嘛要理他?」(对啊!张飞你没事去別人家睡觉干什么?)
  最好笑的是这件事居然连吴国都知道了,吴国君臣在东家长西家短时(门外挂着「战略研讨中心」的牌子),聊到这事,张昭說:「刘巴实在是很不上道,对张飞这么沒礼貌。」孙权说:「刘巴就是这样嘛,高人都是有架子的。」(实在是有够没意义的对話,更无聊的是写史的人还把它記下來......不过,呵呵,我喜欢,可爱的裴松之。)
  刘巴虽然很拽,却有拽的本钱,在刘备攻取益州之后,国库空空,刘备十分忧心。刘巴说:「小事一件,三个动作搞定:一、铸值百钱的铜板通行;二、统一全国物价;三、实行公卖制度。」真不是盖的,数月之间,府库充实。
  孔明要他真是要得太漂亮了!
  这件事上面,就可以看出刘巴的能力实在罕见,但是他的态度非常被动,事情不塞給他,他绝不会抢着做。想也知道,他本來就是被逼着帮刘备的,当然不会追求表现。蜀国建国之后,诏命公文什么的都是刘巴写的,国号年号也都是他定的(好在他沒有公报私仇,把蜀国取名为「输国」,年號章武取為「章螂」),但他实在太不愿意被后人注意到他的存在(备:「当我的手下真的有這么丟脸吗?!」),因此,关于他的记载确实很少。
  刘巴在章武二年去世,时年只有三十九岁。总计花了十三年(生命中三分之一的时光)躲刘备,最后八年才认命。死后的他,总算可以摆脱刘备。
  然而,他在天堂只清静了不到一天(天上一日,人間一年),刘备就跟來了。没错,刘巴去世的第二年,刘备也死了!
  上穷碧落下黃泉,兩处茫茫皆撞见。他们真是有缘啊!

- 作者: 库马 2007年01月11日, 星期四 16:52  回复(0) |  引用(0) 加入博采

.net中 struct与class的区别
类与结构的差别

如何选择结构还是类
一.类与结构的示例比较:
结构示例:
public struct Person

{
string Name;
int height;
int weight
public bool overWeight()
{
//implement something
}
}
类示例:
public class TestTime
{
int hours;
int minutes;
int seconds;

public void passtime()
{
//implementation of behavior
}
}
调用过程:
public class Test
{
public static ovid Main
{
Person Myperson=new Person //声明结构
TestTime Mytime=New TestTime //声明类
}
}
从上面的例子中我们可以看到,类的声明和结构的声明非常类似,只是限定符后面是 struct 还是 class 的区别,而且使用时,定义新的结构和定义新的类的方法也非常类似。那么类和结构的具体区别是什么呢?

二 .类与结构的差别
1. 值类型与引用类型
结构是值类型:值类型在堆栈上分配地址,所有的基类型都是结构类型,例如:int 对应System.int32 结构,string 对应 system.string 结构,通过使用结构可以创建更多的值类型
类是引用类型:引用类型在堆上分配地址

堆栈的执行效率要比堆的执行效率高,可是堆栈的资源有限,不适合处理大的逻辑复杂的对象。所以结构处理作为基类型对待的小对象,而类处理某个商业逻辑

因为结构是值类型所以结构之间的赋值可以创建新的结构,而类是引用类型,类之间的赋值只是复制引用
注:
1.虽然结构与类的类型不一样,可是他们的基类型都是对象(object),c#中所有类型的基类型都是object
2.虽然结构的初始化也使用了New 操作符可是结构对象依然分配在堆栈上而不是堆上,如果不使用“新建”(new),那么在初始化所有字段之前,字段将保持未赋值状态,且对象不可用
2.继承性
结构:不能从另外一个结构或者类继承,本身也不能被继承,虽然结构没有明确的用sealed声明,可是结构是隐式的sealed .
类:完全可扩展的,除非显示的声明sealed 否则类可以继承其他类和接口,自身也能被继承
注:虽然结构不能被继承可是结构能够继承接口,方法和类继承接口一样
例如:结构实现接口
interface IImage
{
void Paint();
}
struct Picture : IImage
{
public void Paint()
{
// painting code goes here
}
private int x, y, z; // other struct members
}
3.内部结构:
结构:
没有默认的构造函数,但是可以添加构造函数
没有析构函数
没有 abstract 和 sealed(因为不能继承)
不能有protected 修饰符
可以不使用new 初始化
在结构中初始化实例字段是错误的
类:
有默认的构造函数
有析构函数
可以使用 abstract 和 sealed
有protected 修饰符
必须使用new 初始化

三.如何选择结构还是类
讨论了结构与类的相同之处和差别之后,下面讨论如何选择使用结构还是类:
1.堆栈的空间有限,对于大量的逻辑的对象,创建类要比创建结构好一些
2. 结构表示如点、矩形和颜色这样的轻量对象,例如,如果声明一个含有 1000 个点对象的数组,则将为引用每个对象分配附加的内存。在此情况下,结构的成本较低。
3. 在表现抽象和多级别的对象层次时,类是最好的选择
4. 大多数情况下该类型只是一些数据时,结构时最佳的选择

- 作者: 库马 2007年01月7日, 星期日 14:42  回复(0) |  引用(0) 加入博采

C++的static关键字
  C++的static有两种用法:面向过程程序设计中的static和面向对象程序设计中的static。前者应用于普通变量和函数,不涉及类;后者主要说明static在类中的作用。

一、面向过程设计中的static

1、静态全局变量

在全局变量前,加上关键字static,该变量就被定义成为一个静态全局变量。我们先举一个静态全局变量的例子,如下:

//Example 1
#include <iostream.h>
void fn();
static int n; //定义静态全局变量
void main()
{
	n=20;
	cout<<n<<endl;
	fn();
}

void fn()
{
	n++;
	cout<<n<<endl;
}
静态全局变量有以下特点:
  • 该变量在全局数据区分配内存;
  • 未经初始化的静态全局变量会被程序自动初始化为0(自动变量的值是随机的,除非它被显式初始化);
  • 静态全局变量在声明它的整个文件都是可见的,而在文件之外是不可见的; 
静态变量都在全局数据区分配内存,包括后面将要提到的静态局部变量。对于一个完整的程序,在内存中的分布情况如下图:
 
代码区
全局数据区
堆区
栈区

  一般程序的由new产生的动态数据存放在堆区,函数内部的自动变量存放在栈区。自动变量一般会随着函数的退出而释放空间,静态数据(即使是函数内部的静态局部变量)也存放在全局数据区。全局数据区的数据并不会因为函数的退出而释放空间。细心的读者可能会发现,Example 1中的代码中将

	static int n; //定义静态全局变量
改为
	int n; //定义全局变量
程序照样正常运行。
的确,定义全局变量就可以实现变量在文件中的共享,但定义静态全局变量还有以下好处:
  • 静态全局变量不能被其它文件所用;
  • 其它文件中可以定义相同名字的变量,不会发生冲突;

您可以将上述示例代码改为如下:

//Example 2
//File1
#include <iostream.h>
void fn();
static int n; //定义静态全局变量
void main()
{
	n=20;
	cout<<n<<endl;
	fn();
}

//File2
#include <iostream.h>
extern int n;
void fn()
{
	n++;
	cout<<n<<endl;
}
编译并运行Example 2,您就会发现上述代码可以分别通过编译,但运行时出现错误。试着将
static int n; //定义静态全局变量
改为
int n; //定义全局变量
再次编译运行程序,细心体会全局变量和静态全局变量的区别。

2、静态局部变量

在局部变量前,加上关键字static,该变量就被定义成为一个静态局部变量。

我们先举一个静态局部变量的例子,如下:

//Example 3
#include <iostream.h>
void fn();
void main()
{
	fn();
	fn();
	fn();
}
void fn()
{
	static n=10;
	cout<<n<<endl;
	n++;
}
  通常,在函数体内定义了一个变量,每当程序运行到该语句时都会给该局部变量分配栈内存。但随着程序退出函数体,系统就会收回栈内存,局部变量也相应失效。
  但有时候我们需要在两次调用之间对变量的值进行保存。通常的想法是定义一个全局变量来实现。但这样一来,变量已经不再属于函数本身了,不再仅受函数的控制,给程序的维护带来不便。
  静态局部变量正好可以解决这个问题。静态局部变量保存在全局数据区,而不是保存在栈中,每次的值保持到下一次调用,直到下次赋新值。

静态局部变量有以下特点:

  • 该变量在全局数据区分配内存;
  • 静态局部变量在程序执行到该对象的声明处时被首次初始化,即以后的函数调用不再进行初始化;
  • 静态局部变量一般在声明处初始化,如果没有显式初始化,会被程序自动初始化为0;
  • 它始终驻留在全局数据区,直到程序运行结束。但其作用域为局部作用域,当定义它的函数或语句块结束时,其作用域随之结束;

3、静态函数

  在函数的返回类型前加上static关键字,函数即被定义为静态函数。静态函数与普通函数不同,它只能在声明它的文件当中可见,不能被其它文件使用。

静态函数的例子:

//Example 4
#include <iostream.h>
static void fn();//声明静态函数
void main()
{
	fn();
}
void fn()//定义静态函数
{
	int n=10;
	cout<<n<<endl;
}
定义静态函数的好处:
  • 静态函数不能被其它文件所用;
  • 其它文件中可以定义相同名字的函数,不会发生冲突;

二、面向对象的static关键字(类中的static关键字)

1、静态数据成员

在类内数据成员的声明前加上关键字static,该数据成员就是类内的静态数据成员。先举一个静态数据成员的例子。

//Example 5
#include <iostream.h>
class Myclass
{
public:
	Myclass(int a,int b,int c);
	void GetSum();
private:
	int a,b,c;
	static int Sum;//声明静态数据成员
};
int Myclass::Sum=0;//定义并初始化静态数据成员

Myclass::Myclass(int a,int b,int c)
{
	this->a=a;
	this->b=b;
	this->c=c;
	Sum+=a+b+c;
}

void Myclass::GetSum()
{
	cout<<"Sum="<<Sum<<endl;
}

void main()
{
	Myclass M(1,2,3);
	M.GetSum();
	Myclass N(4,5,6);
	N.GetSum();
	M.GetSum();

}
可以看出,静态数据成员有以下特点:
  • 对于非静态数据成员,每个类对象都有自己的拷贝。而静态数据成员被当作是类的成员。无论这个类的对象被定义了多少个,静态数据成员在程序中也只有一份拷贝,由该类型的所有对象共享访问。也就是说,静态数据成员是该类的所有对象所共有的。对该类的多个对象来说,静态数据成员只分配一次内存,供所有对象共用。所以,静态数据成员的值对每个对象都是一样的,它的值可以更新;
  • 静态数据成员存储在全局数据区。静态数据成员定义时要分配空间,所以不能在类声明中定义。在Example 5中,语句int Myclass::Sum=0;是定义静态数据成员;
  • 静态数据成员和普通数据成员一样遵从public,protected,private访问规则;
  • 因为静态数据成员在全局数据区分配内存,属于本类的所有对象共享,所以,它不属于特定的类对象,在没有产生类对象时其作用域就可见,即在没有产生类的实例时,我们就可以操作它;
  • 静态数据成员初始化与一般数据成员初始化不同。静态数据成员初始化的格式为:
    <数据类型><类名>::<静态数据成员名>=<值>
  • 类的静态数据成员有两种访问形式:
    <类对象名>.<静态数据成员名> 或 <类类型名>::<静态数据成员名>
    如果静态数据成员的访问权限允许的话(即public的成员),可在程序中,按上述格式来引用静态数据成员 ;
  • 静态数据成员主要用在各个对象都有相同的某项属性的时候。比如对于一个存款类,每个实例的利息都是相同的。所以,应该把利息设为存款类的静态数据成员。这有两个好处,第一,不管定义多少个存款类对象,利息数据成员都共享分配在全局数据区的内存,所以节省存储空间。第二,一旦利息需要改变时,只要改变一次,则所有存款类对象的利息全改变过来了;
  • 同全局变量相比,使用静态数据成员有两个优势:
  1. 静态数据成员没有进入程序的全局名字空间,因此不存在与程序中其它全局名字冲突的可能性;
  2. 可以实现信息隐藏。静态数据成员可以是private成员,而全局变量不能;
2、静态成员函数

  与静态数据成员一样,我们也可以创建一个静态成员函数,它为类的全部服务而不是为某一个类的具体对象服务。静态成员函数与静态数据成员一样,都是类的内部实现,属于类定义的一部分。普通的成员函数一般都隐含了一个this指针,this指针指向类的对象本身,因为普通成员函数总是具体的属于某个类的具体对象的。通常情况下,this是缺省的。如函数fn()实际上是this->fn()。但是与普通函数相比,静态成员函数由于不是与任何的对象相联系,因此它不具有this指针。从这个意义上讲,它无法访问属于类对象的非静态数据成员,也无法访问非静态成员函数,它只能调用其余的静态成员函数。下面举个静态成员函数的例子。

//Example 6
#include <iostream.h>
class Myclass
{
public:
	Myclass(int a,int b,int c);
	static void GetSum();/声明静态成员函数
private:
	int a,b,c;
	static int Sum;//声明静态数据成员
};
int Myclass::Sum=0;//定义并初始化静态数据成员

Myclass::Myclass(int a,int b,int c)
{
	this->a=a;
	this->b=b;
	this->c=c;
	Sum+=a+b+c; //非静态成员函数可以访问静态数据成员
}

void Myclass::GetSum() //静态成员函数的实现
{
//	cout<<a<<endl; //错误代码,a是非静态数据成员
	cout<<"Sum="<<Sum<<endl;
}

void main()
{
	Myclass M(1,2,3);
	M.GetSum();
	Myclass N(4,5,6);
	N.GetSum();
	Myclass::GetSum();
}

关于静态成员函数,可以总结为以下几点:

  • 出现在类体外的函数定义不能指定关键字static;
  • 静态成员之间可以相互访问,包括静态成员函数访问静态数据成员和访问静态成员函数;
  • 非静态成员函数可以任意地访问静态成员函数和静态数据成员;
  • 静态成员函数不能访问非静态成员函数和非静态数据成员;
  • 由于没有this指针的额外开销,因此静态成员函数与类的全局函数相比速度上会有少许的增长;
  • 调用静态成员函数,可以用成员访问操作符(.)和(->)为一个类的对象或指向类对象的指针调用静态成员函数,也可以直接使用如下格式:
    <类名>::<静态成员函数名>(<参数表>)
    调用类的静态成员函数

- 作者: 库马 2006年12月11日, 星期一 20:40  回复(0) |  引用(0) 加入博采

泛型算法
前言
  永远记住,编写代码的宗旨在于简单明了,不要使用语言中的冷僻特性,耍小聪明,重要的是编写你理解的代码,理解你编写的代码,这样你可能会做的更好。                   --- Herb Sutter

  1998年,国际C++标准正式通过,标准化对C++最重要的贡献是:对"强大的抽象概念"给于更有力的支持,以降低软件的复杂度,C++提供了二种功能强大的抽象方法:面向对象编程与泛型编程。面向对象编程大家一定很熟悉了,这里就不再哆嗦了。提到泛型编程(Generic Programming),有的人可能还不太熟悉,但是提到STL,你就一定会有所耳闻了。STL(Standard Template Library,标准模板库) 其实就是泛型编程的实现品,STL是由Alexander Stepanov(STL之父)、David R Musser和Meng Lee三位大师共同发展,于1994年被纳入C++标准程序库。STL虽然加入C++标准库的时间相对较晚,但它却是C++标准程序库中最具革命性的部分,同时也是C++标准程序库中最重要的组成部分。由于新的C++标准库中几乎每一样东西都是由模板(Template)构成的,当然,STL也不会例外。所以,在这里有必要先概要说明一下模板的有关概念。

模板概念
  通过使用模板可以使程序具有更好的代码重用性。记住,模板是对源代码进行重用,而不是通过继承和组合重用对象代码,当用户使用模板时,参数由编译器来替换。模板由类模板和函数模板二部分组成,以所处理的数据类型的说明作为参数的类就叫类模板,而以所处理的数据类型的说明作为参数的函数叫做函数模板。模板参数可以由类型参数或非类型参数组成,类型参数可用class和typename关键字来指明,二者的意义相同,都表示后面的参数名代表一个潜在的内置或用户定义的类型,非类型参数由一个普通参数声明构成。下面是类模板和函数模板的简单用法:

template<class T1, int Size>
class Queue         // 类模板,其中T1为类型参数,Size为非类型参数
{
public
    explicit Queue():size_(Size){};         // 显式构造,避免隐式转换
    ……
    template<class T2> void assign(T2 first,T2 last);   // 内嵌函数模板
private:
    T* temp_;
    int size_;
}
    // 类模板中内嵌函数模板Compare的外围实现(如在Queue类外实现)
    template<class T1,int Size> template<class T2>
    void Queue<T1,Size>::assign (T2 first,T2 last) {};

    // 模板的使用方法
    int ia[4] = {0,1,2,3};
    Queue<int, sizeof(ia)/sizeof(int)> qi;
    qi.assign(ai,ai+4);

泛型编程
  泛型编程和面向对象编程不同,它并不要求你通过额外的间接层来调用函数,它让你编写完全一般化并可重复使用的算法,其效率与针对某特定数据类型而设计的算法相同。泛型编程的代表作品STL是一种高效、泛型、可交互操作的软件组件。所谓泛型(Genericity),是指具有在多种数据类型上皆可操作的含意,与模板有些相似。STL巨大,而且可以扩充,它包含很多计算机基本算法和数据结构,而且将算法与数据结构完全分离,其中算法是泛型的,不与任何特定数据结构或对象类型系在一起。STL以迭代器(Iterators)和容器(Containers)为基础,是一种泛型算法(Generic Algorithms)库,容器的存在使这些算法有东西可以操作。STL包含各种泛型算法(algorithms)、泛型指针(iterators)、泛型容器(containers)以及函数对象(function objects)。STL并非只是一些有用组件的集合,它是描述软件组件抽象需求条件的一个正规而有条理的架构。
  迭代器(Iterators)是STL的核心,它们是泛型指针,是一种指向其他对象(objects)的对象,迭代器能够遍历由对象所形成的区间 (range)。迭代器让我们得以将容器(containers)与作用其上的算法(algorithms)分离,大多数的算法自身并不直接操作于容器上,而是操作于迭代器所形成的区间中。迭代器一般分为五种:Input Iterator、Output Iterator、Forward Iterator、Bidirections Iterator和Random Access Iterator。Input Iterator就象只从输入区间中读取数据一样,具有只读性,属于单向移动,如STL中的istream_iterator。Output Iterator刚好相反,只写出数据到输出区间中,具有只写性,属于单向移动,如STL中的ostream_iterator。Forward Iterator也属于单向移动,但不同之处是它同时具有数据读、写性。Bidirections Iterator如名称暗示,支持双向移动,不但可以累加(++)取得下一个元素,而且可以递减(--)取前一个元素,支持读、写性。Random Access Iterator功能最强,除了以上各迭代器的功能外,还支持随机元素访问(p+=n),下标(p[n])、相减(p1-p2)及前后次序关系 (p1<p2)等。Input Iterator和Output Iterator属于同等最弱的二种迭代器,Forward Iterator是前二者功能的强化(refinement),Bidirections Iterator又是Forward Iterator迭代器的强化,最后Random Access Iterator又是Bidirections Iterator迭代器的强化。如下简单示例展示Input Iterator、Forward Iterator、Bidirections Iterator和Radom Access Iterator迭代器的功能(其中input_iterator_tag等带tag字符串为各不同迭代器的专属标识):
1、InputIterator

    template<class InputIterator, class Distance>
    void advance(InputIterator& i, Distance n, input_iterator_tag)
    {
        for(; n>0; --n,++i){}       // InputIterator具有++性
    }

2、ForwardIterator

    template<class ForwardIterator, class Distance>
    void advance(ForwardIterator& i, Distance n,forward_iterator_tag)
    {
        advance(i, n, input_iterator_tag());
    }

3、BidirectionalIterator

    template<class BidirectionalIterator, class Distance>
    void advance(BidirectionalIterator& i, Distance n, bidirectional_iterator_tag)
    {
        if(n>=0)                 // 具有++、--性
          for(; n>0; --n,++i){}
        else
          for(; n>0; ++n,--i){}
    }

4、RandomAccessIterator

    template<class RandomAccessIterator, class Distance>
    void advance(RandomAccessIterator& i, Distance n, random_access_iterator_tag)
    {
        i += n;                 // 具有++、--、+=等性
    }

  函数对象(Function object)也称仿函数(Functor),是一种能以一般函数调用语法来调用的对象,函数指针(Function pointer)是一种函数对象,所有具有operator()操作符重载的成员函数也是函数对象。函数对象一般分为无参函数(Generator),单参函数(Unary Function)和双参函数(Binary Function)三种形式,它们分别能以f()、f(x)和f(x,y)的形式被调用,STL定义的其他所有函数对象都是这三种概念的强化。如下简单示例展示几种形式的实现:

1、无参(Generator)形式

    struct counter
    {
        typedef int result_type;
        counter(result_type init=0):n(init){}
        result_type operator() { return n++;}
        result_type n;
    }

2、单参(Unary Function)形式

    template<class Number> struct even     // 函数对象even,找出第一个偶数
    {
        bool operator()(Number x) const {return (x&1) == 0;}
    }
    // 使用算法find_if在区间A到A+N中找到满足函数对象even的元素
    int A[] = {1,0,3,4};
    const int N=sizeof(A)/sizeof(int);
    find_if(A,A+N, even<int>());

3、双参(Binary Function)形式

    struct ltstr
    {
        bool operator()(const char* s1, const char* s2) const
        { return strcmp(s1<s2) < 0;}
    };
    // 使用函数对象ltstr,输出set容器中A和B的并集
    const int N=3
    const char* a[N] = {"xjz","xzh","gh"};
    const char* b[N]= {"jzx","zhx","abc"};
    set<const char*,ltstr> A(a,a+N);
    set<const char*,ltstr> B(b,b+N);
    set_union(A.begin(),A.end(),B.begin(),B.end(),
                  ostream_iterator<const char*>(cout," "), ltstr());

  容器(container)是一种对象(object),可以包含并管理其它的对象,并提供迭代器(iterators)用以定址其所包含之元素。根据迭代器种类的不同,容器也分为几中,以Input Iterator为迭代器的一般container,以Forward Iterator为迭代器的Forward Container,以Bidirectional Iterator 为迭代器的Reversible Container,以Random Access Iterator为迭代器的Random Access Container。STL定义二种大小可变的容器:序列式容器(Sequence Container)和关联式容器(Associative Container)序列式容器包括vector、list和deque,关联式容器包括set、map、multiset和multimap。以下示例简单说明部分容器的使用:

1、vector使用
    // 将A中以元素5为分割点,分别排序,使排序后5后面的元素都大于5之前的元素(后区间不排序),
    // 然后输出
int main()
    {
        int A[] = {7,2,6,4,5,8,9,3,1};
        const int N=sizeof(A)/sizeof(int);
        vector<int> V(A,A+N);
        partial_sort(V,V+5,V+N);
        copy(V,V+N,ostream_iterator<int>(cout," "));
        cout << endl;
    }
    输出可能是:1 2 3 4 5 8 9 7 6
2、list使用
    // 产生一空list,插入元素后排序,然后输出
    int main()
    {
        list<int> L1;
        L1.push_back(0);
        L1.push_front(1);
        L1.insert(++L1.begin,3);
        L1.sort();
        copy(L1.begin(),L1.end(),ostream_iterator<int>(cout," "));
    }
    输出:0 1 3
3、deque使用
    int main()
    {
        deque<int> Q;
        Q.push_back(3);
        Q.push_front(1);
        Q.insert(Q.begin()+1,2);
        Copy(Q.begin(),Q.end(),ostream_iterator<int>(cout," "));
    }
    输出:1 2 3
4、map使用
    int main()
    {
        map<string,int> M;
        M.insert(make_pair("A",11);
        pair<map<string,int>::iterator, bool> p = M.insert(make_pair("C",5));
        if(p.second)
              cout << p.first->second<<endl;
    }
    输出:5
5、multiset使用
    int main()
    {
        const int N = 5;
        int a[N] = {4,1,1,3,5};
        multiset<int> A(a,a+N);
        copy(A.begin(),A.end(),ostream_iterator<int>(cout," "));
    }
    输出:1 1 3 4 5

设计新思维
  将设计模式(design patterns)、泛型编程(generic programming)和面向对象编程(object-oriented programming)有机的结合起来,便形成了设计新思维。其中,设计模式是经过提炼的出色设计方法,对于很多情况下碰到的问题,它都是合理而可复用的解决方案;泛型编程是一种典范(paradigm),专注于将类型抽象化,形成功能需求方面的一个精细集合,并利用这些需求来实现算法,相同的算法可以运用于广泛的类型集中,所谓泛型,就是具有在多种数据类型上皆可操作的含意;最后同面象对象编程中的多态(polymorphism)和模板 (templates)等技术相结合,便获得极高层次上的具有可复用性的泛型组件。泛型组件预先实现了设计模块,可以让用户指定类型和行为,从而形成合理的设计,主要特点是灵活、通用和易用。
  policies和policy类,是一种重要的类设计技术,所谓policy,是用来定义一个类或类模板的接口,该接口由下列之一或全部组成:内部类型定义、成员函数和成员变量。基于policy的类由许多小型类(称为policies)组成,每一个这样的小型类只负责单纯如行为或结构的某一方面。 Policies机制由模板和多重继承组成,它们可以互相混合搭配,从而形成设计戎的多样性,通过plicy类,不但可以定制行为,也可以定制结构。

下面简单举例说明泛化思维和面向对象思维在部分设计模式中的运用。

  Singletons设计模式泛化实现 Singleton模式是一种保证一个对象(class)只有一个实体,并为它提供一个全局访问点。Singleton是一种经过改进的全局变量,既在程序中只能有唯一实体的类型,它的重点主要集中在产生和管理一个独立对象上,而且不允许产生另一个这样的对象。
先让我们看看一般的C++实现的基本手法,下面是实现源码:

// Singleton.h文件中
class Singleton
{
public:

static Singleton& Instance()
{
    if(!pInstance_){
        if(destroyed_){     // 引用是否已经失效
              OnDeadReference();
        }
        else {
              Create();     // 第一次时创建实例
        }
    }
    return *pInstance_;
}
private:
    Singleton();                   // 禁止默认构造
    Singleton(const Singleton&);         // 禁止拷贝构造
    Singleton& operator= (const Singleton&);    // 禁止赋值操作
    static void Create()               // 传加创建的实例引用
    {
        static Singleton theInstance;
        pInstance_ = &theInstance;
    }
    static void OnDeadReference()
    {
        throw std::runtime_error(" 实例被不正当消毁");
    }
    virtual ~Singleton()
    {
        pInstance- = 0;
        destroyed_ = true;
    }
        static Singleton *pInstance_;
    static bool destroyed_;
}
// Singleton.cpp中静态成员变量初始化
Singleton* Singleton::pInstance_ = 0;
Bool Singleton::destroyed_ = false;

  如上所示,Singleton模式实现中只有一个public成员Instance()用来第一次使用时创建单一实例,当第二次使用时静态变量将已经被设定好,不会再次创建实例。还将默认构造函数、拷贝构造函数和赋值操作符放在private中,目地是不让用户使用它们。另外,为避免实例意外消毁后再实例化情况,加入静态布尔变量destroy_来进行判断是否出错,从而达到稳定性。
  从上面一般实现可以看出Singleton模式实现主要在于创建(Creation)方面和生存期(Lifetime)方面,既可以通过各种方法来创建 Singleton。Creation必然能创建和摧毁对象,必然要开放这两个相应函数,将创建作为独立策略分离开来是必需的,这样你就可以创建多态对象了,所以泛化Singleton并不拥有Creator对象,它被放在CreationPolicy<T>类模板之中。生命期是指要遵循C+ +规则,后创建都先摧毁,负责程序生命期某一时刻摧毁Singleton对象。

下面是一个简单的泛化Singleton模式的实现(不考虑线程因素)

    template
    <
        class T,
        template<class> calss CreationPolicy = CreateUsingNew,
        template<class> class LifetimePolicy=DefaultLifetime,
    >
    classs SingletonHolder
    {
    public:
        static T& Instance()
        {
              if(!pInstance_)
              {
                  if(destroyed_)
                  {
                      LifetimePolicy<T>::OnDeadReference();
                      destroyed_ = false;
                  }
                  pInstance_ = CreationPolicy<T>::Create();
                  LifetimePolicy<T>::SchedultCall(&DestorySingleton);
              }
              return *pInstance_;
        }
    private:
        static void DestroySinleton()
        {
              assert(!destroyed_);
              CreationPlicy<T>::Destroy(pInstance_);
              pInstance_ = 0;
              destroyed_ = true;
        }

        SingletonHolder();
        SingletonHolder (const SingletonHolder &);
        SingletonHolder & operator= (const SingletonHolder &); 

        Static T* pInstance_;
        Static bool destroyed_;
    };

  Instance()是SingletonHolder开放的唯一一个public函数,它在CreationPolicy、 LifetimePolicy中打造了一层外壳。其中模板参数类型T,接收类名,既需要进行Singleton的类。模板参数内的类模板缺省参数 CreateUsingNew是指通过new操作符和默认构造函数来产生对象,DefaultLifetime是通过C++规则来管理生命期。 LifetimePolicy<T>中有二个成员函数,ScheduleDestrution()函数接受一个函数指针,指向析构操作的实际执行函数,如上面DestorySingleton析构函数;OnDeadReference()函数同上面一般C++中同名函数相同,是负责发现失效实例来抛出异常的。CreationPlicy<T>中的Create()和Destroy()两函数是用来创建并摧毁具体对象的。

下面是上述泛化Singleton模式实现的使用:

1、应用一

class A{};
    typedef SingletonHolder<A, CreateUsingNew> SingleA;

2、应用二

    class A{};
    class Derived : public A {};
    template<class T> struct MyCreator : public CreateUsingNew<T>
    {
        static T* Create()
        {
              return new Derived;
        }
        static void Destroy(T* pInstance)
        {
              delete pInstance;
        }
    }
    typedef SingletonHolder<A,MyCreator> SingleA;

  通过上面示例可以看出, SingletonHolder采用基于plicy设计实现,它将Singleton对象分解为数个policies,模板参数类中 CreationPolicy和LifetimePolicy相当于二个policies封装体。利用它们可以协助制作出使用者自定义的 Singleton对象,同时还预留了调整和扩展的空间。由此而得,泛型组件(generic components),是一种可复用的设计模板,结合了模板和模式,是C++中创造可扩充设计的新方法,提供了从设计到代码的简易过渡,帮助我们编写清晰、灵活、高度可复用的代码

- 作者: 库马 2006年12月4日, 星期一 11:18  回复(0) |  引用(0) 加入博采

天岚石语(也是很多年了,很喜欢这类奇幻文)
涯出生的那年,正是穆帅率领大军扫平天岚州西北的“乱涯之叛”胜利归师的时候。在涯呱
呱坠地的那一刻,外面人们在街上载歌载舞,欢迎他们无敌的英雄。巫女将刚出生的涯轻轻浸
泡在爱迷河的河水中,让他哭出这人世间的第一声。当那个中年的巫女为了纪念这次胜利替他
取名为“涯”时,大概就己经注定了他和穆帅之间必然的命运。
在涯七岁那年,按照天岚的传统,当他刚刚有力气抱起自己的母亲时,他拥有了自己的剑。
接下来的修炼是痛苦的,他要学会在一瞬间将三百片明桑叶剖成均匀的两片,站在溪流中用剑
气迫开方圆一丈内的流水,一剑洞穿三个人身那么厚的巨石……
成为剑士是所有天岚青年的梦想,也是父亲对涯的期待。所以涯拼命地努力着,无休止地练
剑。可是涯的内心深外并不对剑士有着多大的期望。偶有闲暇的时候,他会爬上大山,采上一
大捧鲜花,再带回来分给小伙伴们。看着他们雀跃的样子,涯就会感到很快乐。
有一次,涯采到了一朵冰宛花。那花开在很高的悬崖上,涯从崖上顺着绳子攀下,采到了它
。它轻而小,洁白的花瓣散发着淡淡的有些令人伤感的幽香。在涯张开手,将它托在掌心仔细
地欣赏时,一阵大风吹过,将它从涯的手上带走,飘向悬崖外,飘向白云深处。那天晚上,小
小的涯独自一个抱着膝哭泣了一夜。
在涯十一岁的时候,他的剑有了灵。他至今还记得那晚的情形——睡梦中的他仿佛被什么召
唤醒了过来,半睁着睡眼来到剑室,他看到他的剑正随着自己的呼吸,闪烁着兴奋的红芒。他
将这把剑命名为“梵天”。
十五岁时,涯被送到海眼去杀龙——只有杀了龙,涯才可以成为一名真正的剑士。海眼不是
海,是一大片淡蓝色的沙漠。没有水,没有植物,有的只是无边无际的绝望和凶猛的石龙。涯
在第七天遇到了那龙,他开始与龙激战。那是一条很勇猛的龙,而涯己经三天没有饮水了,所
以他战得很苦。到了最后,“梵天”己经没有了剑气,在他掌中痛苦地呻吟着。涯则连站稳都
成了问题。而龙终于躺在血泊中,无力再战,用疲倦而哀伤的眼神望着涯。涯没有杀它,只是
割了它的一只角就回到了部落——他终于完成了父亲的梦想,成为一名剑士。
三年以后,涯作为天岚州新征的骑兵,终于见到了天岚人心中偶像、天岚州的无敌英雄——
穆帅。他仍然是天岚州的统帅,也是天下第一剑士。
十八年的岁月并没有在穆帅的脸上留下任何痕迹,他还是那样的英伟,沉郁。在他的目光中
,没有涯,也没有任何人。涯望着穆帅的眼,不由得想:“他是不是太寂寞了——因为他的无
敌?”
也许是上天对涯的特别“眷顾”,刚入伍不到三个月,涯遭遇到平生第一场战役:在天岚州
的极西方,天地的交汇处裂了一个缺口,一万七千多名来自地狱的鬼徒冲进了天岚州。天岚州
长老院派出三万大军进行围剿。
穆帅率领着他的剑士们与地狱鬼徒在西望平原展开决战。列阵后,西望平原成了刀剑与旗帜
的海洋。敌方的将军豪鬼发出了邀战的请求。穆帅没有出战,出战的是另一名将军——阿琅。
阿琅在第十五回合时被豪鬼的大环刀劈成了两半。在鬼徒们的欢呼声中,豪鬼举起大刀,仰首
向天,疯狂的嚎叫。
天岚剑士们一片静寂,所有的目光都向穆帅投去。穆帅的唇边却露出了一丝无奈的苦笑。剑
士们的心中都变得惶惶不安——难道连穆帅也感到害怕与畏惧了?连穆帅都惧怕的敌人,他们
又有什么资格去挑战?
鬼徒们挑衅的嘲笑声如同铁锤般重重地锤在每一名剑士的心中,也锤在穆帅的心中。穆帅暗
叹:“你们啊,是否每一次都要靠我来取得胜利呢?”无敌的穆帅并不是畏惧,他只是想把煅
炼的机会留给属下的每一名剑士,然而令他失望的是,好像剑士们没有一个能明白他的心意!
正当穆帅的手摸向剑柄,准备纵马而出的一刹那,一声异常响亮的马嘶声响起,一个银色的
身影如同来自九天的闪电,从剑士的队列中闪现出来,瞬间便到了狂笑不己的豪鬼面前。马儿
仍在扬蹄长嘶,长长的鬃毛在西望平原的朔风中猎猎飘扬,更衬得马上的骑士如同巍巍天神般
。那骑士正是涯!
豪鬼的笑声顿止,望向面前的挑战者。双眸中射出青碧色的光芒,使豪鬼看起来像头狼一样
可怕。然而,更可怕的是他的刀法。他的刀法没有路数,狂乱无章下隐藏了无数诡异玄奥的攻
势。涯根本无法腾手还招,只能抛开学到的一切剑术,凭本能招架着。
第十合、二十合、五十合……一百合、三百合……五百合……连涯都诧异自己竟然有这样强
韧的耐力。豪鬼的刀法终于开始散乱了。
涯开始驱动梵天剑的剑气。灼热的剑气形成沸腾的火焰带着死亡的呼啸射向豪鬼的胸堂——
这是涯的绝招之一“火炙荒原”。豪鬼不愧为高手,在千钧一发之际用大环刀将对方的剑气弹
开。不过,他也就到此为止了。“呀!”随着涯大声的怒吼,梵天剑愤怒地咆哮着,无法逼视
的光芒照亮了整个空间。豪鬼的眼睛在瞬间失明了,他大声号叫着,疯狂舞动大环刀。梵天剑
无声无息地穿透他的刀网,刺入了他的胸口。
豪鬼倒下了!天岚州的剑士们发出惊天动地的欢呼。
涯缓缓勒转马头,望向穆帅。穆帅的面孔仍旧是一片沉郁,仿佛世界上没有什么值得他流露
感情的人或情。不过他的手却动了,涯没有看到他是怎样张弓搭箭,只看到箭在离弦时那一瞬
间的停顿。
箭在离弦后化作一道银芒向涯射来。
涯没有动。箭掠过涯的耳际,飞了过去。
背后传来一声呻吟。涯转过身去,发现自己背后近在咫尺的地方,豪鬼缓缓松开手中的环刀
,诧异地看了胸前的箭羽一眼,重重地倒在地上。
天岚剑士们取得了完全胜利。涯被战士们歌颂着,被将军们夸奖着。可涯却无法高兴起来—
—他知道自己欠了穆帅一条命,他不喜欢这样的感觉!
那一战之后,涯被升为骑兵队长。他接到的第一个任务就是去天岚州的都城迎接穆帅的新娘
,天岚州的公主——水姬。虽然涯没有见过她,可也知道水姬不仅是天岚州最美的公主,也是
世界上最美丽的女人。
在穆帅给涯下达这个命令时,涯在穆帅的脸上看到了欣喜与温柔的神情——那是从末有过的
。穆帅在外连续征战己经三年了,虽然他取得了无数的胜利,可天岚州的西北始终不能完全平
定。他己经三年没有见过他的新娘,可涯还是看出她在穆帅心目中有多重要——比剑士们重要
,比战争重要,也许,比他自己的生命更重要。
涯所率领的骑兵队经过一个多月的跋涉,抵达了天岚州的都城石峨。城内张灯结彩,充满了
喜庆的气氛。从人们洋溢的笑脸上,涯看出他们对公主和穆帅的爱戴。欢送公主出阁的仪式庄
严而盛大,人们欢呼着公主和穆帅的名字。——最美丽的公主嫁给最伟大的英雄,不正是一个
最完美的结局么?
涯率领着骑兵们在城门列队,迎接公主的銮驾。出乎意料,与那盛大的仪式相反,来的只有
寥寥近百骑和十余辆大车。而且公主也没有坐辇轿,而是骑马。她催马来到骑兵队前时,所有
的骑士都下马行跪礼,涯身为剑士则不必如此,只是将剑柄单手抬至眉心,向她行剑礼。
公主美丽的脸庞上闪过一丝惊讶:“你是剑士?”涯点了点头。“好久没见到这么年轻的剑
士了……”公主微笑道。她和涯想像中的并不一样,没有王族的娇弱纤秀,反倒显得开朗健康
。而且,不知为什么,看着她的眼神,涯感到很亲切。“走吧,我们出发吧!”公主拍了一下
马头,抢先去了。
车队七天后到达烟眸河。骑兵们在河畔扎营休息。
涯在营中巡视着,看着人们不停地忙碌,直至一股股的炊烟袅袅升起。涯来到公主的帐边,
想询问一下有什么需要,却发现账里没有人。涯拦住一个侍女问道:“公主呢?”
“公主去河边了,还叫你们不要打搅她。”
涯皱了皱眉,向河边赶去——她可以不在乎自己的安全,他却不能。
远远地,涯就看见公主正挽起裙子,赤着脚弯着腰在河水中捞着什么。涯没有惊动她,抱着
剑在一边坐了下。他只需要保证她的安全主得了,至于她想做什么,那是她的自由。
突然,公主欢喜得叫了一声,好像发现了什么似的。当她举起手中的东西,涯才发现那是一
颗半透明的鹅卵石。她将石头贴紧了眼睛,对着太阳瞧。涯对这孩子气的举动有些好笑——身
为公主,应该见过无数的奇珍异宝吧,却为一颗石头高兴成这样?
公主感觉到了什么,抬起头望向涯。“你笑什么?”她不客气地问。
涯有点尴尬,讷讷地说不出话。“算啦,一看你就知道是个老实的家伙……”公主撇嘴,又
仔细地欣赏起手中的石头来。  
“难道那真是什么了不起的东西不成?”涯不禁好奇起来。
“你知道这是什么石头么?”她突然问涯。涯摇了摇头。
“你是缠心石呀,它的石语就是有缘想见。”
“石语?”涯惊奇地道。“是啊,每一种石头都有自己的做含意和传说……你看,这是北藏
石,它的石语是意外惊喜;这是瀚溟石,它的石语是美好的开端;还有,这是孔雀石,它石语
……它的石语倒挺适合你的……”公主突然抿嘴一笑,“它的石语是惜语如金……”
的确,七天来涯和公主见了面也只是行个礼而己,一共也只说了刚才的几句话。不过和公主
说话并不是涯的职责所在。
“好了,既然烦劳你护送我,这颗缠心石就送给你做答谢吧,我们是有缘相见……”,公主
大方地将石头递过去。
涯接过石头时碰到了她被河水浸得冰凉的小手。
“回去吧,该吃晚饭了。”涯想说点什么,却只说出这笨拙的话来。
公主吐了下舌头,提着半湿的裙子向营寨跑去。
谁也没有想到,第二天骑兵们竟遭到了蝎虎群的攻击。
数千只蝎虎不知为何离开了栖身的山涧,向车队疯狂地攻击。比战马还要高大的蝎虎摇着丈
余长的黑色尾椎将骑兵们一个个扎下马来。处处是鲜血,处处是哀嚎,处处是死亡。
涯脑中闪过的第一个念头就是车队己经保不住了,不过无论如何也要将公主救出去。劈翻了
两只蝎虎,涯纵身向公主的坐骑方向奔去。一片混乱中,涯看到一只蝎虎正把几个护卫公主骑
兵一一扎下马去。紧接着巨大的尾椎高高举起,对准公主的头顶扎下去。在那一瞬间,涯发现
公主的脸上竟没有任何恐惧,一片安然。他无暇细想,梵天剑脱手而出,将那只蝎虎的尾椎钉
在地上。
没有了梵天剑,涯费了好大劲才赶到了公主身边。看到涯,公主的眼中露出淡淡的喜色。“
你没事吧?”涯问。公主摇发摇头。涯拽住一只空鞍的战马翻身上马,向她伸出手:“走,我
们冲出去!”公主嫣然一笑,抓着涯的手上了马背。梵天剑不断飞舞着,灼热的剑气逼得蝎虎
们纷纷退开。涯护着公主杀开一条血路向外冲去。
就在冲出蝎虎群的一刹那,一只长长的尾椎穿透了梵天剑的防御,向涯扎来。涯是可以躲开
的,可他的身后还有水姬。就在尾椎戳入了涯的肩头时,梵天剑也将蝎虎的尾椎斩为两面三刀
截。淡青色的黏液喷了涯一头一脸。涯只感肩头一阵剧痛,险些栽下马去,幸亏一双柔软的手
及时伸了过来,抓住了他。然后,涯就在马背上昏了过去。
当涯醒来时,发现自己躺在森林中的一片草地上,公主正在为自己身边忙碌着什么。见涯醒
来,她急促地道:“我要马上为你拔出尾椎,替你拔毒,否则就太晚了。”涯吃力地点了点头
她将一块石头塞到涯的手中,道:“可能会很痛,你忍着点,这是荆麻石,它的石语就是忍
耐。”涯有点好笑:“好歹我也是个剑士,又上过战场,一点痛怕什么……”正这么想着的时
候,“啊……”一阵剧痛由肩头处蔓延全身,他忍不住痛呼出声。
公主将血淋淋的尾椎随手扔在一边,看了看伤口,又皱着眉对涯道:“毒己经浸入肩胛了,
可能要刮骨疗毒。”涯无力地呻吟一声,差点又昏过去:“天!刮……骨……?她到底是哪门
子的公主?这么下得了手……”
涯紧紧地握着手中荆麻石,抵受着一阵阵椎心的剧痛。豆大的冷汗不住地从他头上流下,将
眼睛都打湿了。转过头去看看公主,却发现她的汗竟然比自己流得还要多。她紧紧地咬着下唇
,竟然咬出血来了。
“看来,这块荆麻石应该由她拿着才对。”涯不禁想。
不知什么时候,公主竟开始唱起歌来,低低的,细细的歌声在涯的耳边回响,让涯感到轻松
了许多。
“想不到,她竟有这样一副好喉咙……哦,就是音咬得不太准……”
当涯再次醒来时,感觉己经好了许多,伤口也己经包扎好了。张开手一看,那块荆麻石竟然
被握得粉碎。“公主呢?”涯抬起头张望着。
“看什么?在这里呢!”公主拎着两尾活蹦乱跳的鱼兴高采烈地走了过来。“我们的食物全
没了,幸好我是宫里的第一钓鱼好手!”她得意地道。
“火呢?”涯故意问。公主眨了眨大眼睛,愣住了。
“准备生吃么?”涯忍着笑,又道。公主愤愤地将两尾鱼扔在地上。涯拾起身边的梵天剑,
叹了口气:“对不起啦,老伙计,今天就麻烦你做一下烤叉吧……”串在剑上的两条鱼很快就
被炙热的剑气烤得喷香。涯和公主津津有味地分享鲜美的鱼肉。
“给你!”公主突然将一块石头塞进涯的手心。“这是什么?”涯看着手中这块椭圆形的黑
色石头,上面缠满了金色的丝纹。“这是丝丹晚,它的石语是无限感激。谢谢你救了我。”公
主认真地道。涯有点不好意思,刚想张口说些什么。却被公主抢了话头:“不要说这是你应该
做的或者剑士责任什么的,我最讨厌听这个……”她皱着眉道。涯一下子哑了。
“还有……”她突然凑过身来。“什么?”涯愣愣地问。还没等涯回过神来,公主己经重重
地在他头上敲了一下。看着涯龇牙咧嘴地揉着脑袋,公主笑弯了腰,扬了扬藏在手中的一块绿
色石头:“这是神曼石,它的石语就是惩戒。哼!竟然敢说我的音咬得不准!”
“唉,看来千万不能在半昏迷的时候说话呀……”
因为怕再遭到蝎虎的袭击,涯决定避开蝎虎出没的烟眸河东岸,沿着森林前行至伏青山脉下
,再转道向穆帅的驻地——日落原。
森林中的路并不好走。何况这位稀奇古怪的公主大小姐还经常停下来拣石头。不仅她要捡,
涯也要帮着捡。
一天下午路过一个小湖时,公主突然大发奇想,说根据这个湖水判断,里面肯定有珍贵的银
姬石。于是涯只好停下来陪她在水里捞。结果银姬石没捞上来,倒捞上不少银须虾来,让两人
美美地饱餐了一顿。吃完饭后,涯懒洋洋地坐在湖边,用嘲笑的眼光望着公主。
“看什么看?以为我是笨蛋是不是?”她冲涯瞪眼睛。
涯不敢多说,怎么说她也是个公主更何况还是穆帅的末婚妻。
“我早知道这里是没有银姬石的……”她漫不经心地道。
“那为什么还要拉我下水?”涯装了一肚子问号。
“我只是……想走得慢点,就是这样……”公主望着夕阳下的湖水,喃喃地道。“为什么?
她不想早点见穆帅么?”涯想。
仿佛听到涯心中的话,公主继续喃喃自语着:“穆帅啊,他真是了不起!我很小的时候,他
就是己经闻名天下的大英雄了,没有人不知道他,没有人不以见过他为荣。我第一次见他是在
宫廷舞会,他一进场时候,大家就都停了下来,远远地望着他。当时我想,这是什么人呢?为
什么大家这么怕他?后来才知道,那不是怕,是敬畏。不光是大家,甚至连父王也一样。可是
,从来没有人敢亲近他。从来没有……”
涯突然想到穆帅那孤独的背影——是的,即使是身边围绕着千军万马,穆帅也仿佛永远是一
个人的样子。
“他没有亲人,没有朋友,没有伴侣,最可怕的是,他没有敌人。”公主珠声音在黄昏中缓
缓地荡漾,像湖水的微波,“当时我就想,这怎么行呢?于是我开始试着接近他,和他说话,
给他唱歌,对他搞恶作剧……”她的唇边出现了一丝微笑,显然是想起了穆帅被捉弄的样子。
“我知道穆帅喜欢我,我看得出来。可是……”她的眼光幽幽的,仿佛千年的叹息,“无论
我怎么接近他,还是感觉和他好远好远,永远无法拉近的样子。最后我终于明白了,穆帅是绝
代的英雄,而我,虽然贵为公主,可实际上不过是一个平凡的女孩子而己。”
一时间,涯不知道说些什么才好。对于穆帅的感觉,涯和水姬是完全相同的——穆帅那样的
人,永远也不会真正有人理解他。
“然后父王就宣布了穆帅和我的婚事。在父王想来,嫁给穆帅一定是很幸福的吧。不只父王
这么想,我身边所有的人也都这么想。为什么?嫁给一个英雄就一定是幸福的吗?我只想嫁给
一个自己真正喜欢的人,哪怕他是个最平凡的人也好……”
涯没有说话,将身边的一颗石子用力投了出去。
“咚”的一声,湖水中泛起金色的漪涟。
涯与公主的跋涉在继续着。公主收集的石头也越来越多。有象征友情的琉璃,象征悲伤的雨
涟石,象征流逝时光的双绾石,象征重新开始的飞洹蛋,象征永远守护的天青碧雨……
“真难为她,那么多种的石语是怎样一一记住的。”涯有时忍不住想。