【问题标题】:Java - Is this a bad design pattern?Java - 这是一个糟糕的设计模式吗?
【发布时间】:2010-04-01 14:14:23
【问题描述】:

在我们的应用程序中,我见过这样写的代码:

User.java(用户实体)

public class User
{
  protected String firstName;
  protected String lastName;

 ...
   getters/setters (regular POJO)
}

UserSearchCommand
{
   protected List<User> users;
   protected int currentPage;
   protected int sortColumnIndex;
   protected SortOder sortOrder;

   // the current user we're editing, if at all
   protected User user;

   public String getFirstName()
   {return(user.getFirstName());}

   public String getLastName()
   {return(user.getLastName());}

}

现在,根据我的经验,这种模式或反模式对我来说看起来很糟糕。一方面,我们将几个问题混合在一起。虽然它们都是与用户相关的,但它偏离了典型的 POJO 设计。如果我们要走这条路,那我们不应该这样做吗?

UserSearchCommand
{
   protected List<User> users;
   protected int currentPage;
   protected int sortColumnIndex;
   protected SortOder sortOrder;

   // the current user we're editing, if at all
   protected User user;

   public User getUser()
   {return(user);}

}

只需返回用户对象,然后我们就可以随意调用它的任何方法了吗?

由于这与典型的 bean 开发 JSR 303 完全不同,因此 bean 验证不适用于此模型,我们必须为每个 bean 编写验证器。

其他人认为这种设计模式有什么问题吗,还是我只是作为开发人员很挑剔?

沃尔特

【问题讨论】:

  • 也许你有一个更根本的问题:你为什么要在 search 对象中编辑用户?
  • @Walter White:但在当今人们“高度重视final”(包括Joshua Bloch)并到处谈论“不变性”和“有效不变性”的时代甚至围绕不变性概念设计的整个语言,POJO 本身的概念(它是可变的槽设置器)不是非常糟糕的代码气味和反模式吗? ;)
  • 朱丽叶,我同意你的评论,我就是这么说的。我认为我们不应该混淆这些担忧。他们的评论是这样更容易理解。 WizardOfOdds,我部分同意您的评论,但这仍然令人担忧。

标签: java design-patterns architecture


【解决方案1】:

在返回用户对象时,您让 UserSearchCommand 在现有数据上写入新信息,这可能不是人们想要允许的,因为搜索应该允许读取数据。此外,您所做的是让使用 UserSearchCommand 的人必须知道 User 类上的方法/属性/成员,这在第一个实现中并非如此。

【讨论】:

    【解决方案2】:

    使用接口的第三个选项怎么样?

    UserSearchCommand
    {
      protected List<User> users;
      protected int currentPage;
      protected int sortColumnIndex;
      protected SortOder sortOrder;
    
      // the current user we're editing, if at all
      protected User user;
    
      public I_UserNameDetails getUser()
      {
        return((I_UserNameDetails)user);
      }
    }
    

    现在您可以通过接口进行抽象并防止修改用户对象。

    【讨论】:

    • 这就是我会做的。接口正是针对这类事情的。事实上,如果你已经在担心模式和反模式,那么根本就不应该暴露类。相反,应该公开接口。尽可能少,但尽可能多。
    【解决方案3】:

    Law of Demeter 建议第一个示例。

    【讨论】:

    • 得墨忒耳法则提出了第二个例子,对吧?如果您正在编辑用户,只与用户交谈而不通过 UserSearchCommand?
    【解决方案4】:

    虽然 Sjoerd 和 JB 提出了有效的观点,但根据您对 SearchCommand 的使用,我将为第二个示例提出以下论点。如果您在第一个示例中定义的操作不影响 UserSearchCommand 的行为,那么通过定义 getFirstName() 等,您实际上只是在复制代码,这可能会导致可维护性问题,例如,如果稍后添加中间用户类的名称?然后,您不仅需要将其添加到用户,还需要在 UserSearchCommand 中添加访问器。如果对用户做某事会修改搜索的行为,那么这可能是让调用者通过搜索命令访问用户的有效参数,但这也可以通过诸如 PropertyListeners 之类的机制来实现。

    正如您所指出的,第一个示例是将信息混合在一起,在我看来,从 OOP 的角度来看,这似乎违反直觉。如果这是一个限制用户访问某些属性的问题,那么它可能是更改访问修饰符的问题,或者创建一个公开您认为安全的接口和一个公开适当的包/受保护属性的实现类。除非您的 UserSearchCommand 用词不当,否则我希望它执行涉及搜索用户的操作,然后使这些用户作为一个单元可用(而不是用户的单个属性)。也就是说,搜索命令应该执行与搜索相关的操作,并且用户应该包含有关用户的信息。

    当然,这是一个风格问题,但我会投票给你的第二个例子。

    【讨论】:

    • 这就是我的意思,为什么要重复代码?这没有意义。我的理解是,它的开发方式不是因为简单,而是为了让其他东西为这个家伙的控制器或其他东西工作。不,我们没有做那种事情。
    【解决方案5】:

    我同意你的看法。我见过同样的技术,但没看清重点:它只是意味着复制一大堆代码,为了什么?

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2012-09-06
      • 2011-08-01
      • 1970-01-01
      • 1970-01-01
      • 2011-01-13
      • 1970-01-01
      • 2011-06-09
      相关资源
      最近更新 更多