【问题标题】:What's a design pattern to decouple services for owned entities?为自有实体解耦服务的设计模式是什么?
【发布时间】:2017-07-14 21:18:18
【问题描述】:

我正在寻找一种设计模式或约定来解耦处理自有实体的服务。假设我有一个ThemeService,它负责创建主题。起初,ThemeService 只是为每个用户的UserData 保留主题,但需求发生变化,主题由其他实体拥有,例如 ThemeCollection。我的问题是,每个ThemeService 都与它们的“拥有”实体紧密耦合。例如:

public class ThemeService{
    //coupled to UserData
    createTheme(Theme t, UserData u);
    getTheme(String name, UserData u);
    hasTheme(String name, Userdata u); //Theme name unique within a userdata.
    validateTheme(Theme t, UserData u); //unique name per user, valid colors, etc.
}

public class UserDataService{
   ThemeService tService; //component for themes

   getUsername(UserData u);
   addTheme(Theme t, UserData u){ tService.createTheme(t, u); }
   getTheme(String name, UserData u){ tService.getTheme(name, u); }
   hasThemes(String name, UserData u){ tService.hasTheme(name, u); }
}

现在 ThemeService 与 UserData 紧密耦合。如果需求发生变化并且主题可以属于另一个实体,例如 ThemeCollection,那么我无法真正重用 ThemeService 中的大部分代码,现在需要更多代码来处理 ThemeCollection 内容:

public class ThemeService{
    //...continued or in another ThemeService class...
    createTheme(Theme t, ThemeCollection c);
    getTheme(String name, ThemeCollection c);
    hasTheme(String name, ThemeCollection c);
    validateTheme(Theme t, ThemeCollection c);
}

public class ThemeCollectionService{
   ThemeService tService;

   getCollectionName(ThemeCollection c);
   addTheme(Theme t, ThemeCollection c){ tService.createTheme(t, c); }
   getTheme(String name, ThemeCollection c){ tService.getTheme(name, c); }
   hasThemes(String name, ThemeCollection c){ tService.hasTheme(name, c); }
}

我很想让它采用一个通用参数来实现类似“Themeable”的东西。但是,这会使实体实现一个接口:

public class ThemeService{
    createTheme(Theme t, Themeable owner);
    getTheme(String name, Themeable owner);
    hasTheme(String name, Themeable owner);
    validateTheme(Theme t, Themeable owner);
}

@Entity
public class UserData implements Themeable{
   getUsername();
   getThemes(); //From Themable
}

@Entity
public class ThemeCollection implements Themeable{
   getUsername();
   getThemes(); //From Themable
}

我没有在 Themeable 接口中包含创建、获取、验证等,因为我不希望我的实体类中的业务逻辑应该是一个纯数据结构(在模型中包含业务逻辑是草率的根据罗伯特马丁的“清洁代码”,我正在尝试遵循一些标准)。

是否有标准的方式、模式、约定等来解耦?我所拥有的或多或少“好的”还是在生产环境中不受欢迎?我试图摆脱“完成工作”的代码,转向模块化和可重用的代码,因此非常感谢任何帮助和指针。

编辑:“为什么您的服务与两个实体耦合?”

我需要一个地方来将拥有实体和拥有实体“缝合”在一起。例如,为 UserData 创建主题:

public void createTheme(Theme t, UserData u){
   entityManager.persist(t);

   if(!hasTheme(t.name(), u){
      u.getThemes().add(t);
      entityManager.merge(u);
   }
}

所以这个函数与 UserData 耦合,任何类似的“主题所有者”都会有类似的代码。

【问题讨论】:

  • 为什么您的服务要耦合到两个实体?你能发布一些代码来揭示原因吗?
  • @NiklasP 我在问题末尾添加了一个简短的 sn-p。
  • 这并不能完全回答问题。如果UserData 确实拥有 Theme,为什么除了更新UserData 实体之外,添加新主题还涉及其他任何事情?您提到的“拼接”可能应该在UserDataService中完成。
  • 在您的代码中创建紧密耦合的是UserDataServiceThemeService 的引用。每个服务方法都应该真正对应一个单一的业务逻辑操作,无论它是否涉及修改一个或多个数据实体。因此,一个服务很少需要依赖另一个服务(同时,可能需要多个存储库来实现业务目标;但这些不应包含除持久化和删除实体)。
  • @crizzis 发布 1:我想让主题逻辑更接近于成为一个组件。 UserData 拥有一个主题,但将来主题可能会被其他东西拥有。发布 2:我试图从 UserDataService 中分离出 ThemeService 逻辑,因为 UserDataService 将成为一个大类(即,用户将拥有主题、书签、设置等),但我想在这种情况下我应该有一个 UserThemeService , 专门将用户和主题拼接在一起?

标签: java jpa design-patterns service-layer decoupling


【解决方案1】:

一个好的方法是将主题集合的概念与用户分开。那么你有:

Class Theme
Class ThemeCollection  //all theme managment things go here
Class UserData  //has a member of type ThemeCollection

这样,与管理 Theme 相关的功能就在 ThemeCollection 中,可以在不同实体之间共享。

【讨论】:

  • 我的问题是 ThemeCollection 也只是一个数据结构。 ThemeCollection 需要知道如何持久化自身并合并其所有者,ServiceLayer 从数据结构中抽象出来。在数据库端将 ThemeCollection 缝合到其所有者的服务仍然存在耦合问题,它必须“知道”其所有者才能合并它。
  • 向 ThemeCollection 添加新主题时,所有者无需自行更新。因为,它已经与 ThemeCollection 保持了关系,并不关心其中的内容。只有 ThemeCollection 会被合并。
  • 是的,但我在之前的评论中的意思是,现在 ThemeCollection 与 Theme 所处的位置相同:ThemeCollection 仍然需要与 UserData 以及未来可能的其他实体绑定在一起.
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2010-12-18
  • 1970-01-01
相关资源
最近更新 更多