关于 Vaadin / Hibernate 应用开发的结构的考虑

关于 Vaadin / Hibernate 应用开发的结构的考虑

总体来说,用户界面与业务模型的互动牵扯很多 配置信息(比如,当使用一个选择的时候,可以用 Combo,也可以用 List,完全处于美观或者方便的需要,具体使用哪一个是用户的决定,而这个决定即属于上面所说的配置信息,再比如说,使用一个文本输入的时候,可以用单行输入,也可以多行输入,还可以按照密码输入,也可以出于各方面因素的考虑,也是配置信息)。另外还需要很多 搭建/配置行为,包括初始化控件,配置控件,将控件与业务模型进行连接,配置数据校验以及类型转换等等行为。除了一些特殊行为,这些行为应该多数由工具包提供。

工具包应该实现一个灵活的 FormFieldFactory。FormFieldFactory 根据一个 context 来生成 Field,对 Field 进行各种配置,并且将 Field 和 Property 进行合理的连接,以便实现 validate 和 type conversion等各种操作。FormFieldFactory 实际上做得很少,也没有任何灵活性。灵活性全部在 context 中。具体而言,context 包含了上述 配置信息搭建/配置行为。配置信息方面,context包含了用来生成 Field 的各个相关元素(也就是下面要说到的默认信息)以及用户的指示等等。搭建/配置方面,context包含了具体实现的 command。通常是一个 command chain,由用户提供或者指定。但是,工具包应该提供一个或者多个通用的 command,供用户在大多数情况下使用。


主要的考虑有以下几点:

    工具包提供的默认行为应该可以在大多数情况下满足需要。
    仅仅特殊的指示和特殊的操作需要用户提供配置信息和操作的实现。
    以上配置信息和搭建/配置行为应该互相分开。
    配置信息 / 搭建配置行为各自在一个适合的 / 集中的地方进行配置,以便管理。
    配置信息以及搭建/配置行为应该灵活,容易扩展。

关于配置信息的公开界面的考虑:

配置信息是要可以被各个搭建/配置行为的具体实现查询到的。各个搭建/配置行为的具体实现会问这样的问题:
        我正在处理这个context(包含了正在为了哪一个form,哪一个Item,哪一个propertyId,来生成Field),希望获得这样的指示(比如,“Field 应该用哪个具体实现类?”)。因此,界面可以是:

    Context {
        Object getConfigurationInfo(Object configurationType)
        // 以下仅仅是为了免得客户进行类型转换
        String getStringConfigurationInfo(Object configurationType)
    }

这样,Context 会有很多具体代码,但是省掉了各个搭建/配置行为具体实现去写重复的代码来或者这些关于Context的一些进一步信息。

关于配置信息的考虑

配置信息分为默认信息和特定指示信息。如果一个搭建/配置行为同时参考特定指示信息和默认信息,应该让特定指示信息优先于默认信息。

默认信息是本来就存在的,随着业务模型或者UI等于生俱来的(比如业务模型的类的名称,属性的名称等),或者虽然是用户配置的信息,但不是专门为生成用户界面而准备的信息(比如hibernate 的元数据)。默认信息不需要配置或者至少不需要专门配置,因此可以很分散,总之让搭建/配置程序可以得到即可。默认信息应该可以允许搭建/配置程序在多数情况下生成可以使用的,不需要进一步修改的控件。

特定指示信息与默认信息相反,是专门为了搭建/配置用户界面而准备的,应该集中设置和管理,这样比较方便查找和修改。特定指示信息应该仅仅在特殊情况下用来进行非常规配置(比如虽然业务模型是一个String类型的属性,但是用选择来进行输入),或者对默认配置的进一步修饰(比如默认用选择控件,但指示信息进一步指示使用哪一样选择控件)。

指示信息应该集中,从而方便管理。指示信息还应该尽量通用,即不是仅仅为了某搭建/配置程序而准备(虽然可能经常如此),而是为了描述用户所希望的结果。指示信息还应该便于各个搭建/配置程序查询。

关于默认信息的具体考虑

FormFieldFactory 可以得到的各种信息都可以成为默认信息的来源,它们包括:

    Item - 在与 Hibernate 进行结合的时候应该是 BeanItem,那么 getBean() 可以得到 bean,进一步可以得到其 class, Hibernate 的 metadata,以及一些标记。这些 class, metadata 以及标记应该都可以作为智能生成 Field 的一些判断。但是,bean 属于model,不应该过分地将表现层的东西(比如文本框的大小什么的)放到这里。如果某些属性是与 model 相关而不因表现层改变的,比如密码不论用什么表现层都应该按照密码输入对待,那么在这里进行标注似乎是合理的。

    id - BeanItem 使用属性的名字作为 id,可以作为判断条件,可以结合 bean 的类进行判断。

    Form - 似乎没有什么特别可以作为判断条件的。但不妨作为参数传递给处理器。

默认信息需要用代码来获得,具体实现可以先在 Context 上面来实现,直接把获得具体信息的代码写在 Context 上面。当然,属于对这些信息进一步分析的代码就应该由具体的搭建/配置实现的代码来完成了。

关于特定指示信息的具体考虑

特定指示信息应该放在 context 里面,从而可以由所有的搭建/配置的具体实现单元参考。作为一种具体实现,指示信息可以按照这样的双层方式组织:第一层是以作为信息类型的Object为索引的Map,第二层按照以下几种方式查询/设置(按照以下次序,最特殊的在前,最通用的在后,以解决冲突问题):

    关于某 bean class / 某 property
    关于某 property (这两者都在 Context 里面有,因此完全可以 Context 自行得到)
    仅仅在用到的时候实现:符合某种 condition - 使用一个 condition framework (这个可以由用户在指定)

关于搭建/配置行为的实现的考虑

为了使得这些行为尽可能得可以重用,这些行为应该按照上面的配置信息(默认信息以及特定指示信息)进行动作。

行为可以考虑用 chain of responsibility 模式实现。工具包提供很多行为的实现(command),还提供一个或者几个一般用途的 chain 共用户选择使用。用户也可以在具体应用中提供特殊 chain,两者进行组合来实现。

关于具体的要完成的功能以及如何完成的考虑

要完成的功能 如何完成
生成 Form 中的 Field

默认行为和 Property 的类型有很大关系,比如 
    enum 应该用选择控件,
    boolean 用checkbox,
    String 用文本输入框
    Date 用日期输入框
    数值类型用文本输入框

特殊行为根据用户指示,比如 enum 的选择控件使用 ComboBox 还是 ListSelect。具体的做法可以是在特定指示信息中指定具体的类来操作。

在 Field 之间和 pojo entity 之间进行连接以及数据类型转换

需要考虑 Field 在 commit() 的时候将何种类型的值传送给 datasource.setValue()。按照 AbstractField.commit()源代码,应该是getValue()。按照Field接口的文档,getValue()的类型应该是 getType()。因此,可以考虑以下实现:


如果类型相符 - 就是说 field.getType() == datasource.getType(),可以直接连接,不需要进行类型转换。

如果类型不相符,则应该连接一个类型转化器,连接在两个 Property 之间。

converter.setValue() 接受 field.getType()类型参数,然后进行转换,再调用 datasource.setValue()。反之,converter.getValue() 从 datasource.getValue() 取得值,然后进行转换,再返回给调用者。 converter 应该实现 property 接口。

默认实现可以维护一组转化器,自动在 Field 和 data source 之间搭建类型转换器。


对 Field 进行装饰 - 比如定义文本栏的尺寸大小,secret属性,等等 默认行为可以不进行任何修饰或者进行默认修饰。其他的可以在特定指示中查找,如果有特定指示,则进行修饰。
设置 Field 的 Caption 默认的实现可以将 bean name + property id 当作键值,然后查找一个设定的 resource boundle。
对各个 Field 的 validate
默认行为,可以查看是否 hibernate validate 或者其他 validation framework 的 validate 适用,如果适用,则生成一个对应的 validator 适配器,进行 validate。
对 form 进行的 validate
默认行为:如果 form.getItemDataSource()是一个BeanItem,getBean返回一个 hibernate 管理的 bean,可以自动生成一个适配器 validator 给 form。
权限控制
根据用户的 id, roles, 以及 bean/property id,自动查找该用户对应的权限。
   
   
   
   

你可能感兴趣的:(关于 Vaadin / Hibernate 应用开发的结构的考虑)