简体   繁体   English

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

[英]How can I write DAOs for resources with extensible properties?

I'm trying to write an embedded ( NOT web, not enterprise ) content management system in Java, with a focus on organization and ease of use and scalability to 100,000 or so items. 我正在尝试用Java编写嵌入式( 不是Web,不是企业 )内容管理系统,重点是组织和易用性以及可扩展到100,000个左右的项目。 The user & system should be able to create and define metadata items which can be associated with unique resources, to allow for searching. 用户和系统应该能够创建和定义可以与唯一资源相关联的元数据项,以便进行搜索。

For example, they can create a tag "ProjectName" which takes String values. 例如,他们可以创建一个带有字符串值的标签“ ProjectName”。 Then they can tag a bunch of resources as belonging to projects "Take Over the World" or "Fix My Car." 然后,他们可以将一堆资源标记为属于“ Take Over the World”或“ Fix My Car”项目。 The tags are strongly typed, so a tag may store single or multiple string(s), integer(s), double(s), etc. Each tag type should have formatters and input validators to allow editing. 标签是强类型的,因此标签可以存储单个或多个字符串,整数,双精度等。每种标签类型都应具有格式化程序和输入验证器以允许编辑。

I've decided that it is important to abstract the storage model from the GUI, to allow for scalability; 我已经决定从GUI中抽象存储模型以实现可伸缩性非常重要。 the obvious way to do this is to use data access objects (DAOs) for each resource. 这样做的明显方法是为每个资源使用数据访问对象(DAO)。 However, I can't figure out how to write DAOs that support a variable number of tags and will scale properly. 但是,我不知道如何编写支持可变数量的标签并且可以正确缩放的DAO。

The problem is that resources need to behave both as tuples (for tabular viewing/sorting/filtering) and as (TagName,TagValue) maps. 问题在于资源需要既表现为元组(用于表格查看/排序/过滤)又表现为(TagName,TagValue)映射。 The GUI models may call these methods potentially thousands of times for each GUI update, so some notion of indexing would make it all work better. 对于每个GUI更新,GUI模型可能会调用这些方法数千次,因此某种索引概念会使它们都更好地工作。 Unfortunately, the multiple tag types mean it'll be awkward unless I return everything as a generic Object and do a whole mess of "TagValue instanceof Type" conditionals. 不幸的是,多个标记类型意味着除非我将所有内容都作为通用对象返回并完全破坏“ TagValue instanceof Type”条件,否则它将很尴尬。

I've looked into using reflection and Apache's DynaBeans, but coding this to work with GUI models looks just painful and awkward. 我已经研究过使用反射和Apache的DynaBeans,但是对其进行编码以与GUI模型一起使用看起来很痛苦且笨拙。 Is there a better way to do this??? 有一个更好的方法吗??? Some library or design pattern? 一些库或设计模式?

So, my question is, is there a better way? 所以,我的问题是,有没有更好的方法? Some library or design pattern that would simply this whole thing? 一些库或设计模式可以简单地完成整个工作吗?

I assume from your question that a "resource" is an entity in your system that has some "tag" entities associated with it. 根据您的问题,我认为“资源”是系统中的一个实体,具有与之关联的一些“标记”实体。 If my assumption is correct, here's a vanilla DAO interface, let me know if this is what you're thinking: 如果我的假设是正确的,那么这里是一个普通的DAO接口,请让我知道这是否是您的想法:

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

The idea here is that you would implement this interface for whatever data storage mechanism you have available, and the application would access it via this interface. 这里的想法是,您将为可用的任何数据存储机制实现此接口,并且应用程序将通过此接口访问它。 Instances of implementation classes would be obtained from a factory. 实现类的实例将从工厂获得。

Does this fit with what you're thinking? 这符合您的想法吗?

The other aspect of the problem you mention is having to contend with multiple different TagTypes that require different behavior depending on the type (requiring "TagValue instanceof Type" conditionals). 您提到的问题的另一方面是必须应对多个不同的TagType,这些TagType根据类型需要不同的行为(需要“ TagValue instanceof Type”条件)。 The Visitor pattern may handle this for you in an elegant way. 访客模式可以为您提供优雅的处理方式。

I don't think you should consider any of these properties as actual member variables. 我认为您不应该将这些属性中的任何一个视为实际的成员变量。 You should have a "Property" object that contains a property (which would be analogous to a member variable), and a "Collection" object that has collections of properties (which would be like a class). 您应该有一个“属性”对象,它包含一个属性(类似于成员变量),还有一个“集合”对象,它具有多个属性集合(就像一个类)。

Since these attributes and collections don't really have code associated with them, it would make no sense to implement them as objects (and would be a real pain in the butt) 由于这些属性和集合实际上没有与之关联的代码,因此将它们实现为对象没有任何意义(这确实是一个麻烦)

Your attributes and collections need to hold ALL the data specific to them. 您的属性和集合需要保存所有特定于它们的数据。 For instance, if a field is eventually written to the database, it needs to have it's table name stored somewhere. 例如,如果一个字段最终被写入数据库,则需要将其表名存储在某个地方。 If it needs to be written to the screen, that also needs to be stored somewhere. 如果需要将其写入屏幕,则还需要将其存储在某个位置。

Range/value checking can be "Added" to the attributes, so when you define what type of data an attribute is, you might have some text that says "MaxLength(12)" which would instantiate a class called MaxLength with the value 12, and store that class into the attribute. 可以将范围/值检查“添加”到属性,因此,当定义属性是什么类型的数据时,可能会有一些文字“ MaxLength(12)”,它将实例化名为MaxLength的值12的类。并将该类存储到属性中。 Whenever the attribute's value changes, the new value would be passed to each range checker that has been applied to this class. 每当属性的值更改时,新值就会传递到已应用于此类的每个范围检查器。 There can be many types of actions associated with the class. 与该类关联的动作可以有很多类型。

This is just the base. 这只是基础。 I've designed something like this out and it's a good deal of work, but it's much simpler than trying to do it in a straight language. 我已经设计出了类似的东西,虽然需要很多工作,但是比尝试使用简单的语言要简单得多。

I know that this seems like WAY too much work right now (it should if you actually get what I'm suggesting), but keep it in mind and eventually you'll probably go "Hmph, maybe that was worth a try after all". 我知道现在这似乎做起来太多了(如果您确实得到了我的建议,应该这样做),但是请记住这一点,最终您可能会选择“ Hmph,也许这值得一试” 。

edit (response to comment): 编辑(回复评论):

I thought about trying to work with the registry/key thing (we're still talking attribute value pairs), but it doesn't quite fit. 我考虑过尝试使用注册表/关键内容(我们仍在讨论属性值对),但这并不完全适合。

You are trying to fit DAOs into Java Objects. 您正在尝试将DAO装入Java对象。 This is really natural, but I've come to see it as just a bad approach to solving the DAO/DTO problem. 这确实很自然,但是我已经将其视为解决DAO / DTO问题的一种不好的方法。 A Java Object has attributes and behaviors that act on those attributes. Java对象具有属性和对这些属性起作用的行为。 For the stuff you are doing, there are no behaviors (for instance, if a user creates an "Birthday" field, you won't be using object code to calculate his age because you don't really know what a birthday is). 对于您正在做的事情,没有任何行为(例如,如果用户创建了“生日”字段,则您将不会使用对象代码来计算其年龄,因为您实际上并不知道生日是什么)。

So if you throw away having Objects and attributes, how would you store this data? 因此,如果不使用对象和属性,该如何存储这些数据?

Let me go with a very simple first step (that is very close to the registry/tag system you mentioned):Where you would have used an object, use a hashtable. 让我开始一个非常简单的第一步(非常接近您提到的注册表/标签系统):在要使用对象的地方,请使用哈希表。 For your attribute names use keys, for the attribute values, use the value in the hashtable. 对于属性名称,请使用键,对于属性值,请使用哈希表中的值。

Now, I'll go through the problems and solutions I took to enhance this simple model. 现在,我将介绍为增强此简单模型而遇到的问题和解决方案。

Problem: you've lost Strong Typing, and your data is very free-format (which is probably bad) 问题:您丢失了“强类型”,并且您的数据是非常自由的格式(可能是不好的)

Solution: Make a base class for "Attribute" to be used in the place of the value in the hashtable. 解决方案:为“属性”创建基类,以在哈希表中的值处使用该属性。 Extend that base class for IntegerAttribute, StringAttribute, DateAttribute, ... Don't allow values that don't fit that type. 为IntegerAttribute,StringAttribute,DateAttribute扩展该基类。...不允许使用不适合该类型的值。 Now you have strong typing, but it's runtime instead of compile time--probably okay since your data is actually DEFINED at runtime anyway. 现在您可以进行强类型化,但是它是运行时而不是编译时-可能还可以,因为您的数据实际上还是在运行时定义的。

Problem: Formatters and Validators 问题:格式化程序和验证程序

Solution: Have the ability to create a plug-in for your attribute base-class. 解决方案:能够为您的属性基类创建插件。 You should be able to "setValidator" or "setFormatter" for any attribute. 您应该可以为任何属性使用“ setValidator”或“ setFormatter”。 The validator/formatter should live with the attribute--so you probably have to be able to serialize them to the DB when you save the attribute. 验证器/格式化程序应与属性一起使用-因此在保存属性时,您可能必须能够将它们序列化到DB。

The nice part here is that when you do "attribute.getFormattedValue()" on the attribute, it's pre-formatted for display. 这里的好处是,当您对属性执行“ attribute.getFormattedValue()”时,该属性已预先格式化以供显示。 attribute.setValue() will automatically call the validator and throw an exception or return an error code if any of the validations fail. 如果任何验证失败,attribute.setValue()将自动调用验证器并抛出异常或返回错误代码。

Problem: How do I display these on the screen? 问题:如何在屏幕上显示这些内容? we already have getFormatted() but where does it display on the screen? 我们已经有getFormatted(),但是它在屏幕上显示在哪里? what do we use for a label? 我们如何使用标签? What kind of a control should edit this field? 什么样的控件应该编辑此字段?

Solution: I'd store all these things inside EACH attribute. 解决方案:我将所有这些内容存储在EACH属性中。 (The order should be stored in the Class, but since that's a hashtable so it won't work--well we'll get to that next). (顺序应该存储在Class中,但是由于这是一个哈希表,因此它将无法正常工作-好吧,我们接下来将继续讨论该顺序)。 If you store the display name, the type of control used to render this (text field, table, date,...) and the database field name, this attribute should have all the information it needs to interact with display and database I/O routines written to deal with attributes. 如果存储显示名称,用于呈现此显示的控件类型(文本字段,表格,日期等)和数据库字段名称,则此属性应具有与显示和数据库I /交互所需的所有信息。编写用于处理属性的O例程。

Problem: The Hashtable is a poor interface for a DAO. 问题:Hashtable对于DAO而言是一个不良的接口。

Solution: This is absolutely right. 解决方案:这是绝对正确的。 Your hashtable should be wrapped in a class that knows about the collection of attributes it holds. 您的哈希表应该包装在一个类中,该类知道它所保存的属性的集合。 It should be able to store itself (including all its attributes) to the database--probably with the aid of a helper class. 它应该能够将自身(包括其所有属性)存储到数据库中-可能借助于辅助类。 It should probably be able to validate all the attributes with a single method call. 它可能应该能够通过一个方法调用来验证所有属性。

Problem: How to actually work with these things? 问题:如何实际使用这些东西?

Solution: Since they contain their own data, at any point in your system where they interact (say with the screen or with the DB), you need an "Adapter". 解决方案:由于它们包含自己的数据,因此在系统中它们进行交互的任何位置(例如与屏幕或与DB交互),都需要一个“适配器”。

Let's say you are presenting a screen to edit your data. 假设您要显示一个屏幕来编辑数据。 Your Adapter would be passed a frame and one of your hashtable-based DTOs. 您的适配器将被传递一个框架和一个基于哈希表的DTO。

First it would walk through the list of attributes in order. 首先,它将按顺序遍历属性列表。 It would ask the first attribute (say a string) what kind of control it wanted to use for editing (let's say a text field). 它会询问第一个属性(例如一个字符串),它想使用哪种控件进行编辑(比如说一个文本字段)。

It would create a text field, then it would add a listener to the text field that would update the data, this binds your data to the control on the screen. 它将创建一个文本字段,然后在该文本字段中添加一个侦听器以更新数据,这会将您的数据绑定到屏幕上的控件。

Now whenever the user updates the control, the update is sent to the Attribute. 现在,无论何时用户更新控件,更新都将发送到属性。 The attribute stores the new value, you're done. 该属性存储新值,完成。

(This will be complicated by the concept of an "OK" button that transfers all the values at once, but I would still set up each binding before hand and use the "OK" as a trigger.) (这将由于“确定”按钮的概念而变得复杂,该按钮可一次传输所有值,但是我仍然会事先设置每个绑定并将“确定”用作触发器。)

This binding can be difficult. 这种绑定可能很困难。 I've done it by hand, once I used a toolkit called "JGoodies" that had some binding ability built in so that I didn't have to write each possible binding combination myself, but I'm not sure in the long-run it saved much time. 一旦使用了内置了某些绑定功能的名为“ JGoodies”的工具包,我就手动完成了这一工作,因此我不必自己编写每种可能的绑定组合,但是从长远来看,我不确定它节省了很多时间。

This is way too long. 这太长了。 I should just create a DAO/DTO toolkit someday--I think Java Objects are not at all suited as DAO/DTO objects. 我应该有朝一日创建一个DAO / DTO工具包-我认为Java对象根本不适合DAO / DTO对象。

If you're still stumped, feel free to Email/IM me-- bill.kress at gmail.. 如果您仍然感到困惑,请随时给我发送电子邮件/即时通讯-gmail.bill.kress。

Are you tied to using a relational database? 您是否要使用关系数据库? It might be worthwhile to look into a document oriented database such as couchDB. 研究面向文档的数据库(例如,couchDB)可能是值得的。 It will give you the flexibility that you need to store any arbitrary strongly typed object that you want and give you the ability to query those objects as well. 它将为您提供存储所需的任何任意强类型对象所需的灵活性,并且还使您能够查询这些对象。 I believe there are some Java libraries for accessing couchDB also. 我相信也有一些Java库可用于访问ouchDB。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM