Search code examples
javaspringjpa-2.0business-logicautowired

Business logic in domain objects


I am coding a ribbon/achievements system for a website and I have to write some logic for each ribbon in my system. For example, you could earn a ribbon if you're in the first 2,000 people registering to the website or after 1,000 post in the forum. The idea is very similar to stackoverflow's badges, really.

So, every ribbon is obviously in the database but they also need a bit of logic to determine when a user has earned the ribbon.

In the way I coded it, Ribbon is a simple interface:

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 is an abstract class that implements the Ribbon interface, avoiding the definition of the isEarned() method:

@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;
    }
}

You can see I define the inheritance strategy as SINGLE_TABLE (since I have to code like 50 ribbons and I don't need additional columns for any of them).

Now, a specific ribbon will be implemented like this:

@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
    }
}

This code works fine, the tables are created in the database in the way I expect (I use DDL generation in my local environment).

The thing is, it feels wrong to code business logic in a domain object. Is it good practice? Can you suggest a better solution? Also, I'm not able to Autowire any DAOs in the entity (FirstUsersRibbon) and I need them in the business logic (in this case, I need a DAO to check whether the user is in the first 2,000 users registered to the website).

Any help very appreciated.

Thank you!


Solution

  • The thing is, it feels wrong to code business logic in a domain object.

    Many would say the reverse was true: that it is an anti-pattern (an anaemic domain model) to have business logic anywhere else. See Domain-Driven Design for more information.

    You might then wonder what the middle tier of the conventional 3-tier architecture was for. It provides a service layer for the application. See my related question "What use are EJBs?".