Java—这是一种糟糕的设计模式吗?

Java—这是一种糟糕的设计模式吗?,java,design-patterns,architecture,Java,Design Patterns,Architecture,在我们的应用程序中,我看到过这样编写的代码: java(用户实体) 公共类用户 { 受保护的字符串名; 受保护的字符串lastName; ... getter/setter(常规POJO) } 用户搜索命令 { 受保护的名单用户; 受保护的当前页面; 受保护的int-sortColumnIndex; 受保护的排序器排序器; //我们正在编辑的当前用户,如果有的话 受保护用户; 公共字符串getFirstName() {return(user.getFirstName());} 公共字符串getL

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

java(用户实体)

公共类用户
{
受保护的字符串名;
受保护的字符串lastName;
...
getter/setter(常规POJO)
}
用户搜索命令
{
受保护的名单用户;
受保护的当前页面;
受保护的int-sortColumnIndex;
受保护的排序器排序器;
//我们正在编辑的当前用户,如果有的话
受保护用户;
公共字符串getFirstName()
{return(user.getFirstName());}
公共字符串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);}

}
UserSearchCommand
{
受保护的名单用户;
受保护的当前页面;
受保护的int-sortColumnIndex;
受保护的排序器排序器;
//我们正在编辑的当前用户,如果有的话
受保护用户;
公共用户getUser()
{返回(用户);}
}
只需返回user对象,然后我们就可以根据需要对其调用任何方法了

由于这与典型的bean开发JSR303大不相同,因此bean验证不适用于此模型,我们必须为每个bean编写验证程序

是否有人认为这种设计模式有什么问题,或者我只是作为一个开发人员很挑剔


Walter

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

这建议了第一个示例。

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

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


当然这是一个文体问题,但我将投票支持你的第二个例子。

我同意你的观点。我见过同样的技术,但没有看到要点:它只意味着复制一大堆代码,为什么呢?

使用接口的第三个选项如何

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);
  }
}
UserSearchCommand
{
受保护的名单用户;
受保护的当前页面;
受保护的int-sortColumnIndex;
受保护的排序器排序器;
//我们正在编辑的当前用户,如果有的话
受保护用户;
公共I_用户名详细信息getUser()
{
返回((I_UserNameDetails)用户);
}
}

现在你可以通过界面进行抽象,防止修改用户对象。

也许你有一个更根本的问题:为什么你要在搜索对象中编辑用户?@Walter White:但在这个“最终高度”(包括Joshua Bloch)的时代,人们谈论“不变性”和“有效不变性”在任何地方,甚至整个语言都是围绕不变性的概念设计的,POJO本身(即可变槽设置器)的概念不是很糟糕的代码气味和反模式吗?;)朱丽叶,我同意你的意见,我就是这么说的。我认为我们不应该把这些顾虑混为一谈。他们的评论是这样更容易理解。Wizadofodds,我部分同意你的评论,但这仍然混合了担忧。这就是我应该做的。接口正是为这类事情而设计的。事实上,如果您已经在担心模式和反模式,那么就根本不应该公开类。接口应该公开。尽可能少,但要尽可能多。德米特定律提出了第二个例子,对吗?如果你正在编辑一个用户,只与用户交谈,而不使用UserSearchCommand?这就是我要说的,为什么要重复代码?这没有道理。我的理解是,它是这样发展的,不是因为容易,而是为了让这个家伙的控制器或其他东西工作。不,我们不做那种事。
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);
  }
}