面向对象还是分层平衡" OO纯度"与完成工作

时间:2020-03-06 14:55:35  来源:igfitidea点击:

我相信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对象,每个对象都有几种方法。想象一下,其中某些操作不是"集中"在特定数据容器上的。

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

解决方案

残酷的是,"我们不想要"部分必须删除。我们或者希望它是正确的,或者希望它保持原样。在需要时不创建类是没有意义的。 "我们有很多"是一个不好的借口。

确实,公开所有内部类很不好,但是以我的经验,按概念创建一个类(即用户,ID,数据库概念...)总是有帮助的。

紧接着,Facade模式不是解决隐藏在一个井井有条,整洁的界面后面的BizRules类负载的方法吗?

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

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

OOD / OOP的最大乐趣之一是,当设计正确时,我们就知道它是正确的,因为很多事情都超出了我们可以做的事情,而我们以前做不到的事情。

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

其余的"我们不要"子弹是正确的;它们不仅是正确分层所必需的,而且对于干净的OO设计也是必需的。

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

考虑一下如果没有计算机,将如何完成这些任务,然后以这种方式对系统进行建模。

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

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

表格是否验证其正确填写?不,员工愿意。员工在此过程中将扮演什么角色?表格处理器。

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

等等...

要将其推送到Java EE实现中...

Servlet代表客户行事,填写表格(从HTTP请求中提取数据并创建适当的Java对象),并将其传递给适当的员工(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系统中,似乎有时我们必须处理Java EE的管道,管道并不总是受益于OO概念,但是肯定可以通过一些创造力和工作来实现。例如,我们可能会利用诸如AbstractFactory之类的东西来帮助尽可能多地通用此基础架构。
  • 埃里克·埃文斯(Eric Evans)出色的著作《域驱动设计》(Domain Driven Design)中讨论了许多我们正在寻找的内容。我强烈建议我们看一下它,因为他确实解决了表达领域知识和处理支持该问题的技术基础架构的问题。
  • 读完DDD并对其进行GROKD处理后,我会将我的技术基础结构封装在存储库中。所有存储库都将被编写为使用基于会话EJB的持久性策略。我们将为此编写一个默认实现,该实现知道如何与会话EJBS对话。要使此工作有效,我们需要添加一些约定,并在界面中指定该约定/合同。存储库执行所有CRUD,并且仅在绝对需要时才执行更多操作。如果我们说"我的DAOS是我的存储库",那么我会同意。
  • 因此,继续进行。我们需要一些东西来封装UseBizLayer中表示的工作单元。在这个级别上,我认为它的本质是我们被困在编写全部将成为事务脚本的代码。我们正在创建责任与状态的分离。通常,这是我在Java EE系统中将其作为默认架构完成的方式。但这不是面向对象的。我将尝试探索模型,看看是否至少可以尝试使写入BizClass中的某些行为通用化。
  • 我之前使用的另一种方法是摆脱BizLayer类,然后将来自Domain的调用代理到执行该操作的实际存储库/ DAO。但是,这可能需要在基础设施上进行一些投资。但是我们可以大量使用Spring这样的框架,并使用一些AOP概念来使其良好运行,并减少所需的自定义基础结构量。

我认为这是关于"关注分离"的问题。我们似乎在分层架构的正确轨道上还有很长的路要走,但是也许我们需要做更多的相同工作,即在Java EE层中创建架构层?

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

现代的OO设计有很多小类,每个小类都与少量的"朋友"有关,例如通过组成。这可能会产生比我们真正喜欢的更多的类和Java样板,但是它应该导致设计更好的分层并且更容易进行单元测试和维护。

(+1表示问题,+ 1表示关于何时知道我们拥有分层权的答案)