代码之家  ›  专栏  ›  技术社区  ›  BobMcGee

如何为具有可扩展属性的资源编写DAOS?

  •  0
  • BobMcGee  · 技术社区  · 15 年前

    我想写一个嵌入的( 不是网络,不是企业 JAVA中的内容管理系统,重点是组织和易用性和可伸缩性,以100000个左右的项目。用户系统应该能够创建和定义与唯一资源关联的元数据项,以便进行搜索。

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

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

    问题在于,资源需要同时表现为元组(用于表格查看/排序/过滤)和as(标记名、标记值)映射。对于每个图形用户界面更新,图形用户界面模型可能会调用这些方法数千次,因此一些索引的概念将使这些方法更好地工作。不幸的是,多个标记类型意味着它将很难处理,除非我将所有内容作为通用对象返回,并执行一大堆“tagValue instanceof type”条件。

    我曾经研究过使用反射和Apache的Dynabeans,但是将其编码为与GUI模型一起工作看起来是痛苦和尴尬的。有更好的方法吗?你说什么?一些图书馆或设计模式?

    所以,我的问题是,有更好的方法吗?一些库或设计模式会简单地处理整个事情?

    3 回复  |  直到 15 年前
        1
  •  1
  •   Bill K    15 年前

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

    因为这些属性和集合实际上没有与它们相关联的代码,所以将它们作为对象来实现是没有意义的(这将是真正的麻烦)。

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

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

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

    我知道这似乎是目前工作太多了(如果你真的得到了我的建议,应该这样做),但请记住,最终你可能会去“嗯,也许这毕竟值得一试”。

    编辑(对评论的响应):

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

    您正试图将DAOS安装到Java对象中。这是很自然的,但我开始认为这只是解决DAO/DTO问题的一个糟糕方法。Java对象具有对这些属性起作用的属性和行为。对于您正在做的事情,没有任何行为(例如,如果用户创建了“生日”字段,则不会使用对象代码来计算他的年龄,因为您实际上不知道生日是什么)。

    所以,如果您放弃拥有对象和属性,您将如何存储这些数据?

    让我来进行一个非常简单的第一步(这非常接近您提到的注册表/标记系统):在应该使用对象的地方,使用哈希表。对于属性名,使用键;对于属性值,使用哈希表中的值。

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

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

    解决方案: 为“attribute”创建一个基类,以代替哈希表中的值。扩展integerattribute、stringattribute、dateAttribute等的基类…不允许不适合该类型的值。现在您有了强类型,但它是运行时而不是编译时——也许可以,因为您的数据实际上是在运行时定义的。

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

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

    这里的好部分是,当您在属性上执行“attribute.getFormattedValue()”时,它是为显示而预先格式化的。attribute.setValue()将自动调用验证器并引发异常,或者在任何验证失败时返回错误代码。

    问题: 如何在屏幕上显示这些内容?我们已经有了getFormatted(),但是它在屏幕上显示在哪里?我们用什么做标签?什么类型的控件应编辑此字段?

    解决方案: 我将把所有这些东西存储在每个属性中。(顺序应该存储在类中,但是因为这是一个哈希表,所以它不起作用——那么我们下一步将讨论这个问题)。如果存储显示名称、用于呈现此项的控件类型(文本字段、表、日期…)和数据库字段名称,则此属性应具有与显示交互所需的所有信息,以及为处理属性而编写的数据库I/O例程。

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

    解决方案: 这是绝对正确的。哈希表应该包装在一个类中,该类知道它所包含的属性集合。它应该能够将自己(包括它的所有属性)存储到数据库中——可能需要助手类的帮助。它应该能够用一个方法调用来验证所有属性。

    问题: 如何实际处理这些事情?

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

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

    首先,它将按顺序遍历属性列表。它会询问第一个属性(比如说字符串)想要使用哪种控件进行编辑(比如说文本字段)。

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

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

    (这将被一个“确定”按钮的概念复杂化,该按钮一次传输所有值,但我仍然会在手前设置每个绑定,并使用“确定”作为触发器。)

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

    这太长了。我应该在将来创建一个DAO/DTO工具包——我认为Java对象根本不适合做DAO/DTO对象。

    如果你仍然感到困惑,请随时给我发电子邮件/给我——Gmail的Bill.Kress……

        2
  •  1
  •   Edward Q. Bridges    15 年前

    我假设从您的问题来看,“资源”是您系统中的一个实体,它有一些与之相关联的“标记”实体。如果我的假设是正确的,这里有一个普通的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”条件)。这个 Visitor pattern 可以优雅地为您处理这个问题。

        3
  •  0
  •   Andrew    15 年前

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