【问题标题】:How would you model this application?您将如何建模此应用程序?
【发布时间】:2011-01-13 01:59:04
【问题描述】:

我有一个用 Zend Framework 编写的 MVC 应用程序,它从 Oracle 10g 数据库中提取数据并在表格和列表中显示这些数据,并通过颜色和图表直观地丰富这些数据。不涉及 ORM,也不涉及创建、更新或删除,只是纯粹的阅读。数据是从另一个应用程序插入的。数据库中的数据是根据它们所代表的概念建模的,并由数据库视图访问,这些数据视图从各种其他表(旧的,无法更改)聚合这些数据,例如

| Event ID | Start               | End                 | Status | Created_By |
-----------------------------------------------------------------------------
| 12345678 | 2009-10-01 12:00:00 | 2009-10-01 12:15:00 | booked | John Doe   |
| 12345679 | 2009-11-01 13:00:00 | 2009-12-01 12:00:00 | booked | John Doe   |
| 12345680 | 2009-11-01 13:00:00 | 2009-12-01 12:00:00 | tba    | Jane Doe   |

用户可以从视图影响列的显示、排序和排序。客户端可以拒绝/允许访问列并将列内容限制为某些值。用户不能覆盖客户端设置。用户是一个参与者,而客户端基本上只是一个过滤器,它为属于客户端的用户创建可用数据的子集。用户和客户端设置保持不变。

我目前的做法大致是这样的:

Request --> Controller
            | <--> sanitizes and returns Request params
            | ---> Facade (capsules steps to fetch View Data)
            |      | <--> Table Data Gateway builds Query for requested View
            |      | <--> Query Decorator¹ applies User/Client settings
            |      | <--> DB Adapter fetches RecordSet from decorated Query
            | <----returns Recordset
            | <--> applies RecordSet to View
            | <--> Data-Aware ViewHelper render RecordSet (and View)
Response <--returns rendered View

¹ 查询装饰器可以读取持久的用户/客户端设置并将其添加到 TDG 动态返回的基本查询对象中。

但是,最近我一直怀疑这种方法并希望对其进行改进。我想我可以完全删除 TDG 并使视图构建从 UI 完全通用;仅基于数据库结构。用户肯定会喜欢这个。问题是,视图必须对数据了解很多。 ViewHelper 必须知道列名才能丰富数据,而且他们通常会针对 Recordsets 中的多个列这样做。它们不能是通用的,有些东西告诉我这无论如何都是麻烦的。感觉就像杂烩。我只是无法确定原因。

非常感谢任何模式、想法和意见。我知道这个问题有些模糊,但就像我说的,我无法确定是什么让我怀疑这种方法。所以我想我正在寻找任何好的实践方法来以可维护的方式构建用户和客户端可定制的以数据库为中心的应用程序。我当然不需要解决方案,只需要一些想法,也许还有一些链接来看看其他人是如何解决这个问题的,所以我可以在下一次重构时考虑它。

注意
在接受答案之前,我会在整个过程中保持问题开放。任何意见表示赞赏。

【问题讨论】:

  • 请原谅我的怀疑,但是:视图需要对数据了解很多? ViewHelpers 必须知道列名? 为什么? 这听起来像是一种内部平台效应,是 Microsoft Access 或 Cognos 的再发明。超出一定门槛的定制是邪恶的;可能是需要重构的需求
  • @Aaronaught 怀疑主义很好。这就是让我问这个问题的原因 :) 回答你的问题:想象有一个 ViewHelper,它根据 StartEndStatus呈现时间轴栏> 作为呈现整个 Recordset 的表的一部分,以及基于 Created_By 呈现 PieChart 的 ViewHelper。

标签: php design-patterns oop architecture


【解决方案1】:

在反复阅读你的问题并思考了一下之后,我相信我会这样总结情况:

“MVC”中缺少“M”。

此时,您已经手工制作了一个关系数据库架构,使其与您的域模型具有 1:1 的映射关系。这很好,它使映射变得非常容易,但记录集仍然不是域类。

MVC 上下文中的术语模型 指的是领域模型,而不是关系模型。如果您有支持此应用程序的关系数据库,那么您需要某种映射。这并不是说您需要像 Doctrine 这样成熟的 ORM 框架 - 尽管我确实发现这些工具让我的生活变得更加轻松,即使对于小型项目也是如此 - 但您需要一些东西。事实上,Zend 框架甚至详细介绍了在Quick Start 中映射域模型。

我认为您不需要删除 TDG。抽象是好的。撕掉它以使您的应用程序更精简一点,我认为这就像进入办公楼并撕掉电话系统,理由是员工只能使用他们的手机。他们可以,但您不希望他们这样做,就像您不希望您的视图直接向数据库抛出 SQL 查询一样。它效率低下,通常难以管理。

我的架构版本如下所示:

Request --> Controller
            | <--> sanitizes and returns Request params
            | ---> Facade (encapsulates steps to fetch View Data)
            |      | <--> Table Data Gateway builds Query for requested View
            |      | <--> Query Decorator applies User/Client settings
            |      | <--> DB Adapter fetches RecordSet from decorated Query
***         |      | <--> Mapping layer converts RecordSet to Domain Model
***         | <----returns Model
***         | <--> applies Model to View
***         | <--> Data-Aware ViewHelper render Model (and View)
Response <--returns rendered View

我已经用*** 标记了更改行。实际上,我唯一改变的是,它不是从外观中获取记录集,而是获取模型(可能是域类数组),并将 that 应用于视图。

在您的视图 [Helper] 中,您将拥有 $event-&gt;status,而不是像 $row['Status'] 这样的术语,它更安全,更易于长期维护。里面没有列名,只有一个属性。

现在您在问题的最开头明确提到您没有任何 ORM,所以我认为您可能已经知道其中的大部分内容并且可能只是需要推动一下。您脑海中那些挥之不去的疑问可能是这样的:如果它不总是只读的怎么办?如果数据模型变得更复杂怎么办?如果人们开始要求更复杂的报告怎么办?

所有这些都是您拥有域模型的原因,为什么它实际上是 MVC 的基本构建块:最终,您的用户拥有的心智模型会与数据模型,出于多种原因,我不会在这里讨论。关键是,它几乎总是会发生。

我确定这是必要的吗?我是否肯定这不仅仅是矫枉过正,一堆仪式咒语对这么小的项目没有意义?

不,我不是。只有你可以决定。我可以告诉你的是,如果没有适当的域模型,MVC 范式作为一个特定架构对你没有多大好处。这比在每个页面中仅包含内联查询或外观调用要好一些,但 并不好。如果没有模型,MVC 只不过是一种花哨的 URL 重写方案。

也许您需要这种抽象级别,也许您不需要;但我猜你可能会怀疑你可能会,否则你不会问这个问题。想一想,分析当前的需求和范围,问问自己可能会发生什么样的变化,如果当前的架构看起来太脆弱而无法适应,那么下一个合乎逻辑的步骤就是领域模型——即使 今天 它只是关系模型的精确镜像。明天可能就不行了。

希望这是您正在寻找的答案!

【讨论】:

  • 谢谢亚伦。实际上,您对我的怀疑非常准确。由于您提到的原因,我从一开始就想拥有一个 ORM 和一个域模型,但由于担心它会对性能产生影响而被一位上司劝阻。
  • @Gordon:啊,微观管理,现在一切都说得通了!除非您的网站每天处理数百万用户,否则良好的抽象和良好的设计应该比性能更重要(即便如此,还有其他选择)。无论如何,域模型的性能影响几乎为零;大多数数据库支持的应用程序都受 I/O 限制,并且大部分时间都在等待查询结果。祝你好运!
  • 再次感谢。享受你应得的赏金:)
【解决方案2】:

DB 架构设计具有不同的要求(查询/写入性能、可伸缩性)作为一个漂亮的 UI(良好的页面流,支持人们的工作方式或流程的工作方式)。因此,UI 和 DB 方法通常很难直接映射。

作为一个不好的例子,我记得一个使用“Oracle Forms”的应用程序,它直接呈现来自数据库结构的通用视图。对于非技术人员来说,使用它通常非常违反直觉。

我仍然认为在您的情况下,如果 View 可以直接映射到 DB 模式,那么一定要摆脱不必要的抽象层、代码并简化系统。尽可能简单地实现需求。

【讨论】:

    【解决方案3】:

    要根据用户输入从表中动态获取数据,您可以使用 Zend_Dojo 组件数据网格。您可以创建一个 TDG 对象,该对象将根据用户输入重新映射到新表。

    http://zendguru.wordpress.com/2009/01/08/dojo-grid-in-zend-framework-creating-nice-and-cool-grid-in-php-using-zend-framework-and-dojo/

    【讨论】:

      猜你喜欢
      • 2015-02-12
      • 2011-07-30
      • 1970-01-01
      • 1970-01-01
      • 2013-04-19
      • 1970-01-01
      • 2010-09-07
      • 2015-09-18
      • 2010-11-15
      相关资源
      最近更新 更多