Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles / All-Topics

Anemic Domain Model

4.00/5 (1 vote)
21 Jan 2015CPOL2 min read 11.9K  
Anemic Domain Model

The anemic domain model is surprisingly common, even though many refer to it as an anti-pattern. I try not to be that dogmatic about it and rather consider it to be a code smell. It's good to be fully aware of the tradeoffs of different options so the right choice can be made in a given context.

The main characteristic of an anemic model is it doesn't contain much (or any) business logic. The domain logic is placed to where the model is used, usually to services.

I'll use a simple example to highlight the main differences of an anemic and a rich domain model. In our sample system there are customers, they have payment accounts. On each payment, a discount is calculated according to the membership level of the customer. A basic member gets discount only if his payment exceeds a certain amount. A premium member always gets a discount.

An anemic model for the specification above would look like this:

Java
class Customer {
   private Account account;
   private Membership membership;

   public Account getAccount() {
       return account;
   }

   public Membership getMembership() {
       return membership;
   }
}

class Account {
   private double balance;

   public double getBalance() {
       return balance;
   }

   public void setBalance(double balance) {
       this.balance = balance;
   }
}

interface Membership {
}

class BasicMembership implements Membership {
   private double discount;
   private double discountMinimum;

   public double getDiscount() {
       return discount;
   }

   public double getDiscountMinimum() {
       return discountMinimum;
   }
}

class PremiumMembership implements Membership {
   private double discount;

   public double getDiscount() {
       return discount;
   }
}

class PaymentService {
   public void pay(Customer customer, double amount) {
       if(customer.getMembership() instanceof BasicMembership) {
           payBasic(customer, amount);   
       } else if(customer.getMembership() instanceof PremiumMembership) {
           payPremium(customer, amount);   
       }
   }

   private void payBasic(Customer customer, double amount) {
       BasicMembership basic = (BasicMembership) customer.getMembership();
       double paid;
       if (amount >= basic.getDiscountMinimum())
           paid = amount * basic.getDiscount();
       else
           paid = amount;
       withdrawAmount(customer.getAccount(), paid);

   }

   private void payPremium(Customer customer, double amount) {
       PremiumMembership premium = (PremiumMembership) customer.getMembership();
       double paid = amount * premium.getDiscount();
       withdrawAmount(customer.getAccount(), paid);
   }

   private void withdrawAmount(Account account, double amount) {
       if(account.getBalance() > amount)
           account.setBalance(account.getBalance() - amount);
       else
           throw new RuntimeException("Balance low");
   }
}

A sample use is: paymentService.pay(customer, amount);

Here, we can see some of the problems of an anemic model. It violates basic OO principles like encapsulation. The main problem is the model can't ensure its correctness and the code is procedural. The service code can get complicated and things get worse when the complexity of the domain increases.

Let's see how things look with a rich domain model instead:

Java
class Customer {
   private Account account;
   private Membership membership;

   public void pay(double amount) {
       double paid = membership.discountPrice(amount);
       account.withdraw(paid);
   }
}

class Account {
   private double balance;

   public void withdraw(double amount) {
       if(balance >= amount)
           balance -= amount;
       else
           throw new RuntimeException("Balance low");
   }
}

interface Membership {
   public double discountPrice(double origAmount);
}

class BasicMembership implements Membership {

   private double discount;
   private double discountMinimum;

   public double discountPrice(double origAmount) {
       return (discountMinimum >= origAmount) ? origAmount * discount : origAmount;
   }
}

class PremiumMembership implements Membership {
   private double discount;

   public double discountPrice(double origAmount) {
       return origAmount * discount;
   }
}

A sample use is: customer.pay(amount);

The rich domain model shows many benefits over the anemic model. Objects are encapsulated, the model can guarantee its correctness. High complexity can be easier dealt with because of the rich possibilities of OO. On top of that, such a domain model can be much more expressive. This can be easily demonstrated by an interface comparison:

Customer
+getAccount() : Account
+getMembership() : Membership

Account
+setBalance(balance: double)
+getBalance() : double

Membership

BasicMembership
+getDiscount() : double
+getDiscountMinimum() : double

PremiumMembership
+getDiscount() : double

PaymentService
+pay(customer: Customer, amount: double)

VS

Customer
+pay(amount: double)

Account
+withdraw(amount: double)

Membership
+discountPrice(origAmount : double)

So we can ask the question, what are the valid reasons for an anemic model and why are they so common? Making a rich domain model can be more difficult and requires developers with solid OO design skills. Also, a rich model emphasizes the general tension between the principles of encapsulation and separation of concerns. For instance, in a persistence or view layer, it's more trivial to extract data from an anemic model. There are a lot of ways and patterns to address these issues but generally require a little extra effort.

Since the benefits of it are so great, I think it's usually best to go with a rich domain model - unless there is a really good reason to do otherwise.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)