典型的应用包含很多实体,一些实体的共有特征可以抽象为基类。有两种方法:

    1. public interface IEntity{ }

    第一种是引入接口,这种方式要求每个实体都有最基本的功能和ID属性。看起来不错,但使用接口作为基类通常不推荐:接口不能很好地表示实体之间的关系,实现接口意味着类拥有功能,它是”能做没事“,而不是”是某种对象“
    image.png
    两个实现相同接口的类,它们在垂直关系上没有关联。换句话说,接口代表实现类拥有某种功能,但领域实体需要的是类继承——属于某类的概念。实体不仅有相同功能,而且它们都是实体。因此可以使用抽象类构造:

    1. package com.lugew.springbootddd;
    2. public abstract class Entity {
    3. protected long id;
    4. @Override
    5. public boolean equals(Object obj) {
    6. if (!(obj instanceof Entity)) {
    7. return false;
    8. }
    9. Entity other = (Entity) obj;
    10. if (this == other) // Reference equality
    11. return true;
    12. if (!this.getClass().equals(other.getClass()))
    13. return false;
    14. if (this.id == 0 || other.getId() == 0)
    15. return false;
    16. return this.id == other.getId(); //identifier equality
    17. }
    18. @Override
    19. public int hashCode() {
    20. final int prime = 31;
    21. int result = 1;
    22. result = prime * result + (int) (id ^ (id >>> 32));
    23. return result;
    24. }
    25. public long getId() {
    26. return id;
    27. }
    28. protected void setId(long id) {
    29. this.id = id;
    30. }
    31. }

    抽象类拥有可继承的ID,重写了equalshashCode方法。我们为equals方法增加了ID相等验证。hashCode方法确保两个相同id的对象返回的hashCode是一样的。接下来我们重构SnackMachine类:

    1. package com.lugew.springbootddd.snackmachine;
    2. import com.lugew.springbootddd.Entity;
    3. import lombok.Getter;
    4. import lombok.Setter;
    5. @Getter
    6. @Setter
    7. public final class SnackMachine extends Entity {
    8. private Money moneyInside;
    9. private Money moneyInTransaction;
    10. public void insertMoney(Money money) {
    11. moneyInTransaction = Money.add(moneyInTransaction, money);
    12. }
    13. public void returnMoney() {
    14. //moneyInTransaction = 0
    15. }
    16. public void buySnack() {
    17. moneyInside = Money.add(moneyInside, moneyInTransaction);
    18. //moneyInTransaction = 0
    19. }
    20. }

    image.png
    SnackMachine类从基类继承了ID属性和判断相等的方法。