Java 道模式与开闭原理

Java 道模式与开闭原理,java,design-patterns,dao,finder,open-closed-principle,Java,Design Patterns,Dao,Finder,Open Closed Principle,我见过很多旧的、基于JDBC的DAO代码,这些代码通常是从CRUD方法开始的。我的问题特别与检索方法或“查找者”有关。通常,我发现DAO从两种方法开始: 查找并返回所有 基于唯一标识符检索特定实例 通常情况下,这两个发现者是不够的。我通常看到一个DAO类被反复修改以添加查找器方法,如下所示: 查找并返回所有where{condition} 当需要支持新的{conditions}或修改现有方法以添加新参数作为标志来修改方法内的SQL查询以支持附加条件时,会添加更多的方法 这是一种丑陋的方法

我见过很多旧的、基于JDBC的DAO代码,这些代码通常是从CRUD方法开始的。我的问题特别与检索方法或“查找者”有关。通常,我发现DAO从两种方法开始:

  • 查找并返回所有
  • 基于唯一标识符检索特定实例
通常情况下,这两个发现者是不够的。我通常看到一个DAO类被反复修改以添加查找器方法,如下所示:

  • 查找并返回所有where{condition}
当需要支持新的{conditions}或修改现有方法以添加新参数作为标志来修改方法内的SQL查询以支持附加条件时,会添加更多的方法

这是一种丑陋的方法,违反了开放-封闭原则。每当需要支持一些新的检索条件时,看到DAO类不断地被修改,我总是很恼火。对这个问题的研究通常会指向存储库模式,以及将检索条件封装为或查询对象,然后将它们传递给查找器方法。但是,只有当您拥有整个数据集的内存集合或者使用某种ORM(我正在使用较旧的JDBC代码)时,这才似乎是可行的

我考虑了一种解决方案,它将DAO管理的整个数据集作为内存中的集合进行惰性加载,然后使用规范模式作为查询进行检索。然后,我在集合上实现了某种观察器,在调用creates、updates或deletes方法时只更新数据库。但很明显,性能和可伸缩性会受到严重影响

有什么想法吗


感谢您到目前为止的回复。我有一个想法——您对使用命令/策略模式封装数据访问请求有什么看法?每个具体的命令都可以表示一种特定的访问,并可以传递给调用程序。我最终会得到许多具体的命令类,但每一个都只关注一种访问,并且应该是非常可测试和隔离的

    public abstract class Command<R>{
       public <R> execute();
       public void setArguments(CommandArguments args){
          //store arguments  
       }
    }

    //map based structure for storing and returning arguments
    public class CommandArguments{
         public String getAsString(String key);
         public String getAsInt(String key);
         //... others
    }

    //In some business class...
    Command command = CommandFactory.create("SearchByName");
    CommandArguments args = new CommandArguments();
    args.setValue("name", name);
    // others
    command.setArguments(args);
    List<Customer> list  = command.execute();
公共抽象类命令{
公共执行();
public void setArguments(CommandArguments args){
//存储参数
}
}
//用于存储和返回参数的基于映射的结构
公共类命令参数{
公共字符串getAsString(字符串键);
公共字符串getAsInt(字符串键);
//……其他
}
//在一些商务舱。。。
Command=CommandFactory.create(“SearchByName”);
CommandArguments args=新CommandArguments();
args.setValue(“名称”,名称);
//其他
setArguments(args);
List=command.execute();

与其为每个可能出现的情况创建特定的查找器方法,不如创建一个通用的查找器API? 这可以采取DAO的形式,DAO有一个内部枚举来表示字段,以及一个方法,该方法获取DAO内部类的实例列表,其中字段表示要过滤DAO的哪个字段、要对其应用什么过滤器以及什么条件(and、OR等)

这是一个需要设置的工作,对于小项目来说可能有些过分,但它确实是可行的。
ORM框架通常具有已经内置的类似内容,因此您可能需要考虑采用其中之一(或者至少在设计自己的解决方案时如何实现它,以便将其改装成您的遗留应用程序)。.

我们在数据层ORM中使用了iBatis,并且能够通过传递参数对象和您可能希望用作参数的各种字段来实现您在一个查询中提出的建议

然后,在WHERE子句中,您可以将每个字段指定为条件子句,但前提是其已填充到参数对象中。如果param obj中只有一个字段不为null,那么它将是唯一一个用于过滤结果的字段

因此,如果需要向参数添加字段,只需更改SQL和paramObj即可。然后,您可以有两个方法根据传递的参数组合返回全部或子集,或者至少这种方法可以减少所需的查询数量

e、 g.类似于

SELECT * FROM MY_TABLE
WHERE FIELD_ZERO = paramObj.field0
<isNotNull property="paramObj.field1">AND FIELD_ONE = paramObj.field1</isNotNull>
<isNotNull property="paramObj.field2">AND FIELD_TWO = paramObj.field2</isNotNull>
<isNotNull property="paramObj.field3">AND FIELD_THREE = paramObj.field3</isNotNull>
从MY_表中选择*
其中字段_ZERO=paramObj.field0
和字段_ONE=paramObj.field1
和字段_TWO=paramObj.field2
和字段_三=paramObj.field3

当我实现规范模式时,我试图实现一个通用的查找器,或者更确切地说是一个可扩展的查找器。这与我所寻找的非常接近,因为在单查找器方法中传递的SearchCriteria对象也是从域的角度实现的。我不希望searchCriteria对象本身绑定到特定的实现,因为它首先会破坏DAOs的目的,您可以创建一个SearchCriteria类型的基础结构,其中有一个单独的criteria类链接到每个DAO,而不将DAO链接回criteria类。+1我在iBatis中也做了同样的事情,支持可选的日期范围、可选的谓词等。它工作得很好。(顺便说一句,您的示例中不需要主键条件。)我想这可能适用于相对简单的where子句。但是,如果条件变得更加复杂,或者某些检索依赖于来自另一个表的联接,则很难进行扩展。例如,我可以有一个CustomerDAO,它只根据名称检索客户。但是,如果我还想根据需要从另一个表中获取信息的未清余额检索客户,该怎么办。我的DAO中有一个复杂的查询生成器,只是为了预测可以传递的各种不同参数。@eplozada true您需要更多的