【问题标题】:Business logic in domain objects领域对象中的业务逻辑
【发布时间】:2012-05-27 10:32:37
【问题描述】:

我正在为网站编写功能区/成就系统,我必须为系统中的每个功能区编写一些逻辑。例如,如果您是注册网站的前 2,000 人中或在论坛中发帖 1,000 条之后,您就可以获得勋章。这个想法非常类似于 stackoverflow 的徽章,真的。

因此,显然每个功能区都在数据库中,但它们还需要一些逻辑来确定用户何时获得功能区。

按照我的编码方式,Ribbon 是一个简单的界面:

public interface Ribbon {
    public void setId(int id);
    public int getId();
    public String getTitle();
    public void setTitle(String title);
    public boolean isEarned(User user);
}

RibbonJpa是一个抽象类,实现了Ribbon接口,避免了isEarned()方法的定义:

@Entity
@Table(name = "ribbon")
@Inheritance(strategy = InheritanceType.SINGLE_TABLE)
@DiscriminatorColumn(name = "ribbon_type")
public abstract class RibbonJpa implements Ribbon {
    @Id
    @Column(name = "id", nullable = false)
    int id;

    @Column(name = "title", nullable = false)
    private String title;

    @Override
    public int getId() {
        return id;
    }

    @Override
    public void setId(int id) {
        this.id= id;
    }

    @Override
    public String getTitle() {
        return title;
    }

    @Override
    public void setTitle(String title) {
        this.title = title;
    }
}

您可以看到我将继承策略定义为 SINGLE_TABLE(因为我必须编写 50 个功能区,并且我不需要为其中任何一个添加额外的列)。

现在,一个特定的功能区将像这样实现:

@Entity
public class FirstUsersRibbon extends RibbonJpa implements Ribbon {
    public FirstUsersRibbon() {
        super.setId(1);
        super.setTitle("First 2,000 users registered to the website");
    }

    @Override
    public boolean isEarned(User user) {
        // My logic to check whether the specified user has won the award
    }
}

这段代码工作正常,表是按照我期望的方式在数据库中创建的(我在本地环境中使用 DDL 生成)。

问题是,在域对象中编写业务逻辑感觉是错误的。这是好习惯吗?您能提出更好的解决方案吗?此外,我无法在实体 (FirstUsersRibbon) 中自动装配任何 DAO,我需要在业务逻辑中使用它们(在这种情况下,我需要一个 DAO 来检查用户是否在注册到的前 2,000 个用户中网站)。

非常感谢任何帮助。

谢谢!

【问题讨论】:

  • 您听说过 SOLID 吗?我认为您在这里违反了两条原则。 LSP(在您的 RibbonJpa 类中实现 Ribbon)和 ISP(Ribbon 中的方法签名)

标签: java spring jpa-2.0 business-logic autowired


【解决方案1】:

问题是,在域对象中编写业务逻辑感觉不对。

许多人会说反过来是正确的:在其他任何地方都有业务逻辑是一种反模式(anaemic domain model)。请参阅Domain-Driven Design 了解更多信息。

然后您可能想知道传统 3 层架构的中间层是干什么用的。它为应用程序提供了一个服务层。请参阅我的相关问题“What use are EJBs?”。

【讨论】:

  • 感谢您提供此信息,@Raedwald。很高兴知道我正在遵循正确的方法:) 你知道为什么我不能在域对象中自动装配 DAO(或任何其他组件)吗?有什么解决办法吗?谢谢。
  • 我是 Spring 新手,所以对此我无能为力。听起来你应该问一个单独的问题。
  • 注 1:如果您打算在实体中实现业务逻辑,请注意,如果您传递与分离对象相同的内容,客户端也可以访问业务逻辑。客户必须只提供数据而不是业务逻辑。注2:FirstUsersRibbon不需要像RibbonJpa那样显式实现Ribbon接口。
【解决方案2】:

另外,我无法自动装配实体中的任何 DAO

如果您使用 Spring 和 Hibernate,请查看 http://jblewitt.com/blog/?p=129:这很好地描述了具有多种解决方案的类似问题。

如果您正在以您描述的方式寻找丰富的域模型,那么通过 Spring 实例化域对象可能是一个好主意,从而能够将 DAO 注入到您的域对象中。

【讨论】:

  • 把补充问题作为答案不是SO风格。您应该将此作为一个单独的问题提出。
猜你喜欢
  • 2014-02-24
  • 2016-12-06
  • 2011-08-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-11-06
  • 1970-01-01
相关资源
最近更新 更多