2010-02-19 63 views
3

当我不得不为Web应用程序设计我的类时,我经常遇到同样的麻烦。要求如下: - 可维护(例如不复制粘贴) - 完全分开的层(业务层不必知道使用哪种数据层方法) - 高性能:不加载无用的数据。关于OOP的基本问题

首先,我有我的所有客户及其地址的表: 代码:

Customer 
--Id 
--Name 
--Address 
----City 
----ZC 
----Street 

现在我想要一个表(在另一页)我所有的客户,他们买了书,我有几种可能性:

1 /我创建一个新类:

代码:

CustomerWithBooks 
--Id 
--Name 
--Books[] 
----ID 
----name 

PRO:我只加载有用的数据 缺点:我在我的用户界面后建立我的班级,并且有复制粘贴。

2 /我将Books []添加到第一堂课。 PRO:一切都在同一个班级,它是可维护的 缺点:我加载地址为空。如果我不加载地址,我可以:延迟加载,但我真的不喜欢它,或者当我使用我的类时,我必须知道我调用的DAL的哪个方法,而且我不喜欢它。

3 /我使用继承: 代码:

ClientBase 
--ID 
--Name 

ClientWithBooks : ClientBase 
--Books[] 

ClientWithAdress : ClientBase 
--Address 

PRO:真的maintenable,我也并不是没有缺点 加载数据:我该怎么办,如果在一个UI我想什么显示书籍和地址?

4/??我希望有一个完美的解决方案

回答

3

你的选择1接近良好,假设我理解正确。顾客和书是两个完全不同的东西。您希望将这些数据/功能分开,并且不应从任何通用基类(您所做的)继承。

作为“骗子”你说:我建立我的班级后,我的用户界面,并有复制粘贴

  • A.如果你嘲笑了一些用户界面,以帮助您解决您的设计之前,明确需求和代码补课,这是,不坏。
  • B.良好的域对象排列有助于消除复制/粘贴,而不会导致它。如果您在典型的排列良好的类(通常是数据访问代码)中有一些看似重复的代码,请不要担心。您可以使用良好的数据访问层/工具,良好的共享日志记录资源等来解决问题。类中的重复代码意味着您需要进行更多的设计改进,而不是,它为您的所有领域实际设置了单独的类是不好的。

在需要处理与客户和书籍的页面,您将使用客户对象和对象,可能是集合对象。取决于你的数据库/对象模型的设置方式,你可能正在处理其他的对象,以便从顾客那里购买他们购买的书籍。例如,客户可能同时购买1本或更多本书,并且这些书绑定到订单对象,该对象具有对客户的参考。所以,你可能会从

  1. 客户去一个
  2. 订单集合包含所有的客户订单到各个
  3. 订购对象,并从那里到相应的
  4. 图书集合包含所有的
  5. B ook与该Order对象相关的对象。

这些都不需要相互继承。现在,让我们说让顾客购买的所有书籍都是你做的很多事情,并且你想简化它。然后,您希望直接从客户那里获得一个Books集合,尽管用于获取这些书籍的sql查询仍然通过db中的Orders。你必须开始你的对象模型(和表幕后)准确地反映现实。即使这给你看似很多种类,最后也是更简单。你可能最终得到一些继承,你可能不会。

1

我会避免2和3,因为它将你锁定在一个限制性的层次结构中,并不能真正满足你的需求。正如你指出的那样,可以有任何你想要的东西的组合,例如顾客和他们的书籍,也可能是他们的地址,也可能是他们的订购历史。或者,也许你会想要一本与它的客户名单的书。由于您的底层业务信息不是真正的层次结构,您应该尽量避免使您的对象模型不必要地分层。否则,你会建立一些限制,以后会导致很多麻烦,因为你现在无法想到所有的场景。

我认为你在正确的轨道上,我会说为顾客和书籍创建一些基本类,然后创建一个CustomerBook关联类,其中包含客户和书籍的一个实例。然后你可以让你担心如何将数据加载到给定scenerio的列表中。

+0

听起来不错。如果我理解得好,你说如果没有层次结构,我必须避免构成,而不得不做一些“关系类”。 – 2010-02-19 16:02:49

0

我会坚持地址到Customer,并有一个单独的书籍集合。

Bookshelf 
--Books[] 

这样,Customer没有,但可以有,关联到他的一个或更多的书。下面的PHP代码例如:

class BookshelfFactory { 
    public static function getBookshelf(Customer $customer) { 
    // perform some fetching here 
    return $bookshelf; 
    } 
} 
0

你那种从OOA & d的角度设计倒退。在持久性(通常是关系数据库)层使用数据驱动设计是正常的。但在OOA & D中,想象一个对象将发送和接收的消息(您建模一个对象的方法而不是它的成员)更为正常。我会这样想:

Customer 
+getBooks():List<Book> 
+getAddress():Address 
+0

我不太喜欢它:你在商务课堂里打电话给你的DAL。他们必须互相忽视。 – 2010-02-19 16:01:36

+0

@remi bourgarel - 我不会假设客户阶层如何在这个时候实现这些方法;只需通过客户自己就可以获得客户的地址和书籍清单。 – shadit 2010-02-19 16:07:07

+0

@remi bourgarel,在商业课程中使用DAL是相当普遍的(也是很好的)。因此,使用下面的“三层”,每层都在另一层之上。在我目前的解决方案中,我正在执行此操作(即使我正在为单元测试和其他目的注入我的DAL工具)。能够用数据实例化对象也很好,所以(例如)您的书籍集合只需要一个数据库调用即可实例化20个书对象。 – 2010-02-19 17:03:01

0

我认为你的问题是实现你的数据映射层的问题。

您可以通过JOINS获得高度高效的查询,以返回客户以及他们的图书。

您的映射层将其映射到适当的唯一对象中,并负责为对象创建正确的一对多聚合。

此外,你可以迎合浅加载,显示属性来保存不必要的数据量,以便在每个对象只需要几个属性的情况下进行传输。

+0

JOINS的问题是,我将获得1个获取客户+书籍的请求,以及1个获取客户+地址的请求。所以我会复制粘贴大量的sql代码(字段,过滤器等)。 – 2010-02-19 16:05:00

+0

不一定,如果你看到你会复制,你只需重构并将其存储在相关类或抽象的字符串常量中,以便重用。始终保持重构... – 2010-02-19 16:08:14

+0

@remi bourgarel,有多个sql查询提到同一个表是绝对好的,这是不可避免的。这完全是关于平衡,其中一个平衡是在*效率*和*封装*之间。封装只是实现简单性的工具。一个简单的**和高效的系统通常会涉及多个地方的类似的SQL查询。非常好。正如Wim所说,有时你可以/应该删除一些这种重复,这当然是好的,但通常不可能将其全部删除,这很好。 – 2010-02-19 17:09:24