`

面向表格编程的力量——Butler介绍(翻译)

阅读更多

面向表格编程的力量

——Butler介绍<?xml:namespace prefix = o ns = "urn:schemas-microsoft-com:office:office" />

原文:http://www.javaworld.com/javaworld/jw-10-2004/jw-1018-butler.html

摘要

自从面向对象和三层结构出现以后,企业应用设计者一直在尝试着隐藏数据库的具体结构。但是这样却增加了软件的复杂性,而且强迫开发者制造了除了底层以外的很多不必要的层次。这篇文章介绍了一个面向表格编程的库——ButlerButlerJDBC为基础,包括很多具有数据感知能力的SWING组件,可以大大降低在企业客户端应用中书写底层GUI的压力。

当面向对象语言在企业应用中开始应用时,设计者遇到的是如何将关系模型转换成对象模型的压力。在面向对象模型里面,数据是被封装起来的。但关系模型则相反,数据是根本不需要隐藏的。由此很多设计者认为如果使用关系数据库不能被避免,他们将商业逻辑隐藏起来。

面向对象开发者的梦想就是有一个面向对象的数据库。但是这种数据库在市场竞争中无法获得足够的市场份额,而且很可能根本无法取代面向关系的数据库。最近,很多开发者,甚至面向对象论者,都承认关系数据库比面向对象数据要好。

尽管关系数据库有很多优势,但是很多主流的持续性框架(EJBJDO Hibernate)拒绝在关系数据库里面存储对象。所有的关系数据库都是由表、列、主键、外键、记录和查询等组成的。但是没有一个主流的产品具有符合这些实体的对象模型。

另一个可供选择的模型,面向表格编程模型,允许应用源代码知道真实的数据库结构,而不是将数据库结构隐藏在应用的映射层中。许多企业应用具有很多CRUD(createread,update,delete)相关的逻辑,如果数据库结构不被隐藏的话,开发CRUD功能将会很简单。

有些人认为对象模型不必和数据库结构一致,这样即使在数据库结构改变的时候商业逻辑也不需要改变。但是这些人忽视了很多商业逻辑是在关系数据库schema上实现的,所以准确的说,改变数据库schema也将改变商业逻辑。

隐藏关系数据库真实结构的结果就是使用一个额外的抽象层。表、列和外键等必须映射到类、属性和关联等。在很多方面,需要为每个表做一个类,把每个列做成类的属性,用关联来代表外键。另外,SQL也被重新改造(Hibernate查询语言HQL,JDO-QL,EJB-QL)。为什么要增加这些额外的层次呢?这些层次提供了很少的特性,但是却增加了复杂性。

面向表格编程最大的优势就是提供了创建数据感知GUI组件的能力。如果你正在实现一个用来现实和()更新数据库中数据的应用,JTables, JcomboBoxesJformattedTextFields连接数据库可以节约大量的开发时间。对于Web应用,数据感知标签库也可以加速开发。任何一个主流的持续性框架都比不上数据感知组件这样适合面向表格的框架。

在面向对象的世界里,很多观点都反对数据感知组件。一个常见的观点就是GUI和数据库不能共享同一个结构。一些客户端应用的确是这样的,但是对于面向CRUD的客户端,数据感知组件能节约大量的开发时间。仅仅因为数据感知组件不能在所有应用中使用,不是一个足以反对它的原因。

开发者的另外一个担忧是,害怕使用数据感知组件将对特定的数据库和IDE产生依赖。的确,一些数据库和IDE的开发商制造了一个绑定在特定数据库和IDE上的GUI组件库。但是你如果是具有使用JDBCANSI SQL-92语法的组件库,这个库即将和提供商无关。

事实上,对于数据感知组件重要性正在面向对象的世界中慢慢得到重视。甚至SUN公司都已经从开源项目JDesktop Network Components中意识到这种需求。

这篇文章就是讨论一个已经存在的面向表格的持续性框架——Butler

l 对象模型

Butler具有一系列专门用来描述数据库schema结构的类:

u Table:描述表结构

u Column:代表表中的列

u ForeignKey:两个表之间的外键。

这些类只用来代表数据库的结构(DDL,数据描述语言)。当从数据库中读写内容的时候,值对象也是需要的。什么可以比一个叫做RecordJava类能更自然的代表表中的记录呢?

l 取得记录

通过主键的值来取得记录,你可以调用对应表的实例里面的findByPK()方法,取代从需要的表中使用Select。方法的参数就是主键的值。例如:

Record rec = tableRef.findbyPK(“ABC123”);

如果想取得所有的纪录,只需要调用findAll()方法,这个方法返回记录的列表,而不是一条单独的记录。

对于其他复杂的查询,则必须使用Query类,这个类代表一个SQL中的select声明。很多主流的持续性框架都是使用字符串来代表查询的。在很多方面,用字符串代表使代码紧凑,但是也带来了一些不足。使用对象和方法来构造查询则更加类型安全。大量的错误将在编译的时候被编译器发现,而不是导致运行时错误。IDE的特性,比如代码自动完成,也会使程序员使用Java语言构建查询比使用字符串简单。

Butler中的查询总是具有一个起始表(或者称作主表),这个表代表记录查询的来源。它也可以联合其他的表。结果还将是来自起始表中的记录列表。但是每个来自起始表的记录会和关联的表中记录关联,这些可以通过getRelatedRecord()getRelatedRecords()方法进行访问。这就相对于JDBC提供了一个很大的不同(或者称作优势),在JDBC中,查询的结果总是二维的。通过记录分层,它还可以被更新或者简单的进行更复杂的结果处理。

Butler使用Filter子类来指定需要选择的记录。例如,EqualsFilter简单的比较提供的值是否和列的值相同。Filter表达用来替代你在SQL声明中所有逻辑操作符。

指定记录排列顺序可以使用addSortCritera()方法。这和SQL中的order by子句对应。

把所有的放在一起,那么一个简单的查询将是:

Query q = orderTable.createQuery();

q.join(orderDetailTable);

q.addColumn(orderTable.getColumn("OrderID"));

q.addColumn(orderTable.getColumn("OrderDate"));

q.addColumn(orderDetailTable.getColumn("ProductID"));

q.addColumn(orderDetailTable.getColumn("Quantity"));

EqualsFilter filter;

filter = new EqualsFilter(orderTable.getColumn("CustomerID"))

q.setFilter(filter);

q.addSortCritera(orderTable.getColumn("OrderDate"));

QueryInstance qi = q.createInstance();

filter.populate(qi, "BLONP");

RecordList recList = qi.run();

Butler对很多类提供内置的XML支持。一个查询结果(RecordList)可以被转换成如下的XML格式:

<records table="Order">

<record>

<column name="OrderID">123</column>

<column name="OrderDate">2004-08-29</column>

<records fk="FK_Order_OrderDetail">

<record>

<column name="ProductID">P01</column>

<column name="Quantity">2</column>

</record>

<record>

<column name="ProductID">P02</column>

<column name="Quantity">4</column>

</record>

</records>

</record>

</records>

这对于生成报表非常有用,可以很方便的转换成用于生成PDF文档的格式化对象,查询结果的层次化结构(相对二维结构)使它成为可能。

l 更新纪录

Butler中,更新数据库记录非常简单。只需要调用记录实例的set()方法,以列名和值作为参数,来更新你需要的列。接着调用save()方法:

orderRec.set("OrderDate", orderDate);

orderRec.set("ShippingDate", shippingDate);

orderRec.save();

插入记录时首先调用对应的表对象的addRecord()方法,接着设置列的值和保存记录:

orderRec = orderTab.addRecord();

orderRec.set("OrderID", new Integer(123));

orderRec.set("OrderDate", orderDate);

orderRec.save();

删除记录同样简单。只需要调用记录对象的delete()方法。如果你想删除多条记录,则需要使用DeleteQuery类。它和Query类很类似,你需要指定一个filter来代表你需要删除的记录:

deleteQ = orderTab.createDeleteQuery();

filter = new EqualsFilter(orderTable.getColumn("CustomerID"));

deleteQ.setFilter(filter);

QueryInstance qi = q.createInstance();

filter.populate(qi, "BLONP");

qi.run();

Butler还提供了注册记录监视(triggers)的功能,可以给表注册一个RecordListener,在每次更新、插入、删除的之前和之后,将调用对应的事件方法。

l 生成器

如上面的例子一样,列名和表名以字符串的形式给出。程序员可能会键入错误的表名,这将造成运行时错误。为了防止这种情况,Butler可以使用生成器类生成包含每个列的getset方法的TableRecord子类。

生成器也可以以另外一种形式来使用。产生的子类也包含数据库的结构信息。Butler不必通过JDBC在运行时获得数据的元数据,这被证明对于一些数据库非常耗时。原数据在产生的时候被取得。如果不必生成子类,也可以生成描述数据库结构的XML文件。

l 数据类型

到现在为止,这篇文章已经描述了生成JDBC调用的简单方式。但是Butler也包含了一些JDBC以外的特性。

以数据库为中心的应用总是包含数据的校验和格式化。当用户输入数据的时候,在存入数据库以前必须进行校验。在将数据提供给用户以前,它必须被进行一定的格式化。

Butler中,每个表中的列都能和一个Datatype对象进行关联。Datatype能校验和格式化列的值。Butler对于字符串、数字值和日期有内值的Datatype实现。但是程序员也可以编写个性化的Datatype类实现处理个性化的数据类型,如电话号码,地址,甚至象图片这样的大数据对象。

上面描述的Butler类可以看作是为了简化和增强数据库编程,而在JDBC上增加的一个层。使用这些类不必改变应用的结构。可以在任何具有JDBC的地方使用。

下面我将介绍数据感知Swing组件。使用这些类需要改变应用的结构,但是数据库结构将不再和客户端不可见。

l Swing组件

在以数据库为核心的客户端应用中,你会发现很多JtableS和数据库表关联的例子。实现这样的表经常耗费很多的时间。但是使用RecordListTable类可以节约不少的时间。程序员只需要告诉数据库中的什么表和列需要显示,以及将RecordList指派给RecordListTable即可。相关记录(多对一关系)中的列也可以被显示。RecordListTable允许更新、插入和删除记录。例如:

recListTable = new RecordListTable(orderTab);

recListTable.addColumn(orderTab.getColumn("OrderID"));

recListTable.addColumn(orderTab.getColumn("CustomerID"));

recListTable.addColumn(orderTab.getForeignKey("FK_Orders_Customers"),

customerTab.getColumn("CompanyName"));

recListTable.recordListSelected(orders);

如果记录的内容需要在RecordListTable以外编辑详细的内容,可以使用RecordEditor类。该类提供一个用来编辑记录的面板,为表中的每列(或者指定特定的列)都提供编辑组件。

RecordEditor实现了ActionListener接口,new命令告诉RecordEditor增加新的纪录,save命令保存当前记录。例如:

editor = new RecordEditor(orderTab);

editor.add(orderTab.getColumn("OrderID"));

editor.add(orderTab.getColumn("OrderDate"));

saveButton = new JButton("Save");

saveButton.setActionCommand("save");

saveButton.addActionListener(editor);

为了个性化层次,可以使用RecordController代替RecordEditor。不可见的组件将自动产生。RecordController有一个用来产生编辑组件的工厂方法。程序员只需要将这些组件放在需要的位置:

controller = new RecordController(orderTab);

ValueEditor editor;

Column col = orderTab.getColumn("OrderDate");

editor = controller.createColumn(col)

panel.add(editor);

对于RecordEditor来说,RecordControler的工作方式和RecordSelectionListener类似。

在很多客户端中,已有记录的列表(RecordListTable),在一行(记录)被选中时,选中记录应该在一个详细视图(RecordEditor或者RecordController)中显示。为了在Butler中增加这种功能,只需要将RecordEditorRecordSelectionListener的形式注册给RecordListTable

recordListTable.addRecordListTable(recordEditor);

在很多客户端中,用户需要首先选中他需要显示或者编辑的记录的能力。在Butler中,可以使用QueryPanel来增加这种能力,QueryPanel获得一个Query后将产生一个对应的GUI,可以在里面输入过滤器获得的值。如果结果需要在RecordListTable中显示,只需要将RecordListTableRecordSelectionListener的形式注册给QueryPanel

query = orderTab.createQuery();

query.setFilter(new EqualsFilter(orderTab.getColumn("CustomerID")));

panel = new QueryPanel(query);

recListTable = new RecordListTable(orderTab);

panel.addRecordSelectionListener(recListTable;

如果需要个性化的层次,可以使用和QueryPanel对应的QueryController

上面介绍的是一些常用的数据感知组件,如果你观察一个企业客户端应用,你会在很多画面中发现以下的模式:在应用画面的上面是用来输入查询参数和查询按钮的部分(QueryPanel),下面是用来显示查询结果的列表或者表格(RecordListTable),再下面,是一个类似弹出窗口的用来编辑记录的详细视图(RecordEditor)

如果你需要创建这样模式的客户端,同时你不需要个性化层次,你不必手动设计这些组件。相反,使用SimpleForm类创建这样结构的画面,只需要几行代码。

l 总结

这篇文章描述了非主流的数据库编程解决方案。这种方案类似面向对象出现以前的数据库编程。但是最大的不同是:Butler利用了面向对象编程的完整力量,使关系数据库和面向对象的编程语言不存在任何不协调。

相关网址:

Butler数据库框架:http://butler.sourceforge.net

面向表格编程的更多信息:http://www.geocities.com/tablizer/top.htm


(第一次翻译,不足之处大家海涵。cqucyf@263.net)

分享到:
评论

相关推荐

    面向Android的测试工具Test-Butler.zip

    该演讲介绍了如何解决反复出现并影响移动测试的问题,比如缺少可靠性和可再现性、速度缓慢等。示例代码:public class ExampleTestRunner extends AndroidJUnitRunner {  @Override  public void onStart()...

    mod_butler_butlermatrix_matlab_MOD_

    标题中的“mod_butler_butlermatrix_matlab_MOD_”似乎是指一个修改过的Butler矩阵相关的MATLAB代码库。Butler矩阵是一种多路复用器,常用于无线通信和射频系统,它能将输入信号分配到多个输出端,或者反之,将多个...

    Butler For Mac_v4.3.3

    Butler for Mac_v4.3.3 是一款专为Mac用户设计的任务管理工具,它以其高效性和易用性脱颖而出。该软件旨在帮助用户更有效地组织和执行日常任务,通过定制化的一键触发功能,实现多任务的快速处理。在这款应用中,...

    使用e-Butler提高电子商务服务质量的研究

    接着,文章介绍了e-Butler的概念和在提高电子商务服务质量中的应用。e-Butler是一种智能化的客户服务工具,它通过先进的信息技术和大数据分析手段,能够主动识别客户的需求,并提供个性化、智能化的服务解决方案。e-...

    topcom无绳电话说明文档 butler 2820C

    根据给定的文件信息,我们将深入探讨与Topcom无绳电话Butler 2820C相关的专业知识点,包括其功能、操作指南以及技术规格。 ### Topcom无绳电话Butler 2820C概述 Topcom Butler 2820C是一款高性能的无绳电话,设计...

    PyPI 官网下载 | http_butler-0.1.1.tar.gz

    标题中的"PyPI 官网下载 | http_butler-0.1.1.tar.gz"指的是一个可以从PyPI官网上下载的名为http_butler的Python库的特定版本——0.1.1。这个库被压缩成一个tar.gz文件,这是一种常见的Linux和Unix系统中用于归档和...

    07-com.adobe.Butler.backend.zip

    07-com.adobe.Butler.backend.zip

    前端开源库-butler

    前端开源库"Butler",又被称为"巴特勒",是一个全功能的静态站点服务器,专为前端开发者设计。它旨在简化静态资源的托管、预处理、自动化任务和部署流程,使得前端开发更加高效和便捷。Butler不仅提供了一个强大的...

    商务应用范例Butler共6页.pdf.zip

    从标题来看,我们可以推测这个文件可能详细介绍了Butler在商务环境中的应用实例,共计六页内容。Butler通常指的是一个能够提供高效、便捷服务的系统或工具,尤其在商务领域,它可能是一个自动化流程、管理工具或者...

    swagger-butler-core-2.0.0.zip

    &lt;groupId&gt;com.didispace&lt;/groupId&gt; &lt;artifactId&gt;swagger-butler-core &lt;version&gt;2.0.0 &lt;packaging&gt;jar&lt;/packaging&gt;

    Tim Butler-Nginx Cookbook-Packt Publishing (2017).epub

    Tim Butler-Nginx Cookbook-Packt Publishing (2017).epub

    考虑应力耦合的电化学反应模型:修正Butler-Volmer模型及其应用

    考虑应力耦合的电化学反应模型:修正Butler-Volmer模型及其应用,李宗赞,宋亦诚,本文研究应力耦合在锂离子电池电极嵌/脱锂电化学反应中的作用及影响。基于传统的忽略应力的描述电极反应动力学过程的Butler-Volmer...

    Butler database framework-开源

    总的来说,Butler数据库框架提供了一个简洁、高效的解决方案,帮助开发者以面向对象的方式处理数据库操作,降低了数据库编程的复杂性,同时保持了对JDBC的底层控制。通过开源社区的支持,Butler不断进化和完善,为...

    Laravel开发-file-butler

    **Laravel 开发 - File Butler** `File Butler` 是一个基于 Laravel 框架和 Vue.js 前端库构建的文件浏览器与上传组件。它为 Laravel 应用程序提供了强大的文件管理功能,使得用户可以方便地浏览、上传、下载以及...

    gui-butler:像我这样的懒骨头的itch.io管家包装

    【标题】:“gui-butler:面向懒人用户的itch.io游戏发布助手” 【描述】:“吉·巴特勒(gui-butler)是一个专为那些希望通过itch.io发布游戏但又不想花费大量时间在命令行界面(CLI)上配置和管理构建脚本的...

    trello.butler:Trello发布了一项称为Butler的加电服务,该服务使我们能够自动化许多被广泛使用的功能。

    为了进一步提升用户体验和效率,Trello推出了名为Butler的自动化服务。Butler是Trello的一个强大功能,它允许用户通过简单的规则和命令来自动化重复性的任务和流程,从而减轻日常管理工作负担,提高团队协作效率。 ...

    开源:API文档汇总管理工具Swagger Butler

    Swagger Butler是一个基于Swagger与Zuul构建的API文档汇集工具。通过构建一个简单的Spring Boot应用,增加一些配置就能将现有整合了Swagger的Web应用的API文档都汇总到一起,方便查看与测试。 swagger-butler-core-...

    Vacation-Butler:出行再难不过了

    《假期管家:出行再无难题——深入解析Java技术在Vacation-Butler项目中的应用》 在当今快节奏的生活中,假期的规划与管理成为了一项挑战。"Vacation-Butler",这个项目的出现,旨在让出行变得简单、轻松。作为一款...

    butler-mobile:手机的任务和事件

    TypeScript是一种由微软开发的强类型、静态类型的JavaScript超集,它提供了更好的代码工具支持、错误检查和面向对象编程特性,如类和接口。使用TypeScript可以提高代码质量和可维护性,减少运行时错误,特别是在大型...

Global site tag (gtag.js) - Google Analytics