java select 函数_在java中实现sql的select函数功能

在java中实现sql的select函数功能

2007-6-9文字大小:大中小

在Java中实现sql的select函数功能

――通过简单的机制实现对象数组或集合的选择,过滤,和排序

David RapPOPOrt

摘要

在“filter collections”中,David Rappoport 讲述了一个过滤集合对象的简单方法。在本文中,他扩展了自己的思想,并展示了怎样实现,如同用sql的select处理关系数据库中的表一样,处理对象数组或集合。他描述了用于选择,过滤,排序队形数组或集合的通用机制。通过这种机制,可以在java的对象数组或集合上实现sql的select函数功能。(2004-11-22)。

假设你希望以表格的形式,如行列的形式,显示数组或集合中的数据,并且希望可以选择显示的属性。另外,你还希望只显示满足一定条件的数据子集,希望用自定义先后顺序的的排序标准对数据排序。

这种类型的功能是sql的select函数提供的:在sql语句中,可以定义数据源(通过from指定);可以定义返回的属性(通过在select后面指定返回列);可以添加条件(where子句);并且可以定义数据显示的顺序(order by子句)。

本文讲述了一些使你能把这些函数使用在任何类型的对象数组和集合上的类和接口。为了实现这些函数功能,机制描述使用了一些设计模式。本文提出的方法有一下一些好处:

1。通过本文的代码(可以下载。。。),你可以在不影响原始数据的前提下,以不同的方式显示数据。

2。排序,过滤和选择制定的属性十分简单,并且结果能很快得到。

3。通过这些类和接口,你可以独立的考虑select语句的各部分,从而可以产生纯净,可复用,可扩展的代码。

但是,你可能也会猜到,机制使用的是通用接口,如果你没有很好的理解它,可能会滥用它。

机制的类和接口

下面的列表给出了我们需要的类和接口的简短说明。后文中,你将看到他们怎么协作,实现设计的功能。每一个类和接口都非常简单,只含有一个到两个函数。

1.接口Invoker包含唯一一个函数:public boolean invoke(Object o)。通过这个接口,可以封装函数调用并返回函数结果。后文你将看到他是怎样使用的。

2.接口Condition也只包含一个函数:public boolean passes(Object o)。使用这个函数,可以检测任意类是否满足任意类型的条件,并返回true或false。同样,你也将在后文中看到本接口的使用。

3.类SelectStatement代表整个select语句,包含select,from,where和order by等子句。

4.类SelectInstrUCtion表示select子句中的一个单一部分,选定列并指定显示时该列的名字。一个完整的select子句用一个SelectInstruction对象数组表示。

5.类OrderInstruction代表order by子句的一个单一部分,整个order by子句由一个OrderInstruction对象数组构成。

6.类Executor执行包含了整个执行逻辑的SelectStatement。

7.类ResultTable代表执行SelectStatement后返回的结果集。它用Object[][]的形式组织结果数据,从而可以容易的转换和显示数据。

下面将讲述这些类和接口时怎样协作的。类图显示了它们之间的关联。

一个SelectStatement含有一个对象集合或数组(因为集合和数组都只包含统一类型的对象,所以对象的类型没有关系);一个SelectInstruction对象数组;一个Condition对象数组;和一个OrderInstruction对象数组。然后把SelectStatement对象传入Excuter对象,在那里执行这个statement并返回一个ResultTable。

接下来的问题是,SelectInstruction,Condition,OrderInstruction和ResultTable,这些类都是做什么的?我们为什么需要他们?首先,不要一下全看他们,这可能会使你迷惑。一个一个的看,每一个类都是易于理解和使用的。

每一个SelectInstruction代表你希望在结果集中出现的一个列(或者对象的一个属性)。你为他定义一个名字和Invoker。名字将作为列标题出现,Invoker将在集合中的每一个对象上触发。在某个对象上触发后,Invoker在对应列中返回该对象的对应属性。这项函数功能组成了select子句,在这个子句中,可以定义显示的属性,并用as定义列名(如select speed as Max_speed)。注意:你也可以只有一个SelectInstruction,其中的列名串为*。在这种情况下,类中的所有getter()方法都被invoker包覆,其结果都出现在ResultSet中。

每一个Condition代表一个条件,源数据集合中每一个对象都需满足此条件。这个类对应于where子句,通过它可以通过给定的条件排除任意数目的行。注意:如果想要显示全部对象,只需传入空的Condintion[]即可。

每一个OrderInstruction代表一个怎样排序数据的规则,它由一个Invoker和一个Comparator组成。Invoker的invoke(Object o)方法(作用于对象集合中的一个对象时)会返回一个结果,并于作用于集合中其他对象返回的结果进行比较,从而决定结果数据的排序位置。Comparator(如果实现了)比较两个对象在invoke作用下返回的结果。如果comparator没有实现,结果将基于它们各自的compareTo(Object o)方法(假定他们都实现了java.lang,Comparatable)进行比较。

数组中的OrderInstruction之间的顺序也非常重要:OrderInstruction对象在数组中出现的越早,它的优先级就越高。这就是说,可以通过应用第一各OrderInstruction,忽略后面的OrderInstruction对象,决定优先级。OrderInstruction类对应于select语句中的order by子句。注意:如果你并不需要对结果进行排序,只需简单的传入空OrderInstrument[]。

最后,Executor以SelectStatement作为输入,基于Condition[]过滤对象,基于OrderInstruction[]排序过滤后的对象,然后使用SelectInstuction[]选择需要用来显示的属性。为了便于传送,结果数据放入ResultTable。

ResultTable有一个同样简单的接口:它定义了一个public String[] getColumnNames()方法,按序返回所有列名。它还定义了一个public Object[][] getResultData()方法,返回选择、过滤和排序后的行列数据。

为什么要用通用接口?

正如前文所说,本文的解决方案依赖于一些通用的方法调用--即Invoker的invoke(Object o)方法和Condition的passes(Objdec o)方法。我们为什么需要它们?它们能作什么?

由于我们我们提供的解决方案平等的对待集合或数组中的对象,而不针对特定的对象类型;另外,选择、过滤和排序都是基于对象自身属性的,我们的选择只有两个:反射或者通用接口。反射使我们能构在运行的时候查找对象的方法,并指定调用方法的名字。但是,通常不在产品环境中使用反射,因为这样会使编译时问题推迟到运行时进行,并且反射的性能一般不如编译形成代码好。代替反射的选择是使用通用接口:通用接口适用于所有类型的对象,在内部将对象映射到对应的类,并根据其类别处理对象。这就是Invoker接口所作的:它使Executor可以让Invoker调用类型相关的方法,从而同样的处理所有类型的对象。Condition接口使用了同样的思想。

注意:Apache基金组织的集合api定义了一个Predicate,实现了本文中Condition接口同样的功能,定义了一个Clouser接口,对应于本文的Invoker接口。笔者认为这些接口

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值