2009-04-23 83 views
0

我正尝试在Java中编写嵌入式(NOT web,而不是企业)内容管理系统,重点在于组织性,易用性和可扩展性,达到100,000个左右的项目。系统应该能够创建和定义可以与唯一资源相关联的元数据项目以允许搜索。如何为具有可扩展属性的资源编写DAO?

例如,他们可以创建一个带有String值的标签“ProjectName”。然后,他们可以将一些资源标记为属于项目“掌控世界”或“修理我的车”。标签是强类型的,所以标签可以存储单个或多个字符串,整数,双精度等。每种标签类型应该有格式化器和输入验证器以允许编辑。

我已经决定从GUI抽象存储模型以允许可伸缩性是很重要的;执行此操作的显而易见的方法是为每个资源使用数据访问对象(DAO)。但是,我不知道如何编写支持可变数量标签的DAO,并且可以正确缩放。

问题是资源需要表现为元组(用于表格查看/排序/过滤)和(TagName,TagValue)地图。 GUI模型可能会为每次GUI更新调用这些方法数千次,因此一些索引的概念可以使其更好地工作。不幸的是,多重标签类型意味着它会很笨拙,除非我将所有东西都作为一个通用对象返回并且做了一堆“TagValue instanceof Type”条件。

我已经研究过使用反射和Apache的DynaBeans,但是编码这个与GUI模型一起工作看起来很痛苦和尴尬。有一个更好的方法吗???一些图书馆或设计模式?

所以,我的问题是,有没有更好的方法?一些图书馆或设计模式,将简单的整个事情?

回答

1

我不认为你应该考虑任何这些属性作为实际的成员变量。你应该有一个“属性”对象,它包含一个属性(这将类似于一个成员变量)和一个具有属性集合的“集合”对象(它将像一个类)。

由于这些属性和集合真的没有与它们相关的代码,这将毫无意义,以实现它们的对象(将在屁股真正的痛苦)

你的属性和集合需要保存所有特定于他们的数据。例如,如果一个字段最终写入数据库,它需要将表名存储在某个地方。如果需要写入屏幕,那也需要存储在某个地方。

范围/值检查可以“添加”到属性,因此当您定义属性的数据类型时,可能会有一些文本显示“MaxLength(12)”,它将实例化一个名为MaxLength的类值12,并将该类存储到属性中。只要属性的值发生变化,新的值就会被传递给已经应用到这个类的每个范围检查器。可以有多种与该课程相关的动作。

这只是基础。我已经设计出这样的东西,这是一个很好的工作,但它比试图用一种直白的语言简单得多。

我知道这看起来像是太多的工作了(它应该如果你真的得到我建议的),但记住它,最终你可能会去“哼,也许这是值得的尝试毕竟“。

编辑(回应评论):

我想过尝试与注册表/关键的事情(我们还在讨论属性值对)工作,但它不太适合。

您试图将DAO放入Java对象中。这真的很自然,但我认为这只是解决DAO/DTO问题的一种不好的方法。 Java对象具有对这些属性起作用的属性和行为。对于你正在做的事情,没有任何行为(例如,如果用户创建一个“生日”字段,你将不会使用目标代码来计算他的年龄,因为你不知道生日是什么)。

所以,如果你抛弃了对象和属性,你将如何存储这些数据?

让我走一个非常简单的第一步(非常接近您提到的注册表/标记系统):在哪里使用对象,使用散列表。对于属性名称,使用键,对于属性值,使用散列表中的值。

现在,我将介绍我用来增强这个简单模型的问题和解决方案。

问题: 你已经失去了强类型,你的数据是非常自由的格式(这可能是坏的)

解决方案: 作出“属性”基类中的场所使用散列表中的值。扩展IntegerAttribute,StringAttribute,DateAttribute,...的基类不要允许不适合该类型的值。现在你已经拥有了强大的输入,但它是运行时而不是编译时 - 可能没问题,因为你的数据在运行时实际上是DEFINED的。

问题: 格式化程序和验证程序

解决方案: 必须创建一个插件为您的属性基类的能力。您应该可以为任何属性设置“setValidator”或“setFormatter”。验证器/格式化程序应该使用该属性 - 因此,当您保存属性时,您可能必须能够将它们序列化到数据库。

这里很好的一点是,当你在属性上执行“attribute.getFormattedValue()”时,它已经预先格式化显示。如果任何验证失败,attribute.setValue()将自动调用验证器并抛出异常或返回错误代码。

问题: 如何在屏幕上显示这些信息?我们已经有了getFormatted(),但它在屏幕上显示的是什么?我们用什么标签?什么样的控件应该编辑这个字段?

解决方案: 我会将所有这些东西存储在每个属性中。 (顺序应该存储在类中,但是因为这是一个哈希表,所以它不会工作 - 那么我们会在下一步)。如果您存储显示名称,用于呈现此内容的控件类型(文本字段,表格,日期...)和数据库字段名称,则此属性应具有它需要与显示和数据库I/O例程编写来处理属性。

问题: 该Hashtable是一个糟糕的DAO接口。

解决方案: 这是绝对正确的。你的散列表应该被包装在一个知道它所拥有的属性集合的类中。它应该能够将自身(包括其所有属性)存储到数据库 - 可能需要辅助类。它应该可以通过一个方法调用来验证所有的属性。

问题: 如何实际使用这些东西?

解决方案: 由于它们包含自己的数据,因此它们在系统中任何与它们交互的地方(比如屏幕或数据库)都需要一个“适配器”。

假设您正在展示一个屏幕来编辑您的数据。您的适配器将传递一个框架和一个基于散列表的DTO。

首先它会按顺序遍历属性列表。它会问第一个属性(比如一个字符串)它想要用来进行编辑的控件类型(比如文本字段)。

它会创建一个文本字段,然后它会将一个侦听器添加到将更新数据的文本字段,这会将您的数据绑定到屏幕上的控件。

现在只要用户更新控件,更新就会发送到属性。该属性存储新值,你就完成了。

(这将通过一个“OK”按钮,所有的值在一次迁移的概念很复杂,但我仍然会设专人之前每个绑定,然后使用“OK”作为触发。)​​

这种绑定可能很困难。我用手工完成了这个工作,一旦我使用了一个名为“JGoodies”的工具包,这个工具包内置了一些绑定功能,这样我就不必亲自编写每个可能的绑定组合,但是我不确定从长远来看它节省了很多时间。

这太长了。我将在某一天创建一个DAO/DTO工具包 - 我认为Java对象完全不适合作为DAO/DTO对象。

如果您仍然难住,请随时Email/IM me - billmail在gmail ..

0

您是否使用关系数据库绑定?研究面向文档的数据库(如couchDB)可能是值得的。它会给你灵活性,你需要存储你想要的任意强类型对象,并且还可以让你查询这些对象。我相信还有一些用于访问couchDB的Java库。

+0

我不想与任何特定系统紧密联系,但我已经在考虑使用Apache Jackrabbit作为后备存储。我大多需要一个很好的DAO模型来表达一个好的通用接口。 – BobMcGee 2009-04-23 20:01:05

+0

我对Jackrabbit并不熟悉,但看起来它实现了Java内容库规范。该规范应该为您提供通用节点,属性等API。至于DAO,看起来Spring对JCR有很好的支持,并且使用它们的框架实现了DAO: https://springmodules.dev.java。 net/docs/reference/0.6/html/jcr.html – Andrew 2009-04-23 20:11:42

1

我从你的问题中假设一个“资源”是你的系统中有一些与它关联的“标签”实体的实体。如果我的假设是正确的,这里的香草DAO接口,让我知道,如果这是你在想什么:

public interface ResourceDAO { 
    void store(Resource resource); 
    void remove(Resource resource); 
    List<Resource> findResources(QueryCriteria criteria); 
    void addTagsToResource(Resource resource, Set<Tag> tags); 
} 

这里的想法是,你会实现这个接口的任何数据存储机制,你有可用的,并且应用程序将通过此接口访问它。实现类的实例将从工厂获得。

这是否符合你的想法?

您提到的问题的另一方面是需要根据类型(需要“TagValue instanceof Type”条件)需要与需要不同行为的多个不同TagType进行竞争。 Visitor pattern可以以优雅的方式为您处理。

+0

Visitor模式对于处理多态和可插入显示/处理/验证听起来很有用,我正在研究它。 您的DAO模型与我正在考虑的存储接口非常相似,但我想知道您认为Resource对象在接口方面会是什么样子。 – BobMcGee 2009-04-27 15:30:38