面向对象与面向对象分层;平衡“面向对象的纯度”和完成工作

StackOverflow https://stackoverflow.com/questions/153394

  •  03-07-2019
  •  | 
  •  

我相信面向对象,但还没有达到为了“符合面向对象”而使用不适当的设计/实现的程度。

那么,如何处理Serlvet/EJB/DataContainer分层架构:

  • Servlet 接收请求并调用“业务层”(例如会话 EJB)
  • 业务层从数据库中定位DataContainer并操作它们来实现业务逻辑
  • DataContainers 不包含真正的代码,仅包含与数据库对应的获取/设置。

这种方法很有吸引力;DataContainer 的作用很明确,并且很容易知道数据来自哪里。

除了不是面向对象之外,这还会导致业务层类不明确,难以命名和组织。

即使我们 尝试变得更加“OO”(例如将其中一些方法放入 DataConatiners 中),其中一些操作对多个数据集进行操作。

如何防止业务层变得令人困惑的程序,但又不会用业务逻辑污染您的数据容器?

例子

class UserServlet {
  handleRequest() {
    String id = request.get("id");
    String name = request.get("name");
    if (UserBizLayer.updateUserName(id,name))
      response.setStatus(OK);
    else
      response.setStatus(BAD_REQUEST);
  }
}

class UseBizLayer {
    updateUserName(String id, String name) {
        long key = toLong(id);
        user = userDAO.find(key);
        if user == null
            return false;
        if (!validateUserName(name))
            return false;
        user.setName(name);
        userDAO.update(user);
        return true;
    }

    validateUserName(String name) {
        // do some validations and return
    }
}

class User {
    long key;
    String name;
    String email;

    // imagine getters/setters here
}
  • 我们不想要 validateUserName 对用户而言,因为它仅对名称进行操作;我想它可以进入另一个班级,但我们有 其他 程序“uti”类型类
  • 我们不希望用户使用持久化方法,因为将数据结构与其持久化策略分离是有价值的
  • 我们不希望 Servlet 中包含业务逻辑,因为我们可能需要在其他地方重用该逻辑
  • 我们不希望我们的业务逻辑在 User 中,因为这会过多地吸引 User 类,从而使业务逻辑的重用变得困难,并将用户与其持久性策略耦合起来

我意识到这个示例并没有那么糟糕,但想象一下 10 个 DataContainer 和 20 个 BizLayer 对象,每个对象都有多个方法。想象一下其中一些操作并不“集中”在特定的数据容器上。

我们如何避免这成为程序上的混乱?

有帮助吗?

解决方案

因此,我将通过以下几个要点来阐述我对此的想法:

  1. 似乎在 Java EE 系统中的某个时刻,您必须处理 Java EE 的管道,管道并不总是受益于 OO 概念,但它肯定可以通过一些创造力和工作。例如,您可以利用 AbstractFactory 等来帮助尽可能多地通用此基础设施。
  2. Eric Evans 的优秀著作《领域驱动设计》中讨论了您正在研究的很多内容。我强烈建议您查看它,因为他确实解决了表达领域知识并处理支持它的技术基础设施的问题。
  3. 阅读并理解了 DDD 的一些内容后,我会将我的技术基础架构封装在存储库中。所有存储库都将被编写为使用基于会话 EJB 的持久性策略。您可以编写一个默认实现,它知道如何与您的会话 EJBS 通信。为了实现这一点,您需要添加一些约定并在接口中指定该约定/约定。存储库执行所有 CRUD,并且只有在绝对需要时才应该执行更多操作。如果你说“我的 DAOS 是我的存储库”,那么我会同意。
  4. 所以继续这个。您需要一些东西来封装 UseBizLayer 中表达的工作单元。在这个级别上,我认为它的本质是你被困在编写所有将成为事务脚本的代码。您正在创建责任和状态的分离。这通常是我在 Java EE 系统中看到的默认架构的实现方式。但它不是面向对象的。我会尝试探索该模型,看看是否至少可以尝试通用一些写入 BizClass 的行为。
  5. 我之前使用过的另一种方法是摆脱 BizLayer 类,然后将来自域的调用代理到执行操作的实际存储库/DAO。然而,这可能需要一些基础设施建设投资。但是您可以使用像 Spring 这样的框架做很多事情,并使用一些 AOP 概念来使其工作良好并减少所需的自定义基础设施的数量。

其他提示

由于您正在实现类和对象,因此无论您如何分层,您的解决方案都将是面向对象的 - 根据您的情况/需求,它的结构可能不是很好!;-)

至于您的具体问题,在某些情况下, validateUserName 属于 User 类是有意义的,因为每个用户都希望有一个有效的名称。或者,您可以拥有一个验证实用程序类,假设其他事物具有使用相同验证规则的名称。电子邮件也是如此。您可以将它们分成 NameValidator 和 EmailValidator 类,如果它们会被大量使用,这将是一个很好的解决方案。您还可以在刚刚调用实用程序类方法的 User 对象上提供 validateUserName 函数。所有这些都是有效的解决方案。

OOD/OOP 的最大乐趣之一是,当设计正确时,您 知道 它是对的,因为很多事情都超出了你以前无法做到但你可以做到的模型。

在这种情况下,我将创建 NameValidator 和 EmailValidator 类,因为其他实体将来可能会有名称和电子邮件地址,但我会在 User 类上提供 validateName 和 validateEmailAddress 函数,因为这为业务提供了更方便的接口使用的对象。

其余“我们不想要”的要点是正确的;它们不仅对于正确的分层是必需的,而且对于干净的面向对象设计也是必需的。

分层和面向对象基于层之间关注点的分离紧密结合。我认为您的想法是正确的,但需要一些实用程序类来进行常见验证

想想如果没有计算机,这些任务将如何完成,并以这种方式对您的系统进行建模。

简单的例子...客户填写表格以请求小部件,将其交给员工,员工验证客户的身份,处理表格,获取小部件,将小部件和交易记录提供给客户并保留交易记录公司的某个地方。

客户是否存储他们的数据?不,是员工。员工在存储客户数据时扮演什么角色?客户记录保管员。

表格是否验证其填写正确?不,是员工。员工在这样做时扮演什么角色?表单处理器。

谁给客户提供小部件?充当小部件分销商的员工

等等...

要将其推入 Java EE 实现中......

Servlet 代表客户端,填写表单(从 HTTP 请求中提取数据并生成适当的 Java 对象)并将其传递给适当的员工 (EJB),然后由 EJB 处理该表单需要执行的操作。在处理请求时,EJB 可能需要将其传递给专门处理不同任务的另一个 EJB,其中部分任务包括从存储(数据层)访问信息或将信息放入存储(数据层)。唯一不应该直接映射到类比的事情应该是对象如何相互通信以及数据层如何与存储通信的具体细节。

我自己也有同样的想法。

在传统的 MVC 中,最重要的是将视图与模型和控制器部分分开。将控制器和模型分开似乎是个好主意,因为您最终可能会得到臃肿的模型对象:


public class UserModel extends DatabaseModel implements XMLable, CRUDdy, Serializable, Fooable, Barloney, Baznatchy, Wibbling, Validating {
  // member fields
  // getters and setters
  // 100 interface methods
}

虽然您可以为上面的许多接口拥有单独的控制器(或整个模式),是的,它本质上是相当程序化的,但我想这就是现在的工作方式。或者,您可以意识到某些接口正在做同样的事情(CRUDdy - 数据库存储和检索,可序列化 - 与二进制格式相同,XMLable,与 XML 相同),因此您应该创建一个系统来处理这个问题,使用每个潜在的后端都是系统处理的单独实现。天哪,写得实在是太糟糕了。

也许有类似“共同类”的东西,可以让您为控制器实现提供单独的源文件,就像它们是它们所作用的模型类的成员一样。

至于业务规则,它们经常同时作用于多个模型,因此它们应该是分开的。

我认为这是一个关于“关注点分离”的问题。您似乎已经在分层架构的正确轨道上走了很长一段路,但也许您需要做更多相同的事情 - 即在 Java EE 层中创建架构层?

DataContainer 看起来很像数据传输对象(DTO)模式。

现代的面向对象设计有很多小类,每个小类都与少数“朋友”相关,例如通过组合。这可能会产生比您真正满意的更多的类和 Java 样板,但它应该会带来更好的分层且更易于单元测试和维护的设计。

(+1 表示问题,+1 表示当您知道自己拥有分层权利时的答案)

粗略地说,“我们不想要”部分必须删除。要么你希望它是正确的,要么你希望它保持原样。没有意义 不是 当您需要时创建一个类。“我们有很多”是一个糟糕的借口。

确实,它 不好 暴露 所有内部类,但根据我的经验,为每个概念创建一个类(即用户、ID、数据库概念...)总是有帮助的。

除此之外,Facade 模式不是可以解决隐藏在组织良好且干净的界面后面的大量 BizRules 类的存在问题吗?

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top