我试图理解“查询对象设计模式”。我无法为它找到好的和简单的例子。有人可以帮助我理解这种设计模式的用途以及我们可以在什么问题上实现它?
3 回答
查询设计模式通常与存储库设计模式结合使用。
让我们举个例子,然后我会给出一篇不错的文章来阅读。假设我们有一个数据库,我们在其中存储有关客户及其订单等的信息。
然后我们像这样创建一个初始存储库:
class CustomerRepository() {
Customer GetById(int id) { // implementation }
void DeleteCustomer(int id) { // impl }
Customer GetCustomerWithOrder(int orderId);
Customer[] GetCustomersWithOrdersMoreThan(int numberOfOrders);
}
正如您所看到的,对于每个查询,我们在存储库中创建了一个方法,该方法非常适合有限数量的查询,但是当我们有很多查询并且它们开始变得复杂时有很多组合(例如,让我有购买的客户超过 1000 并且住在纽约并且他们的信用额度小于 3000)那么我们最终会得到一长串方法,甚至更糟糕的是,在存储库中以查询的形式泄露一些我们不想要的业务逻辑即将发生。
因此,要重构我们将存储库更改为以下内容:
class CustomerRepository() {
Customer[] Get(Query query) { // implementation }
void DeleteCustomer(int id) { // impl }
}
如您所见,我们正在传递一个查询对象,它以对象的形式表示我们的查询,并且存储库有一个也是唯一的存储库来执行该查询并将结果返回给我们。
现在如何实现该查询对象以及如何构建它将需要大量代码,所以在这一点上,我将引导您阅读这篇精彩的文章。它在 C# 中,但您会发现它非常有用,您还可以查看 NHibernate 使用的Criteria API ( Java ) 来查看不同但相似的实现。
查询对象表示用领域语言编写的查询,是查询对象模式的实现。Fowler 描述的查询对象模式是“表示数据库查询的对象”。如果没有某种查询机制,存储库将充斥着无数的检索方法,例如可以在以下代码片段中看到:
public interface ICustomerRepository
{
IEnumerable<Customer> FindAll();
IEnumerable<Customer> FindAllVIPCustomers();
IEnumerable<Customer> FindByOrder(Guid ID);
IEnumerable<Customer> FindAllCustomersThatHaveOutstandingOrders();
…
}
相反,查询对象允许构建任何查询,然后将其发送到存储库以得到满足。查询对象模式的主要好处是它完全抽象了底层数据库查询语言,从而将数据持久性和检索的基础架构问题排除在业务层之外。然而,在某些时候,需要创建数据库的原始查询语言;这是使用特定于数据库的 QueryTranslator 来实现的,该 QueryTranslator 接受查询对象并将它们转换为数据库的语言。
来自 Pro ASP.NET 设计模式书。
看看我为 NHibernate 编写的查询对象模式库:https ://github.com/shaynevanasperen/NHibernate.Sessions.Operations