OO vs. Layered;平衡“OO纯度”与完成任务

时间:2008-09-30 14:50:31

标签: oop class-design

我相信OO,但是不应该使用不恰当的设计/实现只是为了“符合OO”。

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

  • Servlet接收请求并调用“业务层”(例如会话EJB)
  • 业务层从数据库中找到DataContainers并对其进行操作以实现业务逻辑
  • DataContainers不包含实际代码,只是对应于数据库获取/设置。

这种方法具有吸引力; DataContainers清楚地知道他们做了什么,并且很容易知道数据的来源。

除了不是OO之外,这导致了不清楚的商业层类,这些类很难命名并且难以组织。

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

如何保持业务层不会出现令人困惑的程序问题,但不会使用业务逻辑污染DataContainer?

实施例

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类产生过多的影响,难以重用业务逻辑并将用户与其持久性策略相结合

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

我们如何避免程序混乱?

6 个答案:

答案 0 :(得分:3)

所以我将在几个要点中阐述我对此的看法:

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

答案 1 :(得分:1)

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

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

关于OOD / OOP的一大惊喜是,当设计正确时,你知道它是正确的,因为很多东西都不属于你可以做到的模型你以前做不到。

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

剩下的'我们不想要'的子弹是正确的;它们不仅是正确分层所必需的,而且它们也是清洁OO设计所必需的。

分层和OO基于层之间的关注点分离而进行手套。我认为你有正确的想法,但是需要一些实用程序类来进行常见的验证

答案 2 :(得分:1)

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

简单示例...客户端填写表单以请求窗口小部件,将其交给员工,员工验证客户端的身份,处理表单,获取窗口小部件,将窗口小部件和事务记录添加到客户并在公司某处保存交易记录。

客户端是否存储了他们的数据?不,员工这样做。员工在存储客户数据时会扮演什么角色?客户记录守护者。

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

谁给客户端小部件?作为Widget分销商的员工

等等......

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

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

答案 3 :(得分:0)

我自己也有同样的想法。

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


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

虽然你可以为上面的许多界面设置单独的控制器(或整个模式),是的,它本质上是程序性的,但我想这就是现在的工作方式。或者你可以意识到一些接口正在做同样的事情(CRUDdy - 数据库存储和检索,Serializable - 与二进制格式相同,XMLable,与XML相同)所以你应该创建一个单独的系统来处理这个,每个潜在的后端都是系统处理的独立实现。上帝,这真的很糟糕。

也许有类似“co-classes”的东西可以让你为控制器实现提供单独的源文件,就像他们是他们所采用的模型类的成员一样。

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

答案 4 :(得分:0)

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

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

现代的OO设计有很多小类,每个类都与少数“朋友”相关,例如:通过作文。这可能会产生比你真正熟悉的更多的类和Java样板,但它应该导致设计更好的分层,更容易进行单元测试和维护。

(问题为+ 1,关于何时知道正确分层的答案为+1)

答案 5 :(得分:-1)

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

事实上, 揭示所有内部类是不好的,但根据我的经验,每个概念创建一个类(即用户,ID,数据库概念) ...)总是有帮助。

接下来,Facade模式是不是可以解决BizRules类加载的问题,隐藏在一个组织良好且干净的界面背后?