荔园在线
荔园之美,在春之萌芽,在夏之绽放,在秋之收获,在冬之沉淀
[回到开始]
[上一篇][下一篇]
发信人: junire (好好学习,天天向上), 信区: Java
标 题: java应用的动态扩展(-)
发信站: 荔园晨风BBS站 (Sat Nov 17 21:36:47 2001), 转信
这里所谓的可扩展应用,是指这样的编程语言或者系统,它可以在不修改现有系统
整体或任意一部分功能的情况下,扩展自身的功能。对于传统的编程语言,比如
Cobol、C、C++,如果要为它们的应用增加新功能,程序员必须重新编辑、编译和
发布程序,因为这些语言都是静态链接的语言,不具备动态添加功能的机制(也就
是说,生成执行代码的时候,所有的程序代码必须事先准备妥当)。Java应用的可
扩展能力突破了这些限制。
Java应用的可扩展功能包含了允许动态地定义新的数据类型以及允许用户插入自己
的程序例程的能力。这一切是如何实现的呢?下面我们通过实例来了解具体的实现
过程。
普通应用的扩展
在Java中,扩展性源于继承,具体手段或者是扩展一个类,或者是实现一个接口。
Java接口的主要用途就在于此。(Java接口定义了一组方法,但不包含实现。实现
某个接口的类必须实现该接口定义的所有方法,因而也就遵循某种确定的行为模式
。)
为什么说这个功能对于普通程序来说也很重要呢?如果一个程序是可以动态扩展的
,用户就不必再为了添加新功能而去修改源程序。这就避免了搞乱原有的代码,使
得用户能够专注于自己的那一部分代码。此外,程序不必为了引入新功能而重新启
动,这对于那些需要不间断运行的程序来说无疑是一个福音。
为进一步了解Java程序的动态扩展技术,我们来看一个例子。一家快速增长的保险
公司想要用计算机管理它的报价系统。这家公司现有两个产品:人寿保险(
lifecare)和医疗保险(medicare)。根据保额、期限、客户年龄和保险产品的不
同,月保险费用的计算方法也不同。系统应该能够在不修改原有代码的情况下,引
入保险公司推出的其他产品。为现有产品设计的类模型如图一所示。
当一个客户试图获取某种保险产品的报价时,系统创建一个对应该产品类型的对象
,调用该对象的calculatePremium()方法,根据指定产品的计算方法计算出保险费
用。系统利用一个XML文件(或属性文件)描述现有产品信息,比如保险产品的名
称和相应的类名称。XML文件如Listing 1所示。
【Listing 1:描述产品信息的XML文件】
<?xml version="1.0" encoding="UTF-8" ?>
<root>
<Product>
<Product-name>MediCare</Product-name>
<Fully-qualified-class-name>com.test.dynamic.MediCare
</Fully-qualified-class-name>
</Product>
<Product>
<Product-name>LifeCare</Product-name>
<Fully-qualified-class-name>com.test.dynamic.LifeCare
</Fully-qualified-class-name>
</Product>
</root>
系统从XML文件读取指定产品的类的全称,动态地创建对象。然后,系统调用
calculatePremium(),根据指定的保额、期限和客户年龄,按照特定产品的计算逻
辑计算出精确的保险费。
现在我们来看看系统如何动态地装入对象。在把类装入内存和创建特定产品类型的
对象时,系统用到了Java类库java.lang.Class。Class类的实例或者代表着Java应
用中的一个类,或者代表着一个接口。在后台,Java虚拟机(JVM)常常利用
Class类操作Java类;然而,用户程序也同样可以通过Class类的实例操作Java类。
请参见Listing 2的Class类摘要。
【Listing 2:Class类概要】
public final class java.lang.Class extends
java.lang.Object
{
public static Class forName(String className)
public static Class forName(
String name, boolean initialize, ClassLoader loader)
public Class[] getClasses()
public ClassLoader getClassLoader()
public Class getComponentType()
public Constructor getConstructor(Class[] parameterTypes)
public Constructor[] getConstructors()
public Class[] getDeclaredClasses()
public Constructor getDeclaredConstructor(
Class[] parameterTypes)
public Constructor[] getDeclaredConstructors()
public Field getDeclaredField(String name)
public Field[] getDeclaredFields()
public Method getDeclaredMethod(String name, Class[],
parameterTypes)
public Method[] getDeclaredMethods()
public Class getDeclaringClass()
public Field getField(String name)
public Field[] getFields()
public Class[] getInterfaces()
public Method getMethod(
String name, Class[] parameterTypes)
public Method[] getMethods()
public int getModifiers()
public String getName()
public Package getPackage()
public ProtectionDomain getProtectionDomain()
public URL getResource(String name)
public InputStream getResourceAsStream(String name)
public Object[] getSigners()
public Class getSuperclass()
public boolean isArray()
public boolean isAssignableFrom(Class cls)
public boolean isInstance(Object obj)
public boolean isInterface()
public boolean isPrimitive()
public Object newInstance()
public String toString()
}
在这里,我们感兴趣的主要是forName()方法和newInstance()方法。静态方法
forName()返回和指定类名字关联的Class对象。它通过类装入器把类装入到执行程
序。类名字参数可以是classpath中存在的任意一个类。如果不能找到指定类,则
forName()方法抛出ClassNotFoundException异常。newInstance()方法为Class对
象代表的类新建一个实例。newInstance()方法也利用类的不带参数的构造函数创
建新对象,因此该类必须有一个不带参数的构造函数。如果newInstance()方法由
于任何原因不能实例化一个类,它将抛出InstantiationException异常;如果不能
访问该类或它的构造函数,则抛出IllegalAccessException异常。Listing 3显示
了Product接口和它的实现:MediCare,LifeCare。
【Listing 3:Product接口及其实现】
// Product.java
// Product接口
package com.test.dynamic;
public interface Product
{
public float calculatePremium(
float face-value,int term, int age);
}
// MediCare.java
// Product的一个实现
package com.test.dynamic;
public class MediCare implements Product
{
public float calculatePremium(
float face-value, int term , int age)
{
float premium;
// 计算保险费
// ......
return premium;
}
}
// LifeCare.java
// Product的一个实现
package com.test.dynamic;
public class LifeCare implements Product
{
public float calculatePremium(
float face-value, int term , int age)
{
float premium;
// 计算保险费(不同的保险产品,计算方法不同)
// .......
return premium;
}
}
当用户询问报价时,报价系统根据保险产品的名字装入并实例化产品类。下面我们
用两个方法实现装入和调用代码。GetProductFromName根据指定的产品名字生成合
适的产品对象,makeQuote()方法计算保险费。Listing 4显示了它们的代码:
【Listing 4:生成产品对象,计算保险费】
public Object GetProductFromName(String productName)
{
// 待装入对象的类名称
String className = null;
// 利用XML分析库org.xml.sax,
// 从XML文件获取产品的相应类名称
// ......
// 假定类名字对应正确的产品,例如
// "Com.test.dynamic.MediCare"
try
{
Object o = null;
o = Class.forName(className).newInstance();
}
//catch(ClassNotFoundException e){}
//catch(InstantiationException e){}
//catch(IllegalAccessException e){}
catch( Exception e )
{
e.printStackTrace();
}
return o;
}
// makeQuote方法无返回值
public void makeQuote()
{
String productName;
float faceValue , premium ;
int faceValue, age;
// 从应用的用户界面获取所有参数,包括
// 产品名称、期限、保额、年龄
// (有效的产品可以从一个选择框选择)
// (选择框的内容通过查看XML文件填写)
// ....
// 获取指定产品名称的产品对象
Product objProd = (Product) GetProductFromName(productName );
premium = ObjProd.calculatePremium(
faceValue , faceValue , age );
// 显示保险费
// ......
}
对于任何新的保险产品,只要把它的类加入到classpath指定的目录,然后更新
XML文件中的产品信息,就可以把它加入到现有的系统。例如,假设有一种新产品
XYZCare,只要按照Listing 5所示修改XML文件,然后把XYZCare的类文件放入
classpath指定的目录,就可以立即把它加入到现有系统之中。
【Listing 5:加入XYZ产品之后的XML文件】
<?xml version="1.0" encoding="UTF-8" ?>
<root>
<Product>
<Product-name>MediCare</Product-name>
<Fully-qualified-class-name>com.test.dynamic.MediCare
</Fully-qualified-class-name>
</Product>
<Product>
<Product-name>LifeCare</Product-name>
<Fully-qualified-class-name>com.test.dynamic.LifeCare
</Fully-qualified-class-name>
</Product>
<Product>
<Product-name>XYZCare</Product-name>
<Fully-qualified-class-name>com.test.dynamic.XYZCare
</Fully-qualified-class-name>
</Product>
</root>
如果系统需要计算XYZCare产品的保费,它就会调用GetProductFromName()装入该
产品,然后调用该产品的calculatePremium()方法,根据该产品的计算逻辑得出保
费金额。
to be continued
--
| # 你记得也好, # |
| # 最好你忘掉, # |
| # 你我交汇时所放出的光芒 # |
---------------------------------
※ 来源:·荔园晨风BBS站 bbs.szu.edu.cn·[FROM: 192.168.0.180]
[回到开始]
[上一篇][下一篇]
荔园在线首页 友情链接:深圳大学 深大招生 荔园晨风BBS S-Term软件 网络书店