3

对于典型的 Web 3 层应用程序,您在以下设计中看到了哪些缺陷(以及您理想的架构建议)?

我目前的蓝图方法是非常粗略的(假设 Java、Spring、Hibernate、JSP)


控制器

无状态,可能用只读事务包装(以避免惰性初始化异常),仅通过服务从持久存储中获取实体,将它们作为模型传递给视图。对它们进行业务逻辑(BL应该只在服务层吗?),如果需要,传递回服务层进行持久化。

优点:对于只读事务包装 - 只有一个连接,同一个持久实体没有冗余命中,更好地利用查询缓存,服务层不应该“知道”请求参数或所需的初始化图跨度,避免惰性初始化异常。

缺点:只读事务方法可能有风险,控制器不是理想的业务逻辑悬挂场所......很难做 JUnits(你的输入是一个请求......)


看法

非事务性(访问非惰性集合/成员将导致惰性初始化异常)

优点

  • 视图作者不应仅仅通过点符号来影响应用程序的性能(例如,由于延迟初始化大型集合而导致 N+1 选择。

  • 同样在断开连接的客户端(Flex 或其他富客户端)中,远程延迟初始化要么不受支持,要么不明智

缺点:控制器/服务/DAO 必须为视图仔细准备正确的实体图,并且可能会过冲(性能)/下冲(惰性初始化异常)。无数的服务器端方法可能会导致混乱,因为对于可以初始化实体图的排列数量存在笛卡尔积


模型

按原样使用持久对象(无数据传输对象),状态保存在会话中。

优点:无需重写 POJO,重用现有实体,会话状态比隐藏字段状态处理更安全。

缺点:对断开连接的框架不利,保存陈旧断开连接对象的风险,锁定问题的风险,覆盖其他数据,有时需要乐观锁定。


服务

事务性的,不知道请求范围,调用 DAO 层进行实际的持久化存储访问。这是 BL 通常应该在的地方,但似乎 BL 一遍又一遍地泄漏到控制器端。


包含原子持久化存储门面,不知道 BL,或任何上下文


最后,问题:

你会在上述架构中修复什么?

您是否(像我一样)认为这是一种相当普遍的方法(有一些细微差别,例如开放会话等)?或者这是您第一次看到它并且我正在做一些非常错误(或正确)的事情?

你如何在你的应用程序中解决它?您是否也将实体 POJO 用于您的模型和视图?还是将其连接到更简单的 UI bean(全部已完全初始化且安全)?

这可能是一个主观问题,但我确信有明确的最佳实践设计模式可以聚集到最多一个、两个或三个一般“宗教”。

4

4 回答 4

3

总的来说,它似乎是一个非常好的架构。如果您还没有阅读它,我会推荐 Martin Fowlers Patterns of Enterprise Application Architecture,它描述了您问题中的每个主题。

从这个问题中不清楚您期望性能有多大的问题。根据我的经验,性能瓶颈很少出现在您认为的位置,并且越早发现它们,更改架构以匹配它们就越容易。

你是对的,可测试性是一个主要问题。我使用 Martin Fowlers Passive View模式取得了一些成功。您还应该查看来自同一站点的监督控制器。

于 2009-12-28T18:21:06.903 回答
2

超级除非做一个 SOFEA 风格的前端,它基本上摆脱了上述架构中的 Controller 部分。

前端完全包含在客户端上,它直接调用返回 JSON 或 XML 的 REST 或 SOAP 服务。这似乎解决了 100% 的转换域对象以进行显示的问题!!!!

也许,有些人认为,上述 N 层架构没有干净的解决方案的原因可能是因为它完全是错误的。

链接

  1. http://raibledesigns.com/rd/entry/sofea_also_known_as_soui
  2. http://www.theserverside.com/news/thread.tss?thread_id=47213
  3. http://wisdomofganesh.blogspot.com/2007/10/life-above-service-tier.html

我当前的项目使用带有数据传输对象的有点过时的 N 层架构。DTO 是不必要的,因为应用程序不是分布式的,也永远不会。使用 DTO 的一个好处(IMO 不值得)是它强制为业务方法提供一个干净的接口——视图组件可以按照他们的意愿遍历伪模型上的对象图——没有延迟初始化异常可以被抛出。

我在我们的架构中看到的架构痛点之一是业务接口非常复杂。似乎我们需要一个元业务接口来封装所有的小业务接口。实际上,这最终会发生在一个服务最终调用其他三个服务来完成其工作的情况下。

控制器(在我们的例子中是 Struts 1.2 Action 类)最终会调用这些超细粒度或粗粒度业务组件的任意组合。遗憾的是,在大多数情况下,开发人员会在不知不觉中或懒惰地在控制器类中编写各种应为业务逻辑的内容。每次看到这三百行Action方法之一的时候我都尖叫!!!!

SOFEA 方法似乎提供了一种更清洁的方法。AJAX 甚至允许在浏览器上运行的 Web 应用程序使用正确的 MVC 模式对其前端进行编码,这对用户(通过提供更动态的 UI)和开发人员(允许他们编写正确的 MVC 编码)都有好处。

UI 与可重用的业务逻辑完全解耦。GUI 是厚的还是薄的?这真的无关紧要——它们的编码方式基本相同。

SOFEA / SOUI 对我来说是新的,我从未尝试过,但我最近一直在阅读它,我想我会分享我的想法。

于 2009-12-29T11:02:51.710 回答
1

您的上述方法听起来不错。

但我认为你应该使用 UI-Beans。当然,这个 UI-Bean 应该是有效的不可变的。一旦它被创建,它的状态(和封装的域对象)就不应改变。

非常简化的例子:


class UIBean {
  DomainObject o;

  public String getDescription(){
     return trimToSummaryText(o.getDescription());
  }

  private static String trimForSummaryText(){
     ....
  }
}

主要优点:

  • 模板代码往往会变得更简洁。您的前端开发人员会对此感到高兴。
  • 您不倾向于将特定于前端的辅助方法添加到域对象类中。
  • 可以对不同的域对象或视图 bean 进行分组(ui-bean 可以有多个字段)。列表的封装在这里特别好。

是的,它涉及更多的java类。但是,只要您的 web 应用程序和页面增长,这个抽象层几乎总是没问题的。

于 2009-12-28T20:19:25.610 回答
0

尽管这个问题最后一次回答是在大约一年前,但也许这个答案似乎对某人有所帮助。您的架构总体概述很好,唯一要添加的细节是:通常用于在层之间传递数据(例如视图和服务)而不是上面提到的 UiBean-s 所谓的DTO(数据传输对象)被使用,这些是简单的 POJO适当的字段/设置器/获取器。

在 Java EE 规范的先前/早期版本之一中,“DTO”一词被错误地与“ValueObject”混合在一起,尽管它们有一些不同的用途。

希望这可以帮助。

于 2013-05-08T09:55:28.070 回答