【问题标题】:Obvious flaws in my EJB3 design我的 EJB3 设计中的明显缺陷
【发布时间】:2011-08-29 05:31:43
【问题描述】:

我有一个名为VehicleRecord 的域对象,它是一个休眠实体。这些 VehicleRecords 上的 CRUD 操作是通过实体访问对象处理的,该对象实现为无状态会话 bean 接口

@Local
interface VehicleRecordEao {
    void add(VehicleRecord record);
    List<VehicleRecord> findAll();
    ...
}

@Stateless
class HibernateVehicleRecordEaoBean implements VehicleRecordEao { ... }

从业务层的角度来看,删除和添加这些记录不仅仅是 CRUD 操作。例如,可能存在日志记录和安全要求。为了向客户端提供这些操作,会话 bean 在业务层中创建。

@Local
interface VehicleRecordManager {
    void createVehicleRecord(VehicleRecord record);
    List<VehicleRecord> findAll(String make, String model); 
    ...
}

@Stateless
class VehicleRecordManagerBean {
    public void createVehicleRecordManager(VehicleRecord record) {
        //business rules such as logging, security,
        //   perhaps a required web service interaction
        //add the new record with the Eao bean
    }
    ...
}

控制器在表示层和上述业务层之间工作以完成工作,并根据需要在表示对象(如表单)和实体之间进行转换。

这里有些不对劲(气味)。我有一个名为 Manager 的类,它必须是一个危险信号,但 EJB 书籍中的几个示例实际上暗示了这种高级类,并且倾向于自己使用名称 manager。我是 EJB 设计的新手,但在 OO 设计中制作称为 Manager 或 Handler 或 Utility 的高级类的程序性尖叫,需要重新考虑他们的设计。

这些过程实用程序类会话 bean 是正常模式,还是通过一堆仅与它们操作的实体相关的方法来组织会话是不好的?会话 bean 有任何命名约定吗? Eao 和业务会话 bean 是否应该在同一层工作?

如果这种模式有不那么臭的替代品,我很想知道,谢谢。

【问题讨论】:

    标签: java jakarta-ee ejb-3.0


    【解决方案1】:

    您的方法或多或少是标准的。是的,从根本上说,这是一种程序方法,与被称为Anemic Domain Model“反模式”的方法密切相关。另一种方法是将您的业务逻辑合并到您的域模型中,以便创建一个更加面向对象的设计,其中您的操作与您的 DO 相结合。如果你沿着这条路线走you should be aware of the inherent pros and cons。如果您觉得您的方法最有意义,易于理解、测试、扩展等……那么就使用它。我曾参与过几个使用这种精确“程序”样式的 n 层项目——请放心,在 EE 应用程序中以这种方式做事是相当标准的。

    【讨论】:

    • 另一个很好的资源——《POJOs in Action》这本书的前两章讨论了组织业务逻辑的“过程风格”和“面向对象”风格
    • 接受这个答案,因为它为我指明了进一步了解 ADM 与 RDM 的方向。这让我意识到为什么尽管我知道 ADM 设计很臭,但我还是这样做了。我相信我所处的情况是,由于经验/动力有限,大多数团队无法维持 RDM,并且会陷入混乱。
    【解决方案2】:

    这是一个古老的讨论。面包应该自己烤,还是烤箱烤?消息是自己发送的,还是邮局自己发送的?我是否可以通过让朋友 Pete 给自己发送消息来向他发送消息?

    根据提出 ADM 一词的人的说法,让每个对象自己做所有这些事情更“自然”和“OO”。极端(当然没有人提倡,但只是作为一个例子)类 User 将包含整个应用程序的所有逻辑,因为最终用户会做所有事情。

    如果您使用 slim 实体(仅包含数据的实体)和服务或 DAO 对象来处理它们,那么您不一定不做 OO。仍有 很多 OO 存在。服务实现接口,从基类继承,封装状态(例如 JPA 中的 EntityManager),通过动态代理具有透明拦截器(例如检查安全性和启动/提交事务)等。

    “贫血”一词具有明确的负面关联,但将同一事物称为“苗条”实际上听起来不错。这不仅仅是使用不同的名称来隐藏代码异味的情况,而是代表了不同人群之间的不同思维。

    【讨论】:

    • +1 一个很好的观点,我也将其解释为模型中有几个 Anemic 类(如果它们没有被滥用)并不一定会破坏一个好的 OO 设计。
    【解决方案3】:

    我认为这取决于您的口味,并且取决于您的应用程序的复杂性 - 这些事情的重要性较小/更多。我认为在设计中,您需要简单地围绕以下内容:

    “如果新来的人对相关系统没有任何先验知识 - 该人是否足够直观地跟踪和追踪代码,并直接找到东西在哪里”

    在您的情况下-命名与实体对象相关的 EJB 使其简单明了-我不明白为什么您将其分为 2 个类 EAO 和 Manager。为什么不将它们组合成一个,所以如果 EJB/Bean 类处理 VehicleRecord 实体,那么它将是“VehicleRecordEAO”或“VehicleRecordManager”或“VehicleRecordAccess”或其他任何东西。

    我认为 EAO / DAO / Access 听起来更像是 getter / setter - 或任何其他简单的操作。我看不出“Manager”有什么问题,并让所有业务层都被称为“Manager”。

    或者,如果您感觉更好,可以将其视为Facade Pattern - 这样您就可以将您的业务层(管理器)称为 VehicleRecordFacade 和 VehicleRecordFacadeBean。

    这样你基本上遵循外观模式的名称和概念,它成为应用层和数据层之间的中介。

    【讨论】:

    • 之所以不将它们组合在一起,是因为添加或删除车辆涉及业务流程。我的第一反应是确保持久性实现的变化和业务需求的变化不会影响其他 EJB。 +1 让我重新考虑在两个 EJB 中进行分离,也许有更好的方法。
    【解决方案4】:

    这里有些不对劲(气味)。 我有一个名为 Manager 的课程 必须是一个危险信号

    我的回答是针对你的这个问题。

    是的。这是一面红旗。命名像“VehicleRecordManager”这样的类将是一种代码味道,暗示Single responsibility principle 迟早会被违反。

    为了详细说明,我举几个处理VehicleRecord的用例

    1. 买车
    2. 租车
    3. 搜索车辆
    4. 卖车
    5. 寻找经销商

    在大多数 Java 应用程序中,当我们编写“VehicleService”(或“VehicleManager”)时,上述所有操作都将放在此类中!好吧,这很容易做到,但很难维护。当然这个类有很多责任,因此有很多改变的理由。 (违反单一责任原则)

    【讨论】:

      【解决方案5】:

      称它为VehicleDao 会消除一些异味吗?一个简单的更改,但清楚地表明它涉及数据访问问题。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2014-08-19
        相关资源
        最近更新 更多