男人=吃饭+ 睡觉+挣钱
猪=吃饭+ 睡觉
男人=猪+挣钱
猪=男人-挣钱
所以男人不挣钱等于猪。
 
女人=吃饭+ 睡觉+花钱。
猪  =吃饭+ 睡觉。代入上式得:
女人=猪+花钱。移项得:
女人-花钱=猪。
结论:女人不花钱的都是猪。
 
综上:
男人为了让女人不变成猪而挣钱!
女人为了让男人不变成猪而花钱!
     
男人+女人=两头猪

posted @ 2006-12-04 01:58 笨蛋啊帆 阅读(318) | 评论 (1)编辑 收藏

Tomcat Server下發布網頁錯誤及解決方法

1﹑tomcat5.5 中 JasperException: Failed to load or instantiate TagExtraInfo class:org.Apache.struts.taglib.html.MessagesTei

JasperException: FailedtoloadorinstantiateTagExtraInfo class: com.acme.tag.IterateTEI( 注意這里有可能是別的相近的提示。)

 

原因是 web-inf/lib/下出現了jsp-api.jar和,serverlet-api.jar,把它們刪除,然後重新啟動 web應用即可。

 

2﹑

HTTP Status 500 -


type Exception report

message

description The server encountered an internal error () that prevented it from fulfilling this request.

exception

javax.servlet.ServletException: org.w3c.dom.Node.getTextContent()Ljava/lang/String;

        org.apache.jasper.runtime.PageContextImpl.doHandlePageException(PageContextImpl.java:825)

        org.apache.jasper.runtime.PageContextImpl.handlePageException(PageContextImpl.java:758)

        org.apache.jsp.login_jsp._jspService(login_jsp.java:318)

        org.apache.jasper.runtime.HttpJspBase.service(HttpJspBase.java:94)

        javax.servlet.http.HttpServlet.service(HttpServlet.java:802)

        org.apache.jasper.servlet.JspServletWrapper.service(JspServletWrapper.java:324)

        org.apache.jasper.servlet.JspServlet.serviceJspFile(JspServlet.java:292)

        org.apache.jasper.servlet.JspServlet.service(JspServlet.java:236)

        javax.servlet.http.HttpServlet.service(HttpServlet.java:802)

        javax.adore.ServletCofing.doFilter(ServletCofing.java:53)

root cause

java.lang.NoSuchMethodError: org.w3c.dom.Node.getTextContent()Ljava/lang/String;

        com.pcc.afs.dao.sql.SQL.getSql(SQL.java:110)

        com.pcc.afs.dao.sql.SQL.getSelect(SQL.java:62)

        com.pcc.afs.dao.AllowIP.initialize(AllowIP.java:41)

        com.pcc.afs.dao.AllowIP.<init>(AllowIP.java:19)

        org.apache.jsp.login_jsp._jspService(login_jsp.java:128)

        org.apache.jasper.runtime.HttpJspBase.service(HttpJspBase.java:94)

        javax.servlet.http.HttpServlet.service(HttpServlet.java:802)

        org.apache.jasper.servlet.JspServletWrapper.service(JspServletWrapper.java:324)

        org.apache.jasper.servlet.JspServlet.serviceJspFile(JspServlet.java:292)

        org.apache.jasper.servlet.JspServlet.service(JspServlet.java:236)

        javax.servlet.http.HttpServlet.service(HttpServlet.java:802)

        javax.adore.ServletCofing.doFilter(ServletCofing.java:53)

note The full stack trace of the root cause is available in the Apache Tomcat/5.0.28 logs.

 

這個錯誤﹐從網上搜索時﹐一般說是JDK版本問題﹐但我更新JDK(由1.5.0~1.5.0.06)還是報以上錯誤﹐后來我又更新了一下TOMCAT(由tomcat5.0.28更為5.5.9)問題解決。

在測試AJAX時也遇到過要更新TOMCAT的問題﹐所以個人覺得如果JDK用1.5﹐TOMCAT也應用5.5.X以上版本最為保險。

posted @ 2006-12-04 01:25 笨蛋啊帆 阅读(991) | 评论 (3)编辑 收藏




一、Win2k + JDK1.4 + Apache Tomcat 4.1.27 + jakarta-struts-1.1 环境

本例新建struts项目应用的存放路径为:TOMCAT_HOME\webapps\ROOT\StrutsWeb 。
(TOMCAT_HOME是Apache Tomcat 4.1.27在服务器的安装路径,根据具体情况而有所不同,StrutsWeb即是一个struts项目应用的保存路径)


1.访问JSP页面:http://127.0.0.1:8080/StrutsWeb/index.jsp ,出现类似下面的错误提示:

  “org.apache.jasper.JasperException: File "/WEB-INF/struts-bean.tld" not found”
  “org.apache.jasper.JasperException: File "/WEB-INF/struts-html.tld" not found”

解决办法:

*1*.

先检查struts应用的标签文件的配置情况,对应\jakarta-struts-1.1\lib\中的*.tld文件,看看\StrutsWeb\WEB-INF\中的*.tld文件是否完整。
如果不全,则需要从\jakarta-struts-1.1\lib\中,把全部*.tld文件copy至\StrutsWeb\WEB-INF\中。
然后重新启动Apache Tomcat,看看效果如何。
*.tld是标签库描述器文件,它们描述了多个struts标记库中的自定义标签。
   
*2*.

如果确认struts项目的标签文件配置无误,那么,在一般情况下,是需要把struts项目的这个WEB应用在Tomcat的服务应用中单独描述出来,
即需修改TOMAT_HOME\conf\server.xml文件,在server.xml中找到如下行:

  <!-- Tomcat Root Context -->
  <!--
      <Context path="" docBase="ROOT" debug="0"/>
  -->

然后在其下面加上这句:

  <Context path="/mystruts" docBase="TOMCAT_HOME\webapps\ROOT\StrutsWeb" debug="0" reloadable="true"/>

保存server.xml,然后重新启动Apache Tomcat,这样就可以访问这个WEB应用了。

即可这样访问:http://127.0.0.1:8080/mystruts/
           或 http://127.0.0.1:8080/mystruts/index.jsp。

注意:“TOMCAT_HOME”的具体含义如前所述,是根据本机的情况而定的。



2.访问JSP页面:http://127.0.0.1:8080/mystruts/index.jsp ,出现如下的错误提示:
   
  “org.apache.jasper.JasperException: Cannot find ActionMappings or ActionFormBeans collection”

解决办法:

*1*

对应\jakarta-struts-1.1\lib\中的*.jar文件(struts1.1共有10个*.jar文件),看看\StrutsWeb\WEB-INF\lib\中的*.jar文件是否完整。
如果在\StrutsWeb\WEB-INF\lib\中只有一个struts.jar,那么将其他的*.jar文件也copy到\StrutsWeb\WEB-INF\lib\中。
然后重新启动Apache Tomcat即可访问。
struts.jar是一个重要的文件,它包含了struts中的所有Java类。

*2*

如果经过上面的一步还没有搞定,那么请耐心的检查或修改\StrutsWeb\WEB-INF\中的struts-config.xml配置文件。
看看struts配置情况是否写错,action-mappings的配置是否写错。
一定要注意区分字母的大小写。
请再检查一遍。
然后请再检查一遍。
不要烦躁,一定要像对待初恋情人一样对待它,不然会死的很难堪!
一定要好好检查。
这个MVC中的C很要命的,流程控制全靠它了,一定要小心呵护的。[:D]
还有,记得修改完毕后重新启动Apache Tomcat。

*3*

我在网上看到有人对这个问题说“试了千百回,改了千百次,就是不知道什么原因”。
如果你也恰好和struts是初恋,也恰好试了千百回,改了千百次,
“Cannot find ActionMappings or ActionFormBeans collection”的错误仍然涛声依旧,
那么,请不要灰心,
相信我,胜利的喜悦你马上就能体会到!

因为,这里有一个毕杀绝技!!!!!

请按照如下操作:

打开TOMAT_HOME\conf\server.xml文件,找到在上面提到过的加入WEB应用的那一行:

  <Context path="/mystruts" docBase="TOMCAT_HOME\webapps\ROOT\StrutsWeb" debug="0" reloadable="true"/>

然后对其修改成为:

  <Context path="/mystruts" docBase="TOMCAT_HOME\webapps\ROOT\StrutsWeb" debug="0" reloadable="true" privileged="true"/>

这样就加上一个参数:privileged="true",这个参数是至关重要的。
(我花N多时间找了N多帖子问了N个人才搞定的,可见struts的初恋有多辛苦了!! [:(])
 
然后重新启动Apache Tomcat,这样访问JSP页面就没有问题了。[:D]
 
*4*

我在网上查找了一些struts应用的配置说明资料,一些配置资料上只提到把struts.jar这个文件copy到\WEB-INF\lib\中,
而并没有说需要把sturts的全部*.jar文件进行copy。
上面提到过,struts.jar包含了struts中的所有Java类。故我有此一试。
(当然,如果连struts.jar都没有了,那就没有搞头了。[:(] )

我只把struts.jar文件copy到\StrutsWeb\WEB-INF\lib\中,然后启动Apache Tomcat(当然,web.xml和struts-config.xml已经配置完毕)。
一试,果然不爽。

访问JSP页面时,看到提示错误:

  “org.apache.jasper.JasperException: Cannot find ActionMappings or ActionFormBeans collection”

傻眼了。

又折腾了半天,发现上面提到的privileged="true"在这种情况下也可以发挥作用,
即修改server.xml文件,在<Context>的描述中加上参数privileged="true",使之变成这样:

   <Context path="/mystruts" docBase="TOMCAT_HOME\webapps\ROOT\StrutsWeb" debug="0" reloadable="true" privileged="true"/>

这样就可以访问JSP页面并且运行无误,没有错误提示了。[^ō^]

所以可以得出这样一个东东:
   如果在\StrutsWeb\WEB-INF\lib\中只有一个struts.jar而没有其他的*.jar文件,那么,在server.xml文件 中把相对的WEB应用的描述进行修改,在其中加入privileged="true"参数,就可以使struts项目的应用正常运行且访问无误。



二、Win2k + JDK1.4 + Apache Tomcat 5.0.13 + jakarta-struts-1.1 环境

用Tomcat5作为JSP的容器,上述问题在struts中也会经常遇到,解决方法也都大致相同,privileged="true"对Tomcat5也同样有效。[:D]

下面主要说一下不同的地方。

平时对Apache Tomcat没有仔细研究,这次发现了几点,简略记录一下。

*1*

与Apache Tomcat4比较,Apache Tomcat5在其conf文件夹中增加了Catalina目录及子目录,其详细路径为:TOMCAT_HOME\conf\Catalina\ localhost\,在localhost文件夹中全部是*.xml文件。
每个*.xml文件对应一个Tomcat的WEB应用的名字。

localhost文件夹中,Apache Tomcat5自动生成的有两个文件,即admin.xml和manager.xml文件。

当Apache Tomcat5启动后,就可以这样访问了:

  http://127.0.0.1:8080/admin/
  http://127.0.0.1:8080/manager/

其中,访问http://127.0.0.1:8080/admin/ ,通过用户名和密码的验证后,就可以进入Tomcat的WEB服务管理器(TOMCAT WEB SERVER ADMINISTRATION TOOL)了。

*2*

在Tomcat4中新增一个WEB应用项目的访问,是在TOMAT_HOME\conf\server.xml文件中增加一个<Context>描述,在server.xml中找到如下行:

  <!-- Tomcat Root Context -->
  <!--
      <Context path="" docBase="ROOT" debug="0"/>
  -->

然后在其下面加上这句:

  <Context path="/mystruts" docBase="TOMCAT_HOME\webapps\ROOT\StrutsWeb" debug="0" reloadable="true"/>

保存server.xml后重新启动Apache Tomcat4,就可以通过http://127.0.0.1:8080/mystruts/ 来访问这个WEB应用了。

在Tomcat5中同样的也可以这么做。

同样的,在TOMAT_HOME\conf\server.xml文件中增加一个<Context>描述,重新启动Tomcat服务后就可以用来访问了。

需 要特别指出的是,当在在Tomcat5的server.xml文件中增加一个<Context>描述后,重新启动Tomcat时,会自动在 TOMCAT_HOME\conf\Catalina\localhost\路径下生成一个xml文件,这个xml文件的名称和< Context>描述中所写的WEB应用的名字是一样的。
如果server.xml文件中的这个<Context>描述有所改动的话(增加属性或修改属性),重新启动Tomcat时,这些改动变化都会及时的反映在同名的xml文件中(这样就做到了同步一致)。

例如上面在server.xml中所写的
<Context path="/mystruts" docBase="TOMCAT_HOME\webapps\ROOT\StrutsWeb" debug="0" reloadable="true"/>

当Tomcat5启动后,会在\Catalina\localhost\下生成一个名字为“mystruts.xml”的文件。
其内容和server.xml中所写的一样,为:

<Context docBase="TOMCAT_HOME/webapps/ROOT/StrutsWeb" path="/mystruts" reloadable="true">
</Context>

所 以,我们可以这样说:如果要在Apache Tomcat5中新增WEB应用服务的话,就可以直接在TOMCAT_HOME\conf\Catalina\localhost\路径下编辑生成一个 xml文件,在这个xml文件中写上相对应的<Context>描述即可,而不需要在server.xml中增加或编辑其他东东了。 [^ō^]


*3*

另外,需要说明的是,Apache Tomcat正常安装后的启动方式有多个:

   ** 可以在TOMCAT_HOME\bin\中点击startup.bat来启动Tomcat服务。

   ** 可以在“开始”-->“程序”-->“Apache Tomcat”菜单中点击“Start Tomcat”来运行Tomcat服务。

但是,Tomcat4和Tomcat5的服务运行形式是不一样的。

Tomcat4无论从“startup.bat”点击运行还是从“Start Tomcat”点击运行,都会出现黑屏白字的命令提示符窗口(类DOS窗口),用来提示说明Tomcat服务的运行情况和一些日志信息。

Tomcat5 从“startup.bat”点击运行后,出现的是黑屏白字的命令提示符窗口,而从“Start Tomcat”点击运行后,服务窗口不会出现,而只会在屏幕的右下方出现一个带绿色三角的托盘图标([:D]乍一看,这个图标和MS SQLSERVER服务管理器的图标几乎一模一样)。


*4*

使用Apache Tomcat5做服务,特别需要指出的是,如果在TOMAT_HOME\conf\server.xml文件中增加一个<Context>描述,
用“startup.bat”方式启动Tomcat服务时,在命令提示符窗口上会显示出如下信息(但是不会影响struts的使用)
------------------------------
警告: Error storing config file
java.io.FileNotFoundException: ..\..\conf\Catalina\localhost\mystruts.xml (系统找
不到指定的路径。)
------------------------------
并且\Catalina\localhost\下对应的xml文件不会得到更新。

从“Start Tomcat”点击运行Tomcat5服务是不会有这种情况的(这个可以察看Tomcat的日志文件)。


*5*

再来关注一下<Context>描述中的参数“privileged="true"”。

在路径TOMCAT_HOME\conf\Catalina\localhost\下,找到Apache Tomcat5自动生成的有两个文件,即admin.xml和manager.xml文件。

打开xml文件,能分别找到如下内容:
------------------------------
<Context path="/admin" docBase="../server/webapps/admin"
         debug="0" privileged="true">
</Context>


<Context path="/manager" docBase="../server/webapps/manager"
        debug="0" privileged="true">
</Context>
------------------------------

呵呵,看明白了吗?
Apache Tomcat5自动生成的xml文件中,对<Context>的描述中,都有一个参数,即privileged="true" 。
   

posted @ 2006-12-04 01:21 笨蛋啊帆 阅读(178) | 评论 (0)编辑 收藏


 
创建数据库
指定数据库字符集和校对规则:
mysql> create database it315 default character set gb2312 collate gb2312_chinese_ci;
 
进入刚创建的数据库:
mysql> use it315;
Database changed
 
创建表:
mysql> create table student (id int primary key,name varchar(20),address varchar(20));
 
写一个属性文件: jdbc_mysql.properties,此文件存储一些连接相关的信息:
driver=com.mysql.jdbc.Driver             //驱动名称
url=jdbc:mysql://localhost:3306/it315    //指定URL
user=root                                                 //用户名
password=                                        //密码
characterEncoding=gb2312                 //指定字符编码
 
写java源文件: JdbcMySql.java
import java.io.IOException;
import java.io.InputStream;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.Statement;
import java.util.Properties;
 
public class JdbcMySql {
 
       public static Properties getProperties() {
              Properties props = new Properties();
              InputStream is = null;
              try {
                     is = JdbcMySql.class
                                   .getResourceAsStream("/jdbc_mysql.properties");
                     props.load(is);
              } catch (Exception ex) {
                     ex.printStackTrace();
return null;
              } finally {
                     if (is != null)
                            try {
                                   is.close();
                            } catch (IOException e) {
                                   e.printStackTrace();
                            }
              }
              return props;
       }
 
       public static void main(String[] args) {
              Connection conn = null;
              Statement stmt = null;
              ResultSet rs = null;
 
              Properties props = getProperties();
              if (props != null){
                    // 读取出属性文件里面的内容
                    String driver = props.getProperty("driver");
                    String url = props.getProperty("url");
                     String user = props.getProperty("user");
                    String password = props.getProperty("password");
                    String characterEncoding = props.getProperty("characterEncoding");
 
                    try {
                            Class.forName(driver);// 加载驱动
 
                            conn = DriverManager.getConnection(url + "?characterEncoding="
                                          + characterEncoding, user, password);// 建立连接
                            stmt = conn.createStatement();
 
                            String sql = "insert into student values(1,' 张三','湖南')";
                            stmt.executeUpdate(sql);// 执行sql语句
 
                            sql = "select * from Student";
                            rs = stmt.executeQuery(sql);
 
                            while (rs.next()) {// 从结果集中取出数据
                                   System.out.print(rs.getInt(1) + "\t");
                                   System.out.print(rs.getString(2) + "\t");
                                   System.out.print(rs.getString(3) + "\n");
                            }
 
                     } catch (Exception e) {
                            e.printStackTrace();
                     } finally {// 释放连接
                            try {
                                   if (rs != null)
                                          rs.close();
                                   if (stmt != null)
                                          stmt.close();
                                   if (conn != null)
                                          conn.close();
                            } catch (Exception ex) {
                                   ex.printStackTrace();
                            }
                     }
}
       }
}
 
编译运行:
C:\ >javac JdbcMySql.java
 
C:\ >java JdbcMySql
1                         张三 湖南
 
进数据库查询刚刚插入的信息:
mysql> select * from student;
+----+------+---------+
| id | name | address |
+----+------+---------+
| 1 | ??? | ??    |
+----+------+---------+
我们看到中文变成了问号.别急!退出mysql
mysql> quit;
Bye
 
再进去:
C:\ >mysql -uroot --default-character-set=gb2312
 
查询:
mysql> use it315;
Database changed
mysql> select * from student;
+----+--------+---------+
| id | name   | address |
+----+--------+---------+
| 1 |张三 | 湖南 |
+----+--------+---------+
OK!一切正常了….

posted @ 2006-11-19 03:28 笨蛋啊帆 阅读(2246) | 评论 (0)编辑 收藏



模型-视图-控制器(MVC)是Xerox PARC在八十年代为编程语言Smalltalk-80发明的一种软件设计模式,至今已被广泛使用。 最近几年被推荐为Sun公司J2EE平台的设计模式,并且受到越来越多的使用 ColdFusion 和 PHP 的开发者的欢迎。模型-视图-控制器模式是一个有用的工具箱,它有很多好处,但也有一些缺点。
MVC如何工作

MVC是一个设计模式,它强制性的使应用程序的输入、处理和输出分开。使用MVC应用程序被分成三个核心部件:模型、视图、控制器。它们各自处理自己的任务。

视图
视 图是用户看到并与之交互的界面。对老式的Web应用程序来说,视图就是由HTML元素组成的界面,在新式的Web应用程序中,HTML依旧在视图中扮演着 重要的角色,但一些新的技术已层出不穷,它们包括Macromedia Flash和象XHTML,XML/XSL,WML等一些标识语言和Web  services.

如何处理应用程序的界面变得越来越有挑战性。MVC一个大的好处是它能为你的应用程序处理很多不同的视图。在视图中其实没有真正的处理发生,不管这些数据是联机存储的还是一个雇员列表,作为视图来讲,它只是作为一种输出数据并允许用户操纵的方式。

模型
模 型表示企业数据和业务规则。在MVC的三个部件中,模型拥有最多的处理任务。例如它可能用象EJBs和ColdFusion Components这样的 构件对象来处理数据库。被模型返回的数据是中立的,就是说模型与数据格式无关,这样一个模型能为多个视图提供数据。由于应用于模型的代码只需写一次就可以 被多个视图重用,所以减少了代码的重复性。

控制器
控制器接受用户的输入并调用模型和视图去完成用户的需求。所以当单击Web页面中的超链接和发送HTML表单时,控制器本身不输出任何东西和做任何处理。它只是接收请求并决定调用哪个模型构件去处理请求,然后用确定用哪个视图来显示模型处理返回的数据。

现在我们总结MVC的处理过程,首先控制器接收用户的请求,并决定应该调用哪个模型来进行处理,然后模型用业务逻辑来处理用户的请求并返回数据,最后控制器用相应的视图格式化模型返回的数据,并通过表示层呈现给用户。

为什么要使用 MVC

大 部分Web应用程序都是用像ASP,PHP,或者CFML这样的过程化语言来创建的。它们将像数据库查询语句这样的数据层代码和像HTML这样的表示层代 码混在一起。经验比较丰富的开发者会将数据从表示层分离开来,但这通常不是很容易做到的,它需要精心的计划和不断的尝试。MVC从根本上强制性的将它们分 开。尽管构造MVC应用程序需要一些额外的工作,但是它给我们带来的好处是无庸质疑的。

首先,最重要的一点是多个视图能共享一个模型,正 如我所提及的,现在需要用越来越多的方式来访问你的应用程序。对此,其中一个解决之道是使用MVC,无论你的用户想要Flash界面或是 WAP 界面;用一个模型就能处理它们。由于你已经将数据和业务规则从表示层分开,所以你可以最大化的重用你的代码了。

由于模型返回的数据没有进 行格式化,所以同样的构件能被不同界面使用。例如,很多数据可能用HTML来表示,但是它们也有可能要用Macromedia Flash和WAP来表示。模型也有状态管理和数据持久性处理的功能,例如,基于会话的购物车和电子商务过程也能被Flash网站或者无线联网的应用程序 所重用。

因为模型是自包含的,并且与控制器和视图相分离,所以很容易改变你的应用程序的数据层和业务规则。如果你想把你的数据库从 MySQL移植到Oracle,或者改变你的基于RDBMS数据源到LDAP,只需改变你的模型即可。一旦你正确的实现了模型,不管你的数据来自数据库或 是LDAP服务器,视图将会正确的显示它们。由于运用MVC的应用程序的三个部件是相互对立,改变其中一个不会影响其它两个,所以依据这种设计思想你能构 造良好的松偶合的构件。

对我来说,控制器的也提供了一个好处,就是可以使用控制器来联接不同的模型和视图去完成用户的需求,这样控制器可以为构造应用程序提供强有力的手段。给定一些可重用的模型和视图,控制器可以根据用户的需求选择模型进行处理,然后选择视图将处理结果显示给用户。

MVC的缺点
MVC的缺点是由于它没有明确的定义,所以完全理解MVC并不是很容易。使用MVC需要精心的计划,由于它的内部原理比较复杂,所以需要花费一些时间去思考。

你将不得不花费相当可观的时间去考虑如何将MVC运用到你的应用程序,同时由于模型和视图要严格的分离,这样也给调试应用程序到来了一定的困难。每个构件在使用之前都需要经过彻底的测试。一旦你的构件经过了测试,你就可以毫无顾忌的重用它们了。

根据我个人经验,由于我们将一个应用程序分成了三个部件,所以使用MVC同时也意味着你将要管理比以前更多的文件,这一点是显而易见的。这样好像我们的工作量增加了,但是请记住这比起它所能带给我们的好处是不值一提。

MVC并不适合小型甚至中等规模的应用程序,花费大量时间将MVC应用到规模并不是很大的应用程序通常会得不偿失。

MVC是一条创建软件的好途径
MVC 设计模式是一个很好创建软件的途径,它所提倡的一些原则,像内容和显示互相分离可能比较好理解。但是如果你要隔离模型、视图和控制器的构件,你可能需要重 新思考你的应用程序,尤其是应用程序的构架方面。如果你肯接受MVC,并且有能力应付它所带来的额外的工作和复杂性,MVC将会使你的软件在健壮性,代码 重用和结构方面上一个新的台阶。

posted @ 2006-11-17 14:03 笨蛋啊帆 阅读(130) | 评论 (0)编辑 收藏

虽然微软的Internet Explorer小组已经发布了微软浏览器的7.0版本,但他们很快就投入到IE 8的开发中。按照微软的一位系统平台设计师的说法,应该称之为“IE Next”。

  在Ajax Experience大会上,微软的Internet Explorer平台设计师Chris Wilson说,“全组人(Internet Explorer小组研发人员)都在努力地开发IE 8,我想我应该叫它作‘IE Next’。” 另外,Wilson在IE 8项目上有过另一次的评论,他提到下一个版本(IE 8)的IE关键主题思想将包含“用户的安全和隐私,改进网络应用程序平台,提供最好的网络用户体验,以及兼容性仍然会继续作为一个宗旨。”

  然而,在Ajax会议即将到来时谈论这个问题,Wilson说,“IE 7所做的不仅是添加了一些无关紧要的特性;它使得开发人员可以结合Ajax进行有趣地开发”。 在IE 7中,微软已经相当大地改进了它的头号浏览器。

  此外,在问到微软关于JavaScript 2——未来浏览器语言的编写形式的远景展望时,Wilson说,他还在等着听到更多的开发人员如何看待JavaScript 2的重要性的声音,“在微软内部,我们正在致力于JavaScript的工作,我认为这是非常好的。作为一种许多人都在应用的开发语言,我们已经成功地使 JavaScript在公司里得到认可——这并不只是在微软中才这样。” 在IE 7发布的四天后,Wilson说,“微软获得了这个浏览器的300万下载量,且这些都不是自动升级的”。他还说道,基于Windows网络的百分之九十的份额都是在Windows XP上,因此,接纳IE 7的数量仍然会迅速地增加。

  在Ajax Experience大会的一次单独谈话中,Mozilla的首席技术官员、JavaScript语言的创造者Brendan Eich说,“在Firefox 2发布的22小时后,Mozilla统计到的这个开源浏览器的下载量是200万。”

  IE 7需要再修复?

  根据Wilson所说的,虽然IE 7增加了一些标准的“承诺”功能,同时修复了一些其它问题,但一些在IE 6中无法正常显示的页面在新的版本中仍无法得以正常显示。因此他重新集合了开发者,呼吁他们行动起来。 “请用IE 7来测试你的页面,”他说,“标准的改进意味着性能将发生变化。最终用户不喜欢页面无法显示;为了确保你的IE组件都为可选择的与受保护的模式做好准备,创造一个质的飞跃。建议用户使用新的东西,像现在的RSS生成器,使用OpenSearch进行搜索,然后向我们反馈。” 微软对IE做了许多改进来帮助网络用户。微软公司最为关注的关键领域之一是“为那些需要谋生的普通人,我们修正了最为恼人的bug,添加了需求标准”。

  确实,微软修正了一些目前IE与万维网联盟(W3C)的规则之间的不协调,例如包含本地的XMLHttpRequest支持。而对于相关Ajax的问题,微软改进了Java脚本垃圾收集机制,修复了一些主要的存储的漏洞,以及以gzipped压缩格式的文件的缓存。

  微软同时还修复了200多个CSS与版面的bug,包括语法错误、JScript引擎的存储漏洞以及溢出性能的错误。提到标准承诺,Wilson说,“我们已经‘故意’地在IE中‘破坏’了许多东西,我们必须切实地注意到我们还会‘破坏’什么,有多少人将会因此受到影响。” 此外,根据他上司的话,Wilson说,“我真的很担心如果我们以善良的名义‘破坏’网页的原始文件,这样所有的用户和开发者将会因为原始文件遭破坏而离开我们。”

  出于这个原因,IE 7也还是有着一个“兼容模式”,而这并未能反映出所做的变化将把这个产品带入“标准模式”或标准版本。另外,微软还成立了一个专注于兼容性的小组,来向用户确保兼容性。 尽管如此,Wilson表示,IE 7需要开发者的帮忙以打破恶意循环,虽然微软优先地修复了平台和破坏标准的bug,但微软仍然需要用户和其他开发人员通过测试和修复页面来帮忙——这是一个共栖的关系。

  安全性仍是IE的“软肋”

  微软开发了一个IE 7的Readiness Toolkit,它包含了一个网页开发者工具条、一个错误CSS表达式查找器和兼容性工具。 Wilson曾在原来的National Center从事超级计算机应用程序Mosaic浏览器相关的工作。他参与了第一个Windows版本的NCSA Mosaic的开发。在他加入微软之后,至少从第四个版本开始就一直致力于IE的开发。 “安全性是IE小组中最重要的工作”,Wilson表示。

  微软在IE 7中提高了安全性,保护用户免受网络中的欺骗行为,提供了更安全的系统默认值和完全的用户控制,同时也提高了防护恶意软件的能力。同时,在一个题为“昔日与未来的网络”的演说中,Wilson说,他相信mashups技术将继续推动革新,正如组件化和语义标注的数据处在重要地位,并将持续增长。

  同样地,隐私也将成为一个重大的问题。 Wilson是有备而来的,他已对那一套频繁被问及的问题胸有成竹。用户曾要求过能够同时运行多个版本IE的功能,对此,Wilson表示:无论如何,我们都不是一个独立的应用程序,而是一整套的系统DLL。这就使得这个要求有些难以实现。但Wilson另外表示:“我们也尝试着想出如何能做到这样的方法”。

  一种可能的解决方案就是虚拟化:“虚拟个人计算机现在是免费的,但我们仍在尝试着围绕镜像和授权镜像之间的努力和工作。” 此外,Wilson指出,IE不久后可能不支持XHTML。直到我们能做好虚拟化解决方案。”

  未来网络中的语义数据

  关于网络的未来,Wilson谈到:maps加速了mashup革命,同时,由于存在附属于数据的语义信息的概念,mashups有助于语义网络的再生。 “RSS则是随处可见的语义数据”。“微格式(microformats)增加了许多缺失的HTML含义。”微格式使HTML(或XHTML)网页中的语义表达成为可能。

  开发者将会试图堆叠语义数据。你会希望能组件化语义数据,使它成为应用程序。但是,必须注意到用标签定义俗语。 此外,mashup技术使得语义化更为实用,例如,微软的活动剪贴板则是用mushup模式的微格式。这就使得网络对更多的用户来说都变得更有可用性。

  同时,Wilson号召网页开发者从设计的第一天开始就充分考虑关键因素:易用性、安全性和隐私。 然而,他却提醒道,Ajax已增加了网络上攻击的介质。此外,mashup代码共享则要求信任,并且,“你必须信任你建造一个沙盒所围绕的这些代码。”

  最后,Wilson告诫开发者,虽然网络架构可利用,但开发者应该“明白为什么你使用它们”,因为它们可能象征着一个沿着道路的“经整合了的潜在的巴别塔”。

posted @ 2006-11-03 03:52 笨蛋啊帆 阅读(142) | 评论 (0)编辑 收藏

引介(Introduction)是指在不更改源代码的情况,给一个现有类增加属性、方法,以及让现有类实现其它接口或指定其它父类等,从而改变类的静态结构。Spring AOP通过采代理加拦截器的方式来实现的,可以通过拦截器机制使一个实有类实现指定的接口。
  在实际应用中可以使用DefaultIntroductionAdvisor来配置引介,也可以直接继承 DefaultIntroductionAdvisor来实现引介。这里是昨天在《深入Spring 2:轻量级J2EE开发框架原理与实践》中作的一个示例。总体感觉代理拦截机制实现的引介,达到类似于AspectJ那样的语言扩展方式实现的AOP引介的火力还差很多。
  示例是一个模拟Warcraft的小游戏,包括英雄、道具、技能、战场(地图)等。整个示例UML图如下所示:
  
  
  示例中的英雄、地图及各自持有的道具等全部通过在Spring配置文件中设置。下面是配置文件中英雄及战场的部分:
<!--10级角色引介-->
<bean id="superHeroIntroduction"
  class="springroad.demo.chap5.wow.SuperHeroIntroductionAdvisor" />
 
  <!--代理配置模板-->
 <bean id="baseHeroProxy"
  class="org.springframework.aop.framework.ProxyFactoryBean"
  abstract="true">
  <property name="proxyInterfaces"
   value="springroad.demo.chap5.wow.Hero" />
  <property name="interceptorNames">
   <list>
    <value>gameRecordAspect</value>
    <value>armorAspect</value>    
   </list>
  </property>
 </bean>
 <!--定义英雄-->
 <bean id="MK" parent="baseHeroProxy">
  <property name="target">
   <bean class="springroad.demo.chap5.wow.BaseHero">
    <constructor-arg value="60" />
    <property name="armor" value="2" />
    <property name="health" value="500" />
    <property name="name" value="Mountain King" />
    <property name="auraAndSkill">
     <list>
      <ref bean="bash" />
      <ref bean="scrollOfProtection" />
     </list>
    </property>
   </bean>
  </property>
 </bean>
 <bean id="POM" parent="baseHeroProxy">
  <property name="target">
   <bean class="springroad.demo.chap5.wow.BaseHero">
    <constructor-arg value="60" />
    <property name="armor" value="1" />
    <property name="health" value="500" />
    <property name="name" value="Priestess of the Moon" />
    <property name="auraAndSkill">
     <list>
      <ref bean="devotionAura" />
      <ref bean="scrollOftheBeast" />
      <ref bean="trueshotAura" />
     </list>
    </property>
   </bean>
  </property>
 </bean>
 <bean id="superHero" parent="baseHeroProxy">
  <property name="target">
   <bean class="springroad.demo.chap5.wow.BaseHero">
    <constructor-arg value="60" />
    <property name="armor" value="1" />
    <property name="health" value="500" />
    <property name="name" value="10级山丘之王" />
    <property name="auraAndSkill">
     <list>
      <ref bean="bash" />
      <ref bean="devotionAura" />
      <ref bean="scrollOftheBeast" />
      <ref bean="trueshotAura" />
     </list>
    </property>
   </bean>
  </property>
  <property name="interceptorNames">
   <list>
    <value>gameRecordAspect</value>
    <value>armorAspect</value>   
    <value>superHeroIntroduction</value>
   </list>
  </property>
 </bean>
 <bean id="WarField"
  class="org.springframework.aop.framework.ProxyFactoryBean">
  <property name="target">
   <bean class="springroad.demo.chap5.wow.WarField">
    <property name="heros">
     <set>
      <ref bean="MK" />
      <ref bean="POM" />
      <ref bean="superHero" />
     </set>
    </property>
   </bean>
  </property>
  <property name="interceptorNames">
   <list>
    <value>warAspect</value>
   </list>
  </property>
 </bean> 
 
  通过配置可以看出,通过使用引介让superHero(也即10级山丘之王)实现了SuperHero接口,这样使得概率出招成功的技能具有100%的出招成功率。
  比如,下面是重击技能的代码:
  
import java.util.Random;
//重击技能,具有20%的概率,可以增加英雄的攻击力20点,如果角色变为SuperHero,则重击100%成功
public class Bash implements AttackProp {
 private boolean haveHit;
 private Random random = new Random();
 public int getAttack(Hero hero) {
  if (bigHit() || (hero instanceof SuperHero)) {
   haveHit = true;
  } else {
   haveHit = false;
  }
  return (haveHit ? 20 : 0);
 }
 public boolean bigHit() {
  int rat = random.nextInt(10);
 // System.out.println(rat);
  return (rat <= 2);
 }
 public String toString() {
  return "重击技能," + (haveHit ? "伤害提高了20点" : "未使出来");
 }
}
  通过代码可以看出来,如果英雄是SuperHero(即10级角色),则出招成功率100%,否则只有20%多。SuperHero只是一个标识接口,内容如下:
  public interface SuperHero {
  }
 
  我们重点看看SuperHeroIntroductionAdvisor,这个引介就是让某一个现有的对象实现指定接口。代码如下示:
import org.springframework.aop.support.DefaultIntroductionAdvisor;
import org.springframework.aop.support.DelegatingIntroductionInterceptor;
public class SuperHeroIntroductionAdvisor extends DefaultIntroductionAdvisor {
 public SuperHeroIntroductionAdvisor() {
  super(new DelegatingIntroductionInterceptor(new SuperHero(){}), SuperHero.class);
 }
}
  现在我们来讨Spring AOP中引介的问题。假如我们的程序需要在Hero上有一个增强,然后通过Hero的实现BaseHero自身来发出技能,也即在BaseHero中包含调用Bash的代码,则该引介将会失效。这是因为当Hero自身调用的时候,已经不再是通过代理对象调用,而是通过目标对象Hero本身来调用,所有代理拦截都将失效,包括引介。
 
  假如你是在Hero之外的另外一个拦截中来调用Bash,也就是说想让一个引介外的拦截跟引介混合使用,则引介同样失效。由于引介的失效,所以造成Bash认不出来SuperHero角色,这就是为什么10级山丘之王的重击技能不能100%发出的原因。
 
  代理拦截引介实际上是代理类实现指定接口,并没有改变实际的类,比如不会因为superHero引入了SuperHero接口而对其它的Hero造成影响。另外注意的是,Spring AOP中的引介不能和任何切入点一起使用,因为它是应用在类级别而不是方法级别。
 
  确保是在代理对象上调用引介模块,而不是在目标对象。下面是修正后的山丘之王的作战记录:
 
log4j:WARN No appenders could be found for logger (org.springframework.core.CollectionFactory).
log4j:WARN Please initialize the log4j system properly.
[英雄名称:Mountain King,生命值:500,基本防御:2]
[英雄名称:Priestess of the Moon,生命值:500,基本防御:1]
[英雄名称:10级山丘之王,生命值:500,基本防御:1]
战斗开始......
第1回合:玩家[Mountain King]向[Priestess of the Moon]发动攻击![命中:失败]
第2回合:玩家[Priestess of the Moon]向[Mountain King]发动攻击![命中:成功]
生命值--[Priestess of the Moon:500]-[Mountain King:500]
基本伤害:60;英雄持有以下攻击道具:物品野兽卷轴,攻击增加了25%;强击光环技能,攻击力增加了10%;[实际攻攻击力:81]
Mountain King--基本护甲:2;物品保护卷轴,护甲增加了2点;[实际防御:4]
实际伤害点数:77
第3回合:玩家[10级山丘之王]向[Mountain King]发动攻击![命中:成功]
生命值--[10级山丘之王:500]-[Mountain King:423]
基本伤害:60;英雄持有以下攻击道具:重击技能,伤害提高了20点;物品野兽卷轴,攻击增加了25%;强击光环技能,攻击力增加了10%;[实际攻攻击力:101]
Mountain King--基本护甲:2;物品保护卷轴,护甲增加了2点;[实际防御:4]
实际伤害点数:97
第4回合:玩家[Mountain King]向[10级山丘之王]发动攻击![命中:成功]
生命值--[Mountain King:326]-[10级山丘之王:500]
基本伤害:60;英雄持有以下攻击道具:重击技能,伤害提高了20点;[实际攻攻击力:80]
10级山丘之王--基本护甲:1;专注光环技能,护甲增加了1点!;[实际防御:2]
实际伤害点数:78
第5回合:玩家[Priestess of the Moon]向[10级山丘之王]发动攻击![命中:失败]
第6回合:玩家[10级山丘之王]向[Mountain King]发动攻击![命中:失败]
第7回合:玩家[Mountain King]向[Priestess of the Moon]发动攻击![命中:成功]
生命值--[Mountain King:326]-[Priestess of the Moon:500]
基本伤害:60;英雄持有以下攻击道具:重击技能,未使出来;[实际攻攻击力:60]
Priestess of the Moon--基本护甲:1;专注光环技能,护甲增加了1点!;[实际防御:2]
实际伤害点数:58
第8回合:玩家[Priestess of the Moon]向[Mountain King]发动攻击![命中:失败]
第9回合:玩家[10级山丘之王]向[Mountain King]发动攻击![命中:成功]
生命值--[10级山丘之王:422]-[Mountain King:326]
基本伤害:60;英雄持有以下攻击道具:重击技能,伤害提高了20点;物品野兽卷轴,攻击增加了25%;强击光环技能,攻击力增加了10%;[实际攻攻击力:101]
Mountain King--基本护甲:2;物品保护卷轴,护甲增加了2点;[实际防御:4]
实际伤害点数:97
第10回合:玩家[Mountain King]向[Priestess of the Moon]发动攻击![命中:失败]
第11回合:玩家[Priestess of the Moon]向[Mountain King]发动攻击![命中:成功]
生命值--[Priestess of the Moon:442]-[Mountain King:229]
基本伤害:60;英雄持有以下攻击道具:物品野兽卷轴,攻击增加了25%;强击光环技能,攻击力增加了10%;[实际攻攻击力:81]
Mountain King--基本护甲:2;物品保护卷轴,护甲增加了2点;[实际防御:4]
实际伤害点数:77
第12回合:玩家[10级山丘之王]向[Priestess of the Moon]发动攻击![命中:成功]
生命值--[10级山丘之王:422]-[Priestess of the Moon:442]
基本伤害:60;英雄持有以下攻击道具:重击技能,伤害提高了20点;物品野兽卷轴,攻击增加了25%;强击光环技能,攻击力增加了10%;[实际攻攻击力:101]
Priestess of the Moon--基本护甲:1;专注光环技能,护甲增加了1点!;[实际防御:2]
实际伤害点数:99
第13回合:玩家[Mountain King]向[Priestess of the Moon]发动攻击![命中:成功]
生命值--[Mountain King:152]-[Priestess of the Moon:343]
基本伤害:60;英雄持有以下攻击道具:重击技能,未使出来;[实际攻攻击力:60]
Priestess of the Moon--基本护甲:1;专注光环技能,护甲增加了1点!;[实际防御:2]
实际伤害点数:58
第14回合:玩家[Priestess of the Moon]向[10级山丘之王]发动攻击![命中:成功]
生命值--[Priestess of the Moon:285]-[10级山丘之王:422]
基本伤害:60;英雄持有以下攻击道具:物品野兽卷轴,攻击增加了25%;强击光环技能,攻击力增加了10%;[实际攻攻击力:81]
10级山丘之王--基本护甲:1;专注光环技能,护甲增加了1点!;[实际防御:2]
实际伤害点数:79
第15回合:玩家[10级山丘之王]向[Priestess of the Moon]发动攻击![命中:成功]
生命值--[10级山丘之王:343]-[Priestess of the Moon:285]
基本伤害:60;英雄持有以下攻击道具:重击技能,伤害提高了20点;物品野兽卷轴,攻击增加了25%;强击光环技能,攻击力增加了10%;[实际攻攻击力:101]
Priestess of the Moon--基本护甲:1;专注光环技能,护甲增加了1点!;[实际防御:2]
实际伤害点数:99
第16回合:玩家[Mountain King]向[10级山丘之王]发动攻击![命中:失败]
第17回合:玩家[Priestess of the Moon]向[10级山丘之王]发动攻击![命中:成功]
生命值--[Priestess of the Moon:186]-[10级山丘之王:343]
基本伤害:60;英雄持有以下攻击道具:物品野兽卷轴,攻击增加了25%;强击光环技能,攻击力增加了10%;[实际攻攻击力:81]
10级山丘之王--基本护甲:1;专注光环技能,护甲增加了1点!;[实际防御:2]
实际伤害点数:79
第18回合:玩家[10级山丘之王]向[Mountain King]发动攻击![命中:失败]
第19回合:玩家[Mountain King]向[Priestess of the Moon]发动攻击![命中:成功]
生命值--[Mountain King:152]-[Priestess of the Moon:186]
基本伤害:60;英雄持有以下攻击道具:重击技能,伤害提高了20点;[实际攻攻击力:80]
Priestess of the Moon--基本护甲:1;专注光环技能,护甲增加了1点!;[实际防御:2]
实际伤害点数:78
第20回合:玩家[Priestess of the Moon]向[Mountain King]发动攻击![命中:失败]
第21回合:玩家[10级山丘之王]向[Mountain King]发动攻击![命中:成功]
生命值--[10级山丘之王:264]-[Mountain King:152]
基本伤害:60;英雄持有以下攻击道具:重击技能,伤害提高了20点;物品野兽卷轴,攻击增加了25%;强击光环技能,攻击力增加了10%;[实际攻攻击力:101]
Mountain King--基本护甲:2;物品保护卷轴,护甲增加了2点;[实际防御:4]
实际伤害点数:97
第22回合:玩家[Mountain King]向[Priestess of the Moon]发动攻击![命中:成功]
生命值--[Mountain King:55]-[Priestess of the Moon:108]
基本伤害:60;英雄持有以下攻击道具:重击技能,伤害提高了20点;[实际攻攻击力:80]
Priestess of the Moon--基本护甲:1;专注光环技能,护甲增加了1点!;[实际防御:2]
实际伤害点数:78
第23回合:玩家[Priestess of the Moon]向[Mountain King]发动攻击![命中:成功]
生命值--[Priestess of the Moon:30]-[Mountain King:55]
基本伤害:60;英雄持有以下攻击道具:物品野兽卷轴,攻击增加了25%;强击光环技能,攻击力增加了10%;[实际攻攻击力:81]
Mountain King--基本护甲:2;物品保护卷轴,护甲增加了2点;[实际防御:4]
实际伤害点数:77
英雄 Mountain King 挂了
第24回合:玩家[10级山丘之王]向[Priestess of the Moon]发动攻击![命中:成功]
生命值--[10级山丘之王:264]-[Priestess of the Moon:30]
基本伤害:60;英雄持有以下攻击道具:重击技能,伤害提高了20点;物品野兽卷轴,攻击增加了25%;强击光环技能,攻击力增加了10%;[实际攻攻击力:101]
Priestess of the Moon--基本护甲:1;专注光环技能,护甲增加了1点!;[实际防御:2]
实际伤害点数:99
英雄 Priestess of the Moon 挂了

最终胜利者:10级山丘之王

posted @ 2006-11-03 03:50 笨蛋啊帆 阅读(166) | 评论 (0)编辑 收藏

郁闷,攻击力那么强,但在群P中,10级的山丘之王总是被先挂掉。好多次了,都是这样!下面是输出的战斗日志:

[英雄名称:Mountain King,生命值:500,基本防御:2]
[英雄名称:Priestess of the Moon,生命值:500,基本防御:1]
[英雄名称:10级山丘之王,生命值:500,基本防御:1]
战斗开始......
第1回合:玩家[Mountain King]向[Priestess of the Moon]发动攻击![命中:失败]

第2回合:玩家[Priestess of the Moon]向[10级山丘之王]发动攻击![命中:成功]
生命值--[Priestess of the Moon:500]-[10级山丘之王:500]
基本伤害:60;英雄持有以下攻击道具:物品野兽卷轴,攻击增加了25%;强击光环技能,攻击力增加了10%;[实际攻攻击力:81]
10级山丘之王基本护甲:1;专注光环技能,护甲增加了1点!;[实际防御:2]
实际伤害点数:79

第3回合:玩家[10级山丘之王]向[Priestess of the Moon]发动攻击![命中:成功]
生命值--[10级山丘之王:421]-[Priestess of the Moon:500]
基本伤害:60;英雄持有以下攻击道具:重击技能,未使出来;物品野兽卷轴,攻击增加了25%;强击光环技能,攻击力增加了10%;[实际攻攻击力:81]
Priestess of the Moon基本护甲:1;专注光环技能,护甲增加了1点!;[实际防御:2]
实际伤害点数:79

第4回合:玩家[Mountain King]向[10级山丘之王]发动攻击![命中:成功]
生命值--[Mountain King:500]-[10级山丘之王:421]
基本伤害:60;英雄持有以下攻击道具:重击技能,未使出来;[实际攻攻击力:60]
10级山丘之王基本护甲:1;专注光环技能,护甲增加了1点!;[实际防御:2]
实际伤害点数:58

第5回合:玩家[Priestess of the Moon]向[10级山丘之王]发动攻击![命中:成功]
生命值--[Priestess of the Moon:421]-[10级山丘之王:363]
基本伤害:60;英雄持有以下攻击道具:物品野兽卷轴,攻击增加了25%;强击光环技能,攻击力增加了10%;[实际攻攻击力:81]
10级山丘之王基本护甲:1;专注光环技能,护甲增加了1点!;[实际防御:2]
实际伤害点数:79

第6回合:玩家[10级山丘之王]向[Priestess of the Moon]发动攻击![命中:成功]
生命值--[10级山丘之王:284]-[Priestess of the Moon:421]
基本伤害:60;英雄持有以下攻击道具:重击技能,未使出来;物品野兽卷轴,攻击增加了25%;强击光环技能,攻击力增加了10%;[实际攻攻击力:81]
Priestess of the Moon基本护甲:1;专注光环技能,护甲增加了1点!;[实际防御:2]
实际伤害点数:79

第7回合:玩家[Mountain King]向[10级山丘之王]发动攻击![命中:成功]
生命值--[Mountain King:500]-[10级山丘之王:284]
基本伤害:60;英雄持有以下攻击道具:重击技能,未使出来;[实际攻攻击力:60]
10级山丘之王基本护甲:1;专注光环技能,护甲增加了1点!;[实际防御:2]
实际伤害点数:58

第8回合:玩家[Priestess of the Moon]向[10级山丘之王]发动攻击![命中:失败]

第9回合:玩家[10级山丘之王]向[Priestess of the Moon]发动攻击![命中:失败]

第10回合:玩家[Mountain King]向[Priestess of the Moon]发动攻击![命中:成功]
生命值--[Mountain King:500]-[Priestess of the Moon:342]
基本伤害:60;英雄持有以下攻击道具:重击技能,伤害提高了20点;[实际攻攻击力:80]
Priestess of the Moon基本护甲:1;专注光环技能,护甲增加了1点!;[实际防御:2]
实际伤害点数:78

第11回合:玩家[Priestess of the Moon]向[10级山丘之王]发动攻击![命中:成功]
生命值--[Priestess of the Moon:264]-[10级山丘之王:226]
基本伤害:60;英雄持有以下攻击道具:物品野兽卷轴,攻击增加了25%;强击光环技能,攻击力增加了10%;[实际攻攻击力:81]
10级山丘之王基本护甲:1;专注光环技能,护甲增加了1点!;[实际防御:2]
实际伤害点数:79

第12回合:玩家[10级山丘之王]向[Priestess of the Moon]发动攻击![命中:失败]

第13回合:玩家[Mountain King]向[10级山丘之王]发动攻击![命中:成功]
生命值--[Mountain King:500]-[10级山丘之王:147]
基本伤害:60;英雄持有以下攻击道具:重击技能,伤害提高了20点;[实际攻攻击力:80]
10级山丘之王基本护甲:1;专注光环技能,护甲增加了1点!;[实际防御:2]
实际伤害点数:78

第14回合:玩家[Priestess of the Moon]向[Mountain King]发动攻击![命中:失败]

第15回合:玩家[10级山丘之王]向[Priestess of the Moon]发动攻击![命中:失败]

第16回合:玩家[Mountain King]向[10级山丘之王]发动攻击![命中:成功]
生命值--[Mountain King:500]-[10级山丘之王:69]
基本伤害:60;英雄持有以下攻击道具:重击技能,未使出来;[实际攻攻击力:60]
10级山丘之王基本护甲:1;专注光环技能,护甲增加了1点!;[实际防御:2]
实际伤害点数:58

第17回合:玩家[Priestess of the Moon]向[Mountain King]发动攻击![命中:成功]
生命值--[Priestess of the Moon:264]-[Mountain King:500]
基本伤害:60;英雄持有以下攻击道具:物品野兽卷轴,攻击增加了25%;强击光环技能,攻击力增加了10%;[实际攻攻击力:81]
Mountain King基本护甲:2;物品保护卷轴,护甲增加了2点;[实际防御:4]
实际伤害点数:77

第18回合:玩家[10级山丘之王]向[Priestess of the Moon]发动攻击![命中:成功]
生命值--[10级山丘之王:11]-[Priestess of the Moon:264]
基本伤害:60;英雄持有以下攻击道具:重击技能,未使出来;物品野兽卷轴,攻击增加了25%;强击光环技能,攻击力增加了10%;[实际攻攻击力:81]
Priestess of the Moon基本护甲:1;专注光环技能,护甲增加了1点!;[实际防御:2]
实际伤害点数:79

第19回合:玩家[Mountain King]向[10级山丘之王]发动攻击![命中:成功]
生命值--[Mountain King:423]-[10级山丘之王:11]
基本伤害:60;英雄持有以下攻击道具:重击技能,未使出来;[实际攻攻击力:60]
10级山丘之王基本护甲:1;专注光环技能,护甲增加了1点!;[实际防御:2]
实际伤害点数:58
英雄 10级山丘之王 挂了

第20回合:玩家[Priestess of the Moon]向[Mountain King]发动攻击![命中:成功]
生命值--[Priestess of the Moon:185]-[Mountain King:423]
基本伤害:60;英雄持有以下攻击道具:物品野兽卷轴,攻击增加了25%;强击光环技能,攻击力增加了10%;[实际攻攻击力:81]
Mountain King基本护甲:2;物品保护卷轴,护甲增加了2点;[实际防御:4]
实际伤害点数:77


第21回合:玩家[Mountain King]向[Priestess of the Moon]发动攻击![命中:成功]
生命值--[Mountain King:346]-[Priestess of the Moon:185]
基本伤害:60;英雄持有以下攻击道具:重击技能,未使出来;[实际攻攻击力:60]
Priestess of the Moon基本护甲:1;专注光环技能,护甲增加了1点!;[实际防御:2]
实际伤害点数:58

第22回合:玩家[Priestess of the Moon]向[Mountain King]发动攻击![命中:失败]

第23回合:玩家[Mountain King]向[Priestess of the Moon]发动攻击![命中:失败]

第24回合:玩家[Priestess of the Moon]向[Mountain King]发动攻击![命中:成功]
生命值--[Priestess of the Moon:127]-[Mountain King:346]
基本伤害:60;英雄持有以下攻击道具:物品野兽卷轴,攻击增加了25%;强击光环技能,攻击力增加了10%;[实际攻攻击力:81]
Mountain King基本护甲:2;物品保护卷轴,护甲增加了2点;[实际防御:4]
实际伤害点数:77

第25回合:玩家[Mountain King]向[Priestess of the Moon]发动攻击![命中:成功]
生命值--[Mountain King:269]-[Priestess of the Moon:127]
基本伤害:60;英雄持有以下攻击道具:重击技能,伤害提高了20点;[实际攻攻击力:80]
Priestess of the Moon基本护甲:1;专注光环技能,护甲增加了1点!;[实际防御:2]
实际伤害点数:78

第26回合:玩家[Priestess of the Moon]向[Mountain King]发动攻击![命中:成功]
生命值--[Priestess of the Moon:49]-[Mountain King:269]
基本伤害:60;英雄持有以下攻击道具:物品野兽卷轴,攻击增加了25%;强击光环技能,攻击力增加了10%;[实际攻攻击力:81]
Mountain King基本护甲:2;物品保护卷轴,护甲增加了2点;[实际防御:4]
实际伤害点数:77

第27回合:玩家[Mountain King]向[Priestess of the Moon]发动攻击![命中:成功]
生命值--[Mountain King:192]-[Priestess of the Moon:49]
基本伤害:60;英雄持有以下攻击道具:重击技能,未使出来;[实际攻攻击力:60]
Priestess of the Moon基本护甲:1;专注光环技能,护甲增加了1点!;[实际防御:2]
实际伤害点数:58
英雄 Priestess of the Moon 挂了

 

最终胜利者:Mountain King

posted @ 2006-11-03 03:50 笨蛋啊帆 阅读(282) | 评论 (0)编辑 收藏

Java程序员必读的十本书
作者:Kevin Taylor
来自:Focus on Java
原文:http://java.about.com/od/advancedjava/tp/mustreadjava.htm

Kevin Taylor对Java书籍的推荐,关于并发的书籍我在书店里好像没看到过。在Web方面只有Java Servlet Programming登场,JSP等并没有提到。开发工具方面也没有一本,这是我觉得比较可惜的。


1. 《Thinking in Java》(Java编程思想)
作者:Bruce Eckel
Eckel将幽默、实践性强的实例和编程的思想融入书中。这本书全面的介绍了Java语言及其核心的API。尽管这本书面向的是初学者,但他的大部分章节仍对有经验的程序员有益处,特别是面向对象编程方面的知识。

2. 《Java in a Nutshell》
作者:David Flanagan
这本书是对有经验的程序员经典的初级读本。它以简捷的Java编程语言为开头。然后深入的介绍了大部分重要的Java API类。这本书包括了很多有用的程序片断,例如Strings、Collections、I/O等。

3. 《Effective Java Programming Language Guide》 (Java高效编程指南)
作者:Joshua Bloch
在你写过一些Java程序后,这本书就适合你了。它包括了中高级的编程思想,例如创建和销毁对象最好的办法,有些的重载equals()和hashcode(),检查相对尚未检查的异常,等等。这本书可能是最好的Java书籍。

4. 《Java Examples in a Nutshell》
作者:David Flanagan
这本书补充了《Java in a Nutshell》遗漏的部分。它提供了对API Class简练的实例。如果你想学习如何开发一个Swing GUI程序,执行JDBC查询语句,加密信用卡密码,解析XML文档等等,这本书里都可以找到答案。浏览很多实用的例子是探究Java API的一条很好的途径。

5. 《Swing, Second Edition》
作者:Pavel Vorobiev, Matthew Robinson
Swing是Java程序主要的GUI工具。这本书可说是Swing方面的圣经,它包括了一个教程和一份为高级Swing开发者准备的参考资料。它不是一本介绍性的书。但是如果你大部分是写MVC、用户界面设计、事件处理,这本书就是你应该读的。

6. 《Java Servlet Programming, 2nd Edition》
作者:Jason Hunter
这本书是Java Web程序方面的经典书籍。这本书包括了所有一般Web程序遇到的问题的代码实例,包括输入处理,接受上传文件,与数据库的通讯等。

7. 《Enterprise JavaBeans》
作者:Richard Monson-Haefel
虽然J2EE包括了很多东西,而不仅仅是EJB,但EJB是J2EE规范下主要的力量。这本书将简明地展示每一样你需要知道的关于EJB各种不同部分。不论你是否计划使用EJB,你都需要知道这项重要的技术。

8. 《Expert One-on-One J2EE Development without EJB》
作者:Rod Johnson, Juergen Hoeller
这本书是没有EJB的J2EE开发方面的权威书籍。 作者展示了如何使用流行的、轻量级的构架和object-relational mapping工具,来脱离复杂的EJB而让企业级程序更好。

9. 《Concurrency: State Models & Java Programs》
作者:Jeff Magee, Jeff Kramer
多线程编程是一个高级的主题,但是Java允许任何程序员产生线程。这本书在建模和实现并发程序上提供了一个坚实的理论与实践的基础。

10. 《Concurrent Programming in Java》
作者:Doug Lea
当你明白实现线程的语法后,读这本书将会学到如何正确有效地使用它。它深入的介绍了并发与平行编程。

posted @ 2006-11-03 03:44 笨蛋啊帆 阅读(160) | 评论 (0)编辑 收藏

Language Oriented Programming : The Next Programming Paradigm

Sergey Dmitriev, JetBrains

 

现在是软件开发中开始下一次技术革命的时候了,而这次革命的轮廓正变得越来越清晰。下一代编程范型也在接近我们,但仍然没有完全成形--不同的部分有不同的名称:Intentional programming, MDA, generative programming, 等等;我建议把把所有这些新方法归并为一个名字: ‘language-oriented programming’(面向语言的编程), 而本文将阐述这种新的编程范型的主要原则

今天主流的编程方法有一些内在的假定像脖子上的绳索一样桎梏着我们,尽管大部分程序员还没有意识到它;即使算上在编程领域取得的所有进步,我们也仍然处于石器时代;我们有我们信赖的石斧(面向对象编程),能够满足我们的需要,但是当用它来对付最困难的问题时,它会裂成碎屑;为了超越石器前进,我们必须驯服烈火,只有这样,我们才能铸造出新的工具,激发一个创作的新时代,和新技术的爆发

我将讨论编程的局限,它强迫程序员像计算机一样思考,而不是令计算机像程序员一样思考;这是严重的,根深蒂固的局限,需要花费巨大的努力去克服它;当我说这将是编程中下一个大的范型转换时我并没有自命不凡;我们需要彻底重新定义我们编写程序的方法

本文中,我表述了我的观点和我当前在Language Oriented Programming (LOP)上的工作;首先我将展示目前主流编程方法的错误,然后我会使用示例来解释LOP的概念,它们基于我已有的一个LOP的实现:the Meta Programming System (MPS). 本文有意只是给你一个对LOP的惊鸿一瞥,目的是激发你对这个思想的兴趣,并希望能够得到反馈和讨论

Part I. LANGUAGE ORIENTED PROGRAMMING OVERVIEW

Language Oriented Programming and the Meta Programming System

理想的,做一个程序员意味着我可以对计算机做任何事情,我有完全的自由,完全的控制;但实际上,今天的程序员只有非常受限的自由;当然,我确实可以在计算机上做任何事情,但其中一些事情花费了我许多年的努力,而它们实际上只需要少的多的时间;一定有什么事情不对劲

程序员被限制是因为他们深深依赖于那些他们不能轻易改变的编程基础设施:编程语言和开发环境;如果我需要一些语言的扩展,我只能等待语言的设计者去更新它;如果我需要我的IDE有一些额外的强大功能,我只能等待供应商来添加新特性;就是这些依赖限制了我完全的自由;当然,我可以写我自己的编译器和IDE,实际上,这也是我启动了IntelliJ IDEA的原因,因为我厌倦了依赖现有的弱弱的Java IDE;但是,这会花费大量的时间和努力,并且显而易见,对大部分程序员来说是不可行的;理论上的自由和实际的自由之间存在巨大的差异;下文中当我谈到自由时,我指的是实际的自由

获得自由的途径是减少我们的依赖层次;例如,Java的一个主要目标是减少对操作系统的依赖,给开发者在不同操作系统上部署的自由;因此,为了在语言和环境之上获得自由,我们需要减少对它们的依赖

为什么这是一个问题呢?任何general-purpose的语言,像Java和C++,给了我们用计算机做任何事情的能力;这是事实,至少理论上是这样,但是,general-purpose的语言趋向于如同后面我将讲到的般生产效率低下;作为一种替代,我们可以使用domain-specific languages(DSLs,aka ‘little languages’),它们被精心设计成在特定问题域具有高度生产率,比如用SQL编写数据库查询;DSLs的强大之处,领域相关,也正是它们的弱处,因为任何真实世界中的程序都会包括许多不同的领域

general-purpose 和 domainspecific 之间,并不是对立的;我需要所有的自由,我希望能够做任何事情,同时有很高的生产效率;目前为止还没有什么好方法能够做到这点;理想情况下,我能够为程序的各个特定部分使用不同的语言,而它们能够融洽的一起工作,并且开发环境会完全支持这些语言,包括重构,代码补全,导航,以及主流语言具有的所有其它生产力工具

为了获得这种独立性,我需要有创建、重用、修改语言和环境的自由;为了使这种自由是可行的,它需要很容易的被获得;如果我们解决了易于进行语言和环境的开发的问题,对程序员来说将是一个巨大的进步;这就是Language Oriented Programming的切入点

要理解Language Oriented Programming是什么,让我们首先看一下今天的主流编程方法,它基本上是这样:

思考: 你需要编程解决一个问题,因此你在你的头脑里形成了如何解决这个问题的概念模型

选择: 你选择了某种general-purpose的语言来编写解决方案

编程: 你通过将你的概念模型艰难的映射到编程语言来编写解决方案

编程这一步是瓶颈所在,因为大部分情况映射不是容易的和自然的;这种方法在程序员表达复杂的设计方面已经被证明是低效的;相对的,下面是LOP的工作方式:

思考: 你需要编程解决一个问题,因此你在你的头脑里形成了如何解决这个问题的概念模型

选择: 你选择了某些特定的DSLs来编写解决方案

创建: 如果没有合适的DSL适合你的问题,你便创建一种DSL来适应你的问题

编程: 你通过将你的概念模型相对直接的映射到DSLs来编写解决方案

现在,编程这一步is much less of a 瓶颈了,因为DSLs大大简化了如何将问题翻译成某种计算机能够理解的东西;看起来困难已经简单的转移到了“创建”这一步,然而,通过联合使用工具支持和将LOP应用到自身,将使这一步更加简单

LOP 背后的动机基本是这样的:我想用我正试图解决的问题相关的概念和意图的词汇来工作,而不是被迫将我的思想翻译成某种general-purpose的语言所能理解的概念(比如:类,方法,循环,条件,等等...);为了达到这个目标,我需要使用domain-specific languages;怎样得到它们呢?创建它们;

我已经开始开发一个通用的平台(the Meta Programming System)来设计domainspecific languages,带有工具支持和开发环境;它将允许程序员像现在编写程序一样容易的来定义语言;这个平台将完全支持LOP,给程序员为程序的每一部分选择使用最合适的语言的自由,而不是将他们绑在某种固定的general-purpose的编程语言上

MPS 只是Language Oriented Programming的一个示例,尽管我在这里使用MPS来做示例,而实际上LOP可以用许多不同的方法来实现,你自己就可能知道一些替代方法;LOP 的概念不等同于它的实现,就像OOP的概念不等同于Java或C++或Smalltalk一样

What Is Wrong with Mainstream Programming

你知道这则古老的谚语:"If it ain't broke, don't fix it". 主流编程方法很明显不完整,我见过它带来的很多问题,而大部分滋生于这样一个事实:general-purpose的语言没有一种方法来完全支持任意的领域,同样也没有一种统一的domain-specific language;下面是将被LOP解决的主流编程中三个最糟糕的问题:

Time Delay to Implement Ideas

对我来说,最严重的问题是,在我确切的知道如何解决一个问题,和我通过一个程序成功的向计算机传达解决方案之间,有一个很长的时间差;我可以用几个小时的时间向另外的程序员解释问题和解决方案,而将解决方案编码到计算机中将花费长的多的时间;这是因为对另外的程序员,我可以使用表达能力非常丰富的自然语言,而对计算机,我只能使用某种表达能力差很多的general-purpose的编程语言;今天的编程语言只能表达几十种概念,而自然语言能够简洁的表达千万种概念;因此,向另外的程序员解释问题,我可以表达很高层的思想,而对计算机,我必须表达每一步的每一个细节

在主流编程中,大部分花在“编程”上的时间,实际上是在寻找用编程层次的抽象的术语来表达自然语言的概念的方法,而这是很困难的,没多少创造性的,或多或少是一种时间的浪费

举个例子,今天大量的开发时间花费在面向对象的设计(OOD)上,在程序员表达类、继承、关联等方面这确实是一种还算有创造性的过程;这项实践的目的是用面向对象的术语,如类和方法,来表达程序;OOD的过程是必要的,因为诸如类和方法等是面向对象语言能够理解的仅有的抽象,它看起来是必要和有创造性的,但是使用Language Oriented Programming,OOD根本就不需要

Understanding and Maintaining Existing Code

下一个问题是理解和维护现存代码;不管它是另一个程序员写的还是我写的,问题都一样;因为general-purpose的语言需要我把高层的领域概念翻译为低层的编程语言特性,在最终的程序中,很多高度概括的视角、蓝图都丢失了;当我在以后重新翻阅程序时,我不得不通过逆向工程来了解我最初的意图是什么,我头脑中的模型是什么;至少,我必须在脑海中重新建造最初在翻译到general-purpose的编程语言的过程中丢失的信息

解决这个问题的传统方法是写注释或其它形式的文档来记录设计信息和模型信息,已经有几个方面的因素证明了这是一种脆弱的解决方案,至少包括编写这些辅助文档的成本、以及文档和代码逐渐不同步的趋势;并且,还有一个没被广泛认识到的事实,就是文档并不能直接连接到它所记录的概念;注释和源代码被绑定到同一个地方,但是概念可能在源代码的多个地方被表达;其它类型的文档彻底从源代码中分离出来,只能间接的引用源代码;理想情况下,代码应该是自我描述的,我应该只阅读代码本身来理解代码,而不是什么注释和外部的文档

Domain Learning Curve

第三个主要的问题是对语言进行领域相关的扩展;例如,在OOP中扩展语言的主要方法是使用类库;问题是类库不是用领域概念相关的术语来表达的,而是用低层的 general-purpose的抽象诸如类和方法等来表达;因此,库很少能够直接表述领域概念,它们必须引入额外的枝节(如一个类的运行时行为)来完成到领域概念的映射;两个很好的常见例子是GUI库和Database库

学习这些类库不是一项简单的任务,即使你是个领域专家;因为从领域到语言的映射不是直接的,你必须学习这种映射;这意味着一个陡峭的学习曲线;通常我们试图用大量的指南和文档来解决这个问题,但是学习这些将花费大量时间;当一个类库变得复杂的时候,它也变得更难以学习,程序员将因此失去学习它的动机

甚至当掌握了这种复杂的映射之后,依然还会很容易的误用类库,因为开发环境(像编译器和编辑器)不能帮助你正确的使用类库,对这些工具来说,调用一个GUI 对象的方法和调用一个DB对象的方法是一样的:它们都只是对象上的方法调用,没有任何更多的意思;记住哪些类和方法应该被调用,以什么顺序被调用,等等,都是使用者的责任

甚至即使你既是领域专家又是类库的使用专家,也仍然有使用类库编写的程序十分冗长的问题;相对简单的领域概念需要复杂的措施来正确的调用;例如,任何用过Swing的开发者都清楚这一点;编写简单的程序就已经花费太长的时间了,复杂的程序甚至更糟

Details of LOP

What Is a Program in LOP?

今天,百分之九十九的程序员认为编程就是编写一串计算机能够执行的指令集;我们被教育说计算机建立在图灵机模型之上,因此它们用指令集的术语来“思考”;但是这种编程的观点是有缺陷的,它混淆了编程的目的和手段;我将为你演示LOP为什么优于传统编程方法,但首先我必须澄清以下事实:一个LOP的程序,不是一串指令集;那么它是什么呢?

当我有一个问题要解决,我在头脑中思考解决方案,这个解决方案用单词、标记、概念、思想,或者任何你喜欢的称呼来表述,它是我头脑中如何解决问题的模型;我几乎从未把它们想象成一堆指令集,而是我正在工作的领域中特定的具有内在联系的概念的集合;例如,当我思考GUI领域时,我想象“这个按钮到那边去,这个输入域到这边来,这个组合框里面需要有一些数据的列表”;我甚至只是在头脑中把它画出来,根本不用任何言语

我之所以认为这种意念模型是一种解决方案是因为我能够用足够的细节向另一个程序员解释这个模型,使他能够坐下来编写一个解决这个问题的程序(比如用 Java);我不需要非得用编程语言的术语来解释这个方案,它可以是任意形式;比如,为了解释如何布局一个GUI的窗体,我只需要画出这个窗体;如果绘画有足够的细节,绘画本身就代表了解决方案;这种领域相关的表述应该就是程序。换句话说,应该有一种方法允许我们使用这种表述作为真正的程序,而不仅仅是与其它程序员交流的手段;于是这便导出了我对程序非正式的定义:一个程序是任何对一个问题无歧义的解决方案,或者,更精确一点:一个程序是对某个领域的某个问题的解决方案的任何使用领域相关概念表达的,精确定义的模型

这就是我认为程序员应该拥有创建他们自己的语言的自由的主要原因:这样他们就能够用更加自然的形式来表达解决方案;General-purpose的语言是无歧义的,但是太冗余和易于出错;自然语言(如英语)表达能力十分丰富,但目前它难以使用因为它太不精确太不形式化了;我们需要能够容易的创建形式化的,精确定义的,领域相关的语言;因此Language Oriented Programming将不只是编写程序,还包括创建用来编写程序的语言;我们的程序将被编写的更接近问题域而不是计算机指令集领域,因此它们将非常容易的被编写

Programs and Text

人们习惯性的认为程序是作为文本来存储的,也就是说,一个字节流;为什么不应该是呢?毕竟有无数的工具来编辑、显示、操作文本;今天的编程语言的核心部分是文法器,解析器,编译器和面向行的调试器;但是程序的文本只是程序的一种表现形式;程序不是文本;强行把程序塞到文本里引起了大量你可能还不知道的问题;我们需要一种不同的方法来存储并和我们程序一起工作

当编译器编译源代码时,它把文本解析成称作抽象语法树的树状结构;当程序员阅读源代码时,他们在脑海中做了本质上相同的事情;我们仍然不得不考虑程序的树状结构;这就是为什么我们要有花括号,方括号,圆括号等;这也是为什么我们需要格式化和缩进代码和遵守编码规范,因为这样就能够更容易的阅读源代码

我们为什么使用文本存储呢?因为当前,阅读和编辑程序最方便和最通用的方法还是使用文本编辑器;但是我们会为此付出代价,因为程序的文本表示有重大的缺点,其中最重要的是基于文本的编程语言非常难于扩展;如果程序以文本的形式存储,你就会需要一个无歧义的文法器来解析程序;当为语言加入新特性时,维护语言无二义性的扩展变得日益困难;我们将需要发明更多类型的括号、操作符、关键字、顺序规则、嵌套,等等;语言的设计者们花费了无数时间来思考语法,并试图发现扩展语言的新方法

如果我们打算让创建语言变得容易,我们就需要将程序的表示和存储从程序本身分离开;我们应该直接将程序存为结构图,因为这允许我们对语言做任何我们喜欢的扩展;有时,我们甚至根本不需要考虑文本存储;今天的一个很好的例子是Excel spreadsheet.百分之九十九的人根本不需要处理存储格式,当这成为问题时总会有各种导入导出功能可用;今天我们使用文本的真正原因是我们没有比文本编辑器更好的编辑器,但是我们可以改变这一点

问题是文本编辑器很愚蠢,并且不知道如何与程序的图状结构一起工作;但是使用正确的工具,编辑器将能够直接和图状结构一起工作,并且能够让我们自由的使用任何编辑器提供的我们喜欢的可视化表现形式;我们可以把程序做成文本、表、图、树、或其它任何形式;我们甚至能为不同目的使用不同的表现形式,比方说,图形化表示用来浏览,文本化表示用来编辑;我们能够为代码的不同部分使用领域相关的表示,比如为数学公式使用图形化的数学符号,为图表使用图形化的图表,为 spreadsheets使用行和列,等等;我们能够为问题域使用最合适的表现形式,可以是文本,但不限于文本;最好的表现形式依赖于我们如何思考问题域;表现形式的灵活性也将使我们的编辑器比以往更加强大,因为不同的表现形式有不同的方式去编辑它们

What Is a Language in LOP?

最后,我应该阐明我认为的“语言”是什么;在LOP中,一种语言是通过三个主要的要素来定义的:结构、编辑器、和语义;结构定义了抽象语法、支持的概念、以及如何安排它们;编辑器定义了具体的语法,如何描绘和编辑语言;语义定义了行为,它如何被解释,和/或它如何被转换成可执行代码;当然,语言还可以有其它方面,比如约束和类型系统

Part II. INTRODUCTION TO META PROGRAMMING SYSTEM

Creating Languages in MPS

我已经解释了为什么我们需要容易的创建新的语言,但是,我们如何才能让它容易呢?如果你turn around这个问题,并且把Language Oriented Programming应用于它自身,你会很快看到答案;This calls for a little self-referential bootstrapping, which can seem tricky, but be patient. 一旦你理解了这个,你将得到LOP真正的力量(一个LOP的元层次)

回顾一下LOP的理念:使创建DSLs更容易,而这些DSLs将使编写程序更容易;但就像我已经说明的,LOP中的‘程序’不局限的意味着你用过的典型的 “一堆指令集”的程序;对某个领域中某个问题任何无二义性的解决方案都是‘程序’;因此如果你设想一下“创建新语言”这个领域,那么这个领域中的‘程序 ’,本身就是一种新语言的定义,可以作为一个解决方案来思考,就像任何其它领域的解决方案一样;

因此,应用LOP的思想,使“创建新语言”更容易的方法,就是创建一种特定的专注于“创建新语言”这个领域的DSL;通过应用这些language- building DSL,我们可以使制造新语言更容易;让我们看几种language-building语言的例子,使你更好的理解它们是如何工作的;这里只是一个概述,以后的文章我会更详细的描述它们

Structure Language

最小最少,我们需要定义新语言的‘结构’;这是我们何以能够编写“精确定义”的程序的原因;语言的结构并不意味着它的文本形式的文法--像我提到过的,这种语言甚至根本就没有文本表示而只有图形化表示

在实践LOP的时候,大部分情况下,你会工作在两个层次的编程中:元层次和程序层次;你在元层次中定义语言,在程序层次中编写程序;当定义一种新语言的结构时,你会使用一种language-structure DSL来定义你的新语言,而这时,你将同时工作在这种language-structure DSL的程序层次和新语言的元层次中

在MPS 中,程序层次的每个节点都有一种“类型”,简单的连接到元层次的另一个节点;程序层次的这个节点被称作这种类型的一个“实例”;元层次中的“类型”节点则定义了这种类型的实例能够拥有的关系和属性;描述这种元层次语言结构的语言,就被简单的称为“Structure Language”

用Structure Language定义一种语言的抽象语法,你应该只是枚举这种语言所有的类型;类型简单的表示了这种语言支持的特性或者概念;每个概念应该用它的名字、实例的内部属性、实例与其它节点之间的关系(通常是连接)来定义

存在两种可能的关联;第一种是类似聚合的关联,它形成了概念模型的父子树结构;第二种是非聚合的,自由形式的关联,它可以连接到系统中任何其它的节点;关联有两个端点:源和目标;关联有角色,你可以定义每个角色的名称、每个端点的多重性,每个目标节点的类型;多重性可以是1, 0..1, 0..n, 1..n等,让你能够约束关联可以创建多少连接;关联的目标类型可以被用来约束哪些类型的节点可以被连接在一起

因此,使用新语言编写程序包括:创建语言中概念的实例、为实例的属性赋值、根据语言概念定义的关系将程序中的节点连接在一起;所有这些将会被强大的编辑器支持,你能够为你的语言定义这种编辑器

Editor Language

那么,编写和操作概念模型的界面应该是什么呢?我们的语言需要几种类型的编辑器,但是我们不想要一个通用的编辑器;经验表明通用的编辑器不能像我们希望的那样有用;我们希望快速的编写模型,因此我们需要专为我们的语言概念定做的特殊的编辑器;一定程度上,编辑器是语言的一部分,而我们的目标是容易的创建新语言,那么创建新的编辑器也应该很容易;本质上,我们需要一种创建编辑器的语言,在MPS中,它被称为Editor Language

当人们听我说我们的程序将存储为图形并且我们需要特定的编辑器,我确信很多人认为我将要谈到图形编辑器,事实不是这样子的;尽管程序是图形形式,编辑器却不一定非得将程序描绘成图形;事实上,只有少数情况下图形编辑器才是有用的(也就是说,当它合适的时候,比如对数据库表);相反,我们的Editor Language有更好的灵感来源,讽刺的是,它来自文本编辑器

如果你用文本编辑器浏览一个典型的程序,你可以想象编辑器被分成了矩形单元;一些单元包含必需的标识如关键字、花括号、圆括号等,其它的单元包含用户定义的标识,如类和方法的名称;大的单元由小的单元组成,像方法块包含语句,而语句可能包含自己的嵌套块;事实上,任何主流编程语言中任何良好构造的程序都可以分解为矩形单元的集合;那么,在Editor Language中,你不需要想象这些单元,因为编辑器就是简单的由矩形单元组成的

单元的使用有一些有趣的优点;首先,当直接工作在程序图形而不是程序文本上时,单元可以完美的模仿甚至超过标准的文本编辑器;第二,单元不局限于文本,你可以往单元里塞进颜色选择器、数学符号、图表、矢量图、或任何别的什么;最后,这种单元形式的layout是可选的,程序员可以提供不同的机制,单元形式的 layout只是一种有用的缺省设置

因此,Editor Language帮助你定义语言中每个概念对应的单元的layout;你可以定义哪些部分是不变的,像括号或其它修饰符号,哪些是可变的,需要用户去定义的;Editor Language也帮助你在你自己的编辑器中加入强大的特性,像自动完成、重构、导航、语法加亮、错误加亮、以及任何其它你想到的事情;因此你能够增加现在的编辑器如IntelliJ IDEA等拥有的功能到你自己的语言中;这是可能的,因为程序和语言被构造为图形,而我们有专门的Editor Language帮助我们创造强大的编辑器

Transformation Language

Structure Language和Editor Language已经共同提供了一些功能,你能够用它们和其他人交流思想,比如画UML图,或者编写其它类型的文档;然而,大部分时间我们是想让我们的代码做点什么,因此,我们必须找到一种方法让它能够执行;有两种主要的方式来做这件事情:解释和编译

DSLs支持的解释方式帮助定义计算机应该如何解释程序,DSLs支持的编译方式帮助定义如何为程序产生可执行代码;我将在以后的文章中讨论对解释方式的支持,现在我想说明一下MPS是如何支持编译方式的

编译意味着拿到源代码,并从中产生某种形式的可执行代码;对于结果代码有多种可能的形式;为产生可执行代码,你可以生成本地机器码,也可以生成虚拟机字节码;或者,你可以生成另外一种语言的源代码(比如Java,C++),然后用现有的编译器转换为可执行代码;类似的,你甚至可以产生某种解释型语言的源代码,用现有的解释器解释执行

为了避免处理这么广泛的目标格式,我们的方法是用MPS来做每一件事;首先,你在MPS中使用Structure Language定义一种目标语言,这种目标语言和目标格式之间应该有直接的一对一的映射;例如,如果你的目标格式是机器码,你应该用MPS定义一种对应机器码的目标语言;如果目标格式是Java源代码,你应该定义一种类Java的目标语言;目标语言不必支持目标格式所有的功能特性,只为你需要的语言特性进行简单的一对一的映射即可

那么现在,编译分为两个阶段:一个简单的从目标语言到最终结果的翻译,一个更复杂的从最初的原始语言到中间目标语言的转换;翻译阶段是微不足道的,因此我们把精力集中于更有意思的转换阶段;至少,现在的问题简化为了如何将模型从一种语言转换到另一种语言;但是,有可能源语言与目标语言是完全不同的,导致转换非常复杂,比如映射一个源节点到许多散布在目标模型中的目标节点;我们想让定义转换尽可能的简单容易,因此我们需要一种模型转换DSL来帮助我们;在MPS中,这种 DSL被称为Transformation Language

代码生成有三种主要的方法,我们将结合使用它们来定义模型转换;第一种是遍历方式,你枚举源模型中所有节点,检视每一个,并基于检视到的信息生成目标模型中的一些目标节点;第二种方式是使用模板和宏来定义如何生成目标语言;第三种方式是使用模式匹配来查找在源模型中的哪些节点上应用转换

我们通过定义DSLs把这些方式结合起来以支持任何一种方法;这些DSLs将一起工作来帮助你定义从一种语言到另一种语言的转换;例如,遍历方式激发了 Model Query Language的灵感,它使枚举节点和从概念模型中收集信息变得简单容易;你可以把它想象成某种针对概念模型的SQL;做为一种额外的奖赏,拥有一种强大的查询语言不只是对代码生成有用(例如,能够使编辑器更聪明)

Templates

模板方法工作方式类似Velocity或者XSLT;模板看起来很像目标语言,但是允许你在模板的任何部分中添加宏;宏本质上是当运行转换的时候被执行的代码段;宏允许你检视源模型(使用Model Query Language),并使用得到的信息对模板进行“填空”,得到最终的目标代码

在图5中,你可以看到为概念“Property”生成Java代码的模板的定义,模板为属性添加了field declarations, getters, setters等;这个模板是将代码从Structure Language转换为Java的生成器的一部分

既然模板看起来像目标语言,你可以想象模板是用某种基于目标语言的特殊的语言编写的;这也是它事实上的工作方式;我们实际上使用一个生成器来为你生成模板语言,而不是手工为每一种可能的目标语言创建模板语言;它基本上是复制目标语言,并添加所有模板特定的特性,诸如宏等;甚至模板编辑器也是从目标语言编辑器产生的,因此你同样不需要处理代码

当你使用一种模板语言的时候,你可以认为它是用目标语言编写的,只是某些部分的代码是参数化的,或者是由宏来计算的;这种技术极大的帮助简化了代码生成;模板还可以用在其它任务上,如重构、代码优化、还有更多...

Patterns

模型的模式匹配方法给我们一种作为Model Query Language的代替的查找模型的强大方法;你可以把模式想象成概念模型的正则表达式;与模板方法类似,我们基于源语言产生模式语言;模式语言看起来像源语言,只是添加了一些特性,来帮助你定义处理复杂源模型匹配的灵活的标准;你可以把这种方法想象成一种强大的“查找替换”的技术;再一次,模式语言不只是对代码生成有用,例如,它们在为源语言编辑器编写自动化的代码检查工具方面非常有用

记住Model Query Language, template languages, 和pattern languages都由强大的编辑器支持其自动完成、重构、引用检查、错误勘测、等等;即使复杂的查询、宏、模式,都可以很容易的编写;代码生成从来没有这么强大过

Using Languages Together

前面有关代码生成的章节带来了一些关于这些语言如何一起工作的有意思的问题;事实上有几种方法能让语言一起工作;在MPS中,所有的概念模型都互相知晓;既然语言也是概念模型,那么便意味着所有的语言都彼此知晓,可以潜在的被连接在一起

语言彼此之间可以有不同的关系;你能够通过扩展现存的语言来创建新语言,继承所有的概念,修改其中的一些,并加入你自己的概念;一种语言可以引用其它语言中的概念;你甚至能将一种语言插入到另一种语言中去;我将在以后的文章中讨论进一步的细节

Platforms, Frameworks, Libraries, and Languages

我们支持Language Oriented Programming的系统需要比元编程能力更多的功能才能更有用;它应该提供程序员依赖于当前的编程语言提供的所有事物:集合,用户界面,网络,数据库连接,等等;程序员不止是单单基于语言本身来选择语言;例如,Java的大部分功能不是语言提供的,而是有成千上万的framework和API供 Java程序员选择;他们买的不是Java语言,而是整个Java平台;MPS也将有一个它自己的支持平台

在我进入细节前,我们先简要谈一下frameworks;什么是framework?在主流的编程中,它通常意味着一堆类和方法打包成的一个类库;让我们更近一点的观察这一点,看看在LOP的镜片下我们会看到什么

我们为什么想要把类和方法打包成库呢?程序员会背诵他们的教授曾经告诉他们的:“复用”;但这只是在原来的位置上留下了另一个问题:我们为什么要复用类库?答案是类库在解决特定类型的问题方面很有用,如制作用户界面,访问数据库等等;你可以说类库对应着某个领域;你瞧,我们看到了联系,Class libraries are wannabe DSLs!这个悲伤的事实真令我沮丧

今天的Domain-specific languages以类库的形式存在,除了它们不是语言,没有语言的优势,并拥有类和方法所有的局限;特别的,类和方法直接绑定到了特定的运行时行为,而特定的运行时行为是不能修改和扩展的,因为行为是提供“类”和“方法”的概念定义的;因为它们不是语言,类库很少被环境(例如编译器和编辑器)聪明的支持

我们应该忠于wannabe DSLs,还是应该拥有当需要DSLs的时候使用真正DSLs的自由?当然是自由;每个类库都是为我们的平台创建一种完全的DSL的候选;例如,JDK的所有类库都应该是MPS平台上的DSLs;其中一些DSL在现在刚开始的时候不是那么紧急需要,但其它一些从一开始就对平台的功能和可复用性有强烈的影响;我将介绍随MPS提供的三种最重要的平台语言:The Base Language, the Collection Language, and the User Interface Language

Base Language

我们首先需要的语言是对应最简单编程领域的,一种general-purpose的命令式编程;这种简单的语言应该支持近乎通用的语言特性诸如算术、条件、循环、函数、变量等等;在MPS中我们有这样一种语言,它被称为Base Language

对这种语言的需求应该是很明显的,例如,如果我们想把两个数字加在一起,我们应该能够简单的说一句“a + b”就可以;我们不需要到处去使用它,但几乎所有的程序都会有一些组成部分用到它,在那里,它是完成工作最合适的工具

Base Language之所以如此命名,是因为它是很多需要基本编程支持如变量、语句、循环等的语言很好的基础;它能够以三种方式使用:你可以扩展它以创建出你自己的基于它的语言,你可以在你的程序中引用它的概念,你还可以以Base Language生成你的代码;将会有几种可用的生成器来将Base Language转换成其它语言如Java,C++等;当然,不是每种语言都需要使用Base Language,但是在很多情况下,它是一个很好的起点

Collection Language

下一种我们需要的最重要的语言是和集合一起工作的语言;对集合支持的需求是普遍存在的;每种主要的主流语言都提供了对集合某种类型的支持,例如,在Java 中你有java.util,在C++中你有STL;每个人都需要集合;如果每种DSL都提供自己的对集合的支持,那么将会有a Babylon of不同的集合语言,它们互不兼容;这就是为什么MPS必须提供一种每个人都使用的单一的Collection Language的原因

在很多主流语言中,集合并非语言特性而是类库,一个例子是Java的java.util包;这种支持技术上来说是存在的,但它是不方便的,杂乱的,并且易于出错的

Yuck!今天大部分的Java代码被一行接一行多余的、重复的处理集合的代码弄的杂乱无章;图6显示了一个例子,Collection Language是如何beats the tar out of a 类库的;例子是一个计算一组给定的点的convex hull的算法;更多关于Collection Language的细节会在以后的文章中提及

User Interface Language

User Interface Language是我们的平台中下一种最重要的DSL;有趣的是,我前面提到的Editor Language能够另人信服的用来提供用户界面,但是一种专为图形用户界面设计的语言将会更灵活;这种语言带来的益处是巨大的;Java Swing代码就是一个想成为DSL的类库的极好的例子:功能有了,但很容易被误用,并且Swing的代码是彻底杂乱的;很多如今的开发环境都包含GUI builder来简化用户界面的创建;User Interface Language将把这项任务带到一个更高的层次;我将在以后的文章中讨论更多细节

Getting Started with MPS

我已经能够听到一些对LOP怀疑的反应:“听起来不错,但是我们的项目已经步入正轨,现在切换到LOP是不可行的”,或者“听起来不错,但用一个像LOP这样的未经检验的方法来启动一个现实生活中的项目风险太大了”,或者“听起来不错,但是它什么时候才能为它的黄金时期做好准备呢?别忘了OOP用了20年才成为主流”

好消息是我们不需要一头扎进未知里,你可以先用脚趾头试一下水;你可以在你的项目中只是应用LOP的一小块来看一下它有没有提供一些实际的好处,然后如果你喜欢你可以用多一点;在不远的未来,你可以在MPS里试验两个可能的LOP应用:

Using MPS on Java Applications

已经有一个IntelliJ IDEA的原型插件允许你在你的项目中包含MPS的概念模型;当你编辑模型时,模型会自动在后台被转换成Java源代码;因此,你可以使用MPS来编写 Java应用的部分模块,喜欢用多点就用多点,喜欢用少点就用少点;这意味着你得到了MPS全部的力量,比如创建和使用特定DSLs的能力,做任何你想要的语言扩展,同时使用定制的带有自动完成、错误加亮、重构功能的编辑器,等等;插件将和IDEA紧密集成,允许你在你的MPS模型中嵌入Java代码,导航到嵌入或生成的Java代码,甚至进行概念层次的调试,就像IDEA中已经可用的JSP调试支持一样;更多集成特性正在计划中;这将是使用IDEA的 Java开发者可用的一个重要的新工具

Configuring and Scripting Your Applications

有一个我见过很多次的模式,一个应用程序启动时需要某种形式的配置,可能是一个简单的配置文件,或者更完整的部署描述符文件;最后,配置变的更复杂,应用程序最后需要一种脚本语言;对于简单的配置文件,XML很流行;对于脚本语言,你可以创建自己的,或者借用一种general-purpose的脚本语言,像VBScript,Python/Jyphon,Tcl,Javascript,或者Lisp;这些方案中的每一种都至少有一些主流编程方法的标准缺陷:很长的实现时间,陡峭的学习曲线,难以扩展,匮乏的环境支持,等等

作为替代的,你能够使用MPS创建你自己的配置/脚本语言;你的应用程序的用户将会拥有一种易于使用的、智能的编辑器来编写他们的脚本,包括语法加亮,错误加亮,代码完成,导航等;只需花费很少的时间来创建并集成这种语言到你的应用中;为了使用这种应用,你可以分发MPS的运行时

Conclusion

LOP 和MPS背后的思想并不新鲜,实际上已经出现超过20年了;Language Oriented Programming本身这个词也已经提出至少10年了;新鲜的是这些思想一直在软件开发社区默默的渗透,而它们的时代最终到来了;通过这篇文章,我希望提供一颗种子,使这些思想能够产生新的讨论、意见、批评、实验、研究、和最终的真实生活中的项目

并且,因此,我邀请你以任何你能做到的方式参与到这种新的范型中来;在后面添加评论,或者发送Email给我:mps_article@jetbrains.com;在http://www.jetbrains.com/mps可找到更多,请关注更新;注意浏览从LOP的视点出发的网站,杂志,博客,书籍等,并思考事情到底能够多么简单;考虑一下你自己的项目,看看你有多频繁的实际上在设计和使用小的特定的用类和方法修补的语言;你是怎么认为的呢?我想知道

当我将LOP的概念用在开发MPS自身时,我已经看到了Language Oriented Programming是如何彻底改进软件开发的第一手资料;MPS目前并没有为真实世界准备好,但它已经成功的达到了目的;也还依然没有文档,除了这篇文章;我将很快的发布更多的文章,深入的探讨MPS;还有,我计划下月试验着使MPS可下载,因此你的耳朵要保持张开;已经有其它的项目使用了类似的方法,特别是来自Intentional Software 和 Xactium

因此,探险愉快,让我看看你能发现什么

 

Acknowledgements

I would like to thank Rob Harwood for his help in editing this article. I would also like to thank the following people for their reviews, comments, and suggestions: Igor Alshannikov, Florian Hehlen, Jack Herrington, Guillaume
Laforge, Vaclav Pech, Thomas Singer, Dmitry Skavish,David Stennett, and Timur Zambalayev.

About the Author

Sergey Dmitriev (http://www.sergeydmitriev.com) is the co-founder and CEO of JetBrains Inc.(http://www.jetbrains.com), makers of the IntelliJ IDEA Java IDE.

References

Articles:
[1] Donald E. Knuth. Literate programming. The Computer Journal, 27, 97-111, May 1984.
[2] M. Ward. Language Oriented Programming.Software - Concepts and Tools, 15, 147-161 1994,
http://www.dur.ac.uk/martin.ward/martin/papers/middle-out-t.pdf

Intentional Programming articles:
Charles Simonyi. The Death of Computer Languages, The Birth of Intentional Programming. 1995.
ftp://ftp.research.microsoft.com/pub/tr/tr-95-52.doc also
ftp://ftp.research.microsoft.com/pub/tr/tr-95-52.ps
John Brockman. Intentional Programming: A Talk With Charles Simonyi. Edge. 2000.
http://www.edge.org/digerati/simonyi/simonyi_p1.html
Microsoft Research. Intentional Programming.
http://www.cse.unsw.edu.au/~cs3141/ip.asf (video)
Charles Simonyi. Intentional Programming: Asymptotic Fun?http://www.hpcc.gov/iwg/sdp/vanderbilt/position_papers/simonyi.pdf

Books:
Krzysztof Czarnecki and Ulrich W. Eisenecker. Generative Programming: Methods, Tools and Applications.Addison-Wesley, 2000. ISBN: 0201309777.
Jack Herrington. Code Generation in Action. Manning, 2003. ISBN: 1930110979. http://www.codegeneration.net/cgia/
Xactium. Applied Metamodelling: A Foundation for Language Driven Development. 2004.
http://albini.xactium.com/content/index.php?option=com_remository&Itemid=28

Other Resources on the Web:
[3] Matt Quail. Totally Gridbag.
http://madbean.com/blog/2004/17/
Jack Herrington. Code Generation Network.
http://www.codegeneration.net/
[4] Intentional Software
http://www.intentsoft.com
[5] Xactium
http://www.xactium.com
Intentional Programming interviews
Sergey Dmitriev.
http://codegeneration.net/tiki-read_article.php?articleId=60
Charles Symonyi.
http://codegeneration.net/tiki-read_article.php?articleId=61
Krzystof Czarnecki.
http://codegeneration.net/tiki-read_article.php?articleId=64
Andy Evans.
http://codegeneration.net/tiki-read_article.php?articleId=68

See Also:

Thinking in Current Paradigms, Platforms, Frameworks, and Libraries

Thinking in Current Programming Languages

posted @ 2006-11-03 03:30 笨蛋啊帆 阅读(164) | 评论 (0)编辑 收藏

仅列出标题
共6页: 上一页 1 2 3 4 5 6 下一页 

posts - 51, comments - 17, trackbacks - 0, articles - 0

Copyright © 笨蛋啊帆