0

我正在尝试用 Java 编写一个嵌入式(不是 Web,不是企业)内容管理系统,重点是组织、易用性和可扩展到 100,000 个左右的项目。用户和系统应该能够创建和定义可以与独特资源相关联的元数据项,以允许搜索。

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

我已经决定从 GUI 中抽象出存储模型以实现可扩展性很重要;显而易见的方法是对每个资源使用数据访问对象 (DAO)。但是,我不知道如何编写支持可变数量标签并能正确扩展的 DAO。

问题是资源既需要表现为元组(用于表格查看/排序/过滤),又需要表现为 (TagName,TagValue) 映射。GUI 模型可能会在每次 GUI 更新时调用这些方法数千次,因此一些索引的概念会使这一切工作得更好。不幸的是,多种标签类型意味着它会很尴尬,除非我将所有内容都作为通用对象返回并做一团糟的“TagValue instanceof Type”条件。

我已经研究过使用反射和 Apache 的 DynaBeans,但是将其编码为与 GUI 模型一起使用看起来既痛苦又尴尬。有一个更好的方法吗???一些库或设计模式?

所以,我的问题是,有没有更好的方法?一些库或设计模式可以简单地完成整个事情?

4

3 回答 3

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);
}

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

这符合你的想法吗?

您提到的问题的另一个方面是必须处理多个不同的 TagTypes,这些 TagTypes 根据类型需要不同的行为(需要“TagValue instanceof Type”条件)。访问者模式可以优雅地为您处理这个问题。

于 2009-04-24T01:22:44.763 回答
1

我认为您不应该将这些属性中的任何一个视为实际的成员变量。您应该有一个包含属性(类似于成员变量)的“Property”对象,以及一个具有属性集合(类似于类)的“Collection”对象。

由于这些属性和集合实际上并没有与之关联的代码,因此将它们作为对象来实现是没有意义的(而且会让人头疼)

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

范围/值检查可以“添加”到属性中,因此当您定义属性是什么类型的数据时,您可能会有一些文本显示“MaxLength(12)”,它将实例化一个名为 MaxLength 的类,其值为 12,并将该类存储到属性中。每当属性的值更改时,新值将传递给已应用于此类的每个范围检查器。可以有许多类型的动作与该类相关联。

这只是基础。我已经设计了这样的东西,这是一个很好的工作,但它比尝试用一种直接的语言来做要简单得多。

我知道现在这似乎工作太多了(如果你真的明白我的建议,它应该),但请记住它,最终你可能会去“嗯,也许这毕竟值得一试” .

编辑(回复评论):

我考虑过尝试使用注册表/键的东西(我们仍在谈论属性值对),但它不太合适。

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

因此,如果您丢弃拥有对象和属性,您将如何存储这些数据?

让我先迈出非常简单的第一步(这与您提到的注册表/标签系统非常接近):在您使用对象的地方,使用哈希表。对于您的属性名称,使用键,对于属性值,使用哈希表中的值。

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

问题:您丢失了强类型,并且您的数据格式非常自由(这可能很糟糕)

解决方案:为“属性”创建一个基类,以代替哈希表中的值。为 IntegerAttribute、StringAttribute、DateAttribute 扩展该基类...... 不要允许不适合该类型的值。现在你有强类型,但它是运行时而不是编译时——可能没问题,因为你的数据实际上是在运行时定义的。

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

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

这里好的部分是,当您对属性执行“attribute.getFormattedValue()”时,它会预先格式化以供显示。如果任何验证失败,attribute.setValue() 将自动调用验证器并抛出异常或返回错误代码。

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

解决方案:我会将所有这些内容存储在每个属性中。(订单应该存储在类中,但由于这是一个哈希表,所以它不会工作——好吧,我们接下来会谈到)。如果您存储显示名称、用于呈现此的控件类型(文本字段、表格、日期...)和数据库字段名称,则此属性应具有与显示和数据库交互所需的所有信息/ O 编写处理属性的例程。

问题:哈希表对于 DAO 来说是一个糟糕的接口。

解决方案:这是完全正确的。您的哈希表应该包装在一个知道它所拥有的属性集合的类中。它应该能够将自己(包括它的所有属性)存储到数据库中——可能在帮助类的帮助下。它应该能够通过单个方法调用来验证所有属性。

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

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

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

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

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

现在,每当用户更新控件时,更新都会发送到 Attribute。该属性存储新值,您就完成了。

(这会因为一次传输所有值的“OK”按钮的概念而变得复杂,但我仍然会事先设置每个绑定并使用“OK”作为触发器。)

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

这太长了。总有一天我应该创建一个 DAO/DTO 工具包——我认为 Java 对象根本不适合作为 DAO/DTO 对象。

如果您仍然感到困惑,请随时通过电子邮件/即时消息给我——gmail 的 bill.kress。

于 2009-04-24T01:51:51.137 回答
0

您是否与使用关系数据库有关?研究面向文档的数据库(例如 couchDB)可能是值得的。它将为您提供存储所需任意强类型对象所需的灵活性,并让您也能够查询这些对象。我相信也有一些用于访问 couchDB 的 Java 库。

于 2009-04-23T19:53:19.563 回答