【问题标题】:How to eliminate hard dependecies on Java Beans如何消除对 Java Bean 的硬依赖
【发布时间】:2019-07-27 12:18:17
【问题描述】:

我有一个关于 DIP 原则的问题。其中一条指导方针说我们不应该持有对具体类的引用(如果它发生变化,那么我将不得不修改所有使用它的客户端)。那么,当我使用 POJO 时,我可以遵循这个准则吗?例如:

我有一个带有一些属性的 Bean 'Foo'(它可以表示一个域对象)

class Foo {  
   private String one;   
   private String two;

  //getters and setters
}

多个客户端实例化此对象,例如,将其保存在数据库中

   class Client1 {   

      private FooDao dao;

      Client1(FooDao dao){     
         this.dao = dao;
      }  

      public void persist() {    
         //hard coding
         Foo foo = new Foo();   
         foo.setOne("something...");    
         dao.save(foo); }     
       } 

       class Client2 {   

         private FooDao dao;

          Client2(FooDao dao){   
            this.dao = dao;

           }  

        public void persist() {   
           Foo foo = new Foo();   
           foo.setOne("something...");   
           foo.setTwo("something...")    
           dao.save(foo); 
         }
       }

如果我向 'Foo' 类添加或更改任何属性,每个客户都必须更改,那么遵循本指南如何避免这种情况?

谢谢!

【问题讨论】:

  • 区分数据类(类似于 C 中的结构)和服务类(通常应该实现一些接口)是有用的。请注意,您在此处显示的 活动记录 模式存在一些基本问题,并且在 Java 中通常不使用。

标签: java oop design-patterns object-oriented-analysis


【解决方案1】:

您需要定义要添加的方法的功能。

interface Functionality {
public void persist();
}

除管理器外的每个类都需要实现接口:

 class Client1 implements Functionality{   
  //Your code..
}

添加不直接与低级类一起使用的高级类高级类:

Class ManageClients{
    Functionality func;

    public void setClient(Functionality f) {
        func= f;
    }


    public void manage() {
        func.persist();
    }
};
  • 添加客户端时,ManageClients 类不需要更改。

  • 将影响 ManageClients 类中存在的旧功能的风险降至最低,因为我们不更改它。

  • 无需重做 ManageClients 类的单元测试。

【讨论】:

  • 谢谢。我知道。但是“Foo”类是一个具体的类,将在客户端实现中实例化,如果我更改它,我将不得不更改所有客户端实现。
【解决方案2】:

我认为你从字面上理解这个有点了。

我有幸参加了 Venkat Subramaniam 的演讲,他谈到了 DIP。

当你说你应该依赖抽象而不是具体时,你是对的,但在那次演讲的笔记中,我有一个脚注,“对此持保留态度。”

在您的情况下,您可能会对此持保留态度,因为这里有相当强烈的代码气味 - 您将使用此 bean 暴露给所有需要它的消费者,这隐含地创建对它的依赖。这违反了Single Responsibility Principle,因为这个 bean 被用在了比它应该可能更多的地方。

由于您似乎在谈论数据库抽象,因此您可能希望查看DTO,它将在服务之间公开以在它们之间传输信息,并让您的 bean 处理内部。

你的意思...

如果它改变[s],那么我将不得不修改所有使用它的客户端

...如果您 删除 功能,这是真的。如果您添加新功能,您可以让下游客户忽略该功能。如果您想更改现有功能,您必须允许客户端迁移路径。

【讨论】:

    【解决方案3】:

    @chrylis 的评论很到位。 Robert Martin 在 Clean Code: Objects and Data Structures 的第 6 章中对此进行了介绍。

    对象将它们的数据隐藏在抽象之后,并公开对这些数据进行操作的函数。数据结构暴露了它们的数据并且没有有意义的功能。 (第 95 页)

    一切都是对象,没有数据结构的 OOP 的定义是幼稚的。

    成熟的程序员知道一切都是对象的想法是一个神话。有时您确实确实想要简单的数据结构,并在其上运行过程。 (第 97 页)

    那么暴露数据和行为的类呢?

    混乱有时会导致不幸的混合结构,即半对象半数据结构。它们具有做重要事情的函数,并且它们还具有公共变量或公共访问器和修改器,出于所有意图和目的,它们使私有变量成为公共变量,从而诱使其他外部函数像程序程序使用这些变量一样使用这些变量数据结构。 这种混合使得添加新功能变得困难,但也使得添加新数据结构变得困难。他们是两全其美的。避免创建它们。 (第 99 页)

    对于最初的问题:依赖倒置原则适用于对象,而不适用于 Java Bean 之类的数据结构。

    【讨论】:

    • 那么,当我必须实例化 Java Bean(数据结构)时,是否可以使用一些创建模式来避免硬编码?
    • 数据结构的目的是暴露细节,所以数据结构应该是具体的依赖。对象的目的是隐藏细节,所以对象应该是抽象的依赖。 The expression problem 更详细地描述了这种二分法,正如 Martin 在 Clean Code 中所做的那样。您不想避免对数据结构进行硬编码,因为这就是数据结构的用途(暴露细节)。在这方面,它与对象完全相反。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-10-06
    • 2010-09-20
    • 2013-12-10
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多