传统上,任何提供商务基本功能的软件都涉及到了事物逻辑。除了定义为实现标准服务或者应用程序的事物规则的代码外,你还可以进一步定义事物逻辑的概念。事物逻辑一般与n层系统的中间层相联系。换句话说,事物逻辑在表示层与数据访问层之间,如图A所示。
图A
事物逻辑组建或者服务一般用来响应表示层的请求、访问数据层中特定资源以获取查询结果,并把查询结果返回到表示层。事物逻辑组件应该对任何用户都是一碗水端平的。这就允许它们用一种与客户无关的方式提供功能。下面,我们将看到JavaBean是如何帮助你实现这一点。不过,在这之前,让我们首先看看什么是软件组件(software component)以及它与对象(object)的区别。
有关组件的一个案例
软件组件可以定义为一种自治的、提供外部公共接口、动态可用的(dynamically discoverable)事物过程,软件组件还可以用来构件其它组件或者应用程序。打个比方,汽车的每个零件(组件)都有明确的目的(过程),只要零件的尺寸和螺孔(接口)符合标准,它就可以用来组装一辆完整的汽车(其它组件或者应用程序)。
也许举个例子可以帮助你理解这一点。假设有一家低水平的软件公司,它有如下的软件技术:电子表格、文本编辑、图形编辑工具、拼写检测。现在,如果说这些技术中的每一种都有一个对应的公共接口可供其它软件组件或者应用程序来使用。发挥一下你的想象力,你就会发现把这些技术组合在一起形成一个功能强大的应用程序――例如字处理软件――并不会花费多少力气。
你也许会说:“软件组件与对象或者代码库有什么区别?”――这是个不错的提问。让我们看看它们之间的区别。
库、组件和对象
单一的代码库是函数调用的一个逻辑上的组合,它们按照与操作系统有关的机器代码的方式打包到一个可链接的文件上。在Java中,库可能是以打包到一个JAR文件一组静态方法的形式存在的。由于这些函数调用或者静态方法对它们所处的环境一无所知,所以它们一般不能维护(与调用它们的客户代码有关的)任何一种状态。例如,Java中的代码库(打包为一组静态方法),看上去可能向代码清单A所示。
清单A如下:
Listing A
public class SystemLib {
public static Date getDateTime()
{
return new Date();
}
public static String getOSVersion()
{
return System.getProperty("os.version");
} }
对象把状态和功能封装当逻辑单元之中。一个或者多个客户可以分享同一个对象。对象一般可以提供其中某些状态数据以及适当的操作。代码清单B给出了一个表示个人信息的Java对象。
代码清单B如下:
Listing B
public class Person {
protected String name;
protected int age;
public Person(String name, int age)
{
this.name = name;
this.age = age;
}
public String getName()
{
return name;
}
public int getAge()
{
return age;
}
public String toString()
{
return "Name: " + name + ", Age: " + age;
} }
请注意观察Person对象是如何提供状态数据(姓名与年龄)以及对应的一个操作(toString)。这些都是相当基本的。那么软件组件又有什么好抄作的呢?
软件组件把对象的概念向前推进了若干步。软件组件像对象那样把状态和操作封装在同一个逻辑单元之中,但与对象不同,软件组件还提供了动态可用的接口、属性和操作的概念。典型的组件还提供了对象的事件概念。让我们看看如何把Person对象扩展、提升成一个组件,代码如清单C所示。
清单C如下:
Listing C
public class Administrator extends Person {
private String rights;
private String department;
private Vector listeners = new Vector();
public Administrator(String name, int age, String rights, String department)
{
super(name, age);
this.rights = rights;
this.department = department;
}
public String getRights()
{
return rights;
}
public void setRights(String rights)
{
this.rights = rights;
fireStateChangedEvent("Rights");
}
public String getDepartment()
{
return department;
}
public void setDepartment(String department)
{
this.department = department;
fireStateChangedEvent("Department");
}
public void setName(String name)
{
this.name = name;
fireStateChangedEvent("Name");
}
public void setAge(int age)
{
this.age = age;
fireStateChangedEvent("Age");
}
public void addStateChangedListener(StateChangedListener l)
{
if (listeners.indexOf(l) == -1)
{
listeners.add(l);
}
}
public void removeStateChangedListener(StateChangedListener l)
{
listeners.remove(l);
}
private void fireStateChangedEvent(String dataName)
{
for (Iterator iter = listeners.iterator(); iter.hasNext();)
{
StateChangedListener l = (StateChangedListener)iter.next();
l.stateChanged(new StateChangedEvent(this, dataName));
}
}
public String toString()
{
return super.toString()
+ ", Rights: " + rights + ", Department: " + department;
} }
Administrator类扩展了Person类,它添加了两个新的数据(或者说属性):权利(rights)和部门(department)。Administrator类提供了修改权利和部门属性的操作。它还添加了改变父类(Person类)的姓名和年龄的操作。Administrator类添加了事件功能,因此有兴趣的客户可以登记为Administrator类事件的接受者,这样该用户就可以知晓Administrator组件中的任何状态改变。
Java中的Bean
Java编程语言中正式的组件模型是JavaBeans规范。该规范增加了若干个概念以提升Java编程语言中组件的性能。其中的某些概念――属性、事件以及方法――与其它标准组件模型中的对应概念含义相同。尽管方法的概念对JavaBeans来说并不新鲜,但是JavaBeans模型发布关于方法的信息还是可以使得在设计和运行时发现它们更容易。
JavaBeans规范引入的最最广为使用的一个概念(尽管从表面上看这个概念相当的简单)就是命名方式。命名方式就是用推荐的前缀和后缀来区分方法的简单标准。例如,JavaBeans规范建议用来任何提供属性值(状态数据)的方法的名字应该有前缀get或者is。这样,提供年龄(age)属性值的方法应该命名为getAge()。另外,任何修改属性值的方法的名字都应该以set为前缀。这样,修改年龄属性的方法应该命名为setAge()。代码清单C中的Person类就演示了如何使用这种命名方式。
JavaBeans规范中另一个广为使用的概念就是任何JavaBeans都要支持串行化(serialization)和具体化(externalization)的要求。这两个要求都用来处理对象自动写入存储器以及从存储器恢复的能力。串行化一般由java.io包来控制,而具体化的工作大多由单独的类来控制。
命名方式、串行化、具体化的概念简洁明了,它们为Java编程语言以及Web应用程序开发环境提供了巨大的动力。让我们看看几种在事物逻辑层利用这些JavaBeans概念的方法。
Beans的事物逻辑层
由于JavaBeans必须支持串行化和通用命名方式,所以它们对数据传输组件自适应。例如,假设我们在利用银行系统的组件和服务,那么我们的事物逻辑层就应该考虑诸如帐号、客户和付款之类的组件。这些组件需要在组件与组件之间、层与层之间传递。这个传递机制可能需要跨越处理边界以及机器边界。为了使得组件可以方便的跨越这些边界,该组件就需要在电缆传输时拥有串行化和解串行化(解串)的能力。由于JavaBeans需要支持串行化,又由于我们可以依靠JavaBeans的通用命名方式,它们可以在过程之间或者层之间动态的串行传输以及解串(deserialized),如图B所示。
图B
总结
我们已经介绍了如何用Java以及JavaBeans来建造事物逻辑组件以及中间件的技术。我们将在下一篇文章中介绍Enterprise JavaBeans在与其它资源交互时是如何用来封装事物逻辑的,并由此进一步展开对事物逻辑组件的讨论。