å æ¥ãDevLOVEã§çºè¡¨ãããã³ã¼ãã§å¦ã¶ãã¡ã¤ã³é§åè¨è¨å ¥éãã§ãããå ¥éã¨ããªãããé£ããã£ãããããã¾ãããã¢ããªã³ã°ã®è©±ã¯é£ããæ¹ã®è©±é¡ãªã®ã§ä»æ¹ãªãã®ã§ãããã§ããã ãããããããè£è¶³ããããã°ãæ¸ãã¦ã¿ããã¨æãã¾ãã
ã¾ããã¬ã¤ã¤ã¼ãã¢ã¼ããã¯ãã£ã®è©±ã§ããããã¡ãã®ã¹ã©ã¤ããåç
§ãã¦ãã ããã
DEVLOVE HangarFlight で話したスライド&ソースコード - じゅんいち☆かとうの技術日誌
å¹³ããè¨ãã¨ããã®ã¢ããªã±ã¼ã·ã§ã³ã解決ããåé¡ã®é åããã¡ã¤ã³ã§ãããã¡ã¤ã³ã¨ãã以å¤ã®ãã®ããã£ã¡ãã«ããªãããã«ããã®ãããã¡ã¤ã³é§åè¨è¨ã ã¨èããã°ããã¨æãã¾ãã
ä¸è¬çã«æ¥åã·ã¹ãã ã§ã¯ã対象æ¥åããã¡ã¤ã³ã«æãå¾ã¾ãã®ã§ããã¡ã¤ã³ã¯æ¥åã«æºãã¦èªããããã¨ãå¤ãã¨æãã¾ãããã¡ã¤ã³ã«ç»å ´ããæ¦å¿µãã¦ããã¿ã¹è¨èª*1ã¨ãã¦å®ç¾©ããã¢ãã«ã«è½ã¨ãããã¨ããã®ãè¨è¨ã®å¤§ã¾ããªæµãã§ãã
ã¾ããæ¥åã·ã¹ãã 以å¤ã®éçºãã¼ã«ã«ããã¡ã¤ã³ã¯ããã¾ããä¾ãã°ãã³ã³ãã¤ã©ã®ãã¡ã¤ã³ã¯ä½ã§ãããããã³ã³ãã¤ã«ãã¤ã¾ããããå½ä»¤ãæ§æ解æãæå³è§£æãªã©ãç¨ããå¥ã®å½ä»¤(æ©æ¢°èªãªã©)ã«å¤æãããã¨ãã«é¢ããåé¡ã®é åã§ãããã以å¤ã®ç»é¢ã«ã³ã³ãã¤ã«ã®é²æã表示ãããããã¡ã¤ã«ã«ã³ã³ãã¤ã«çµæãåºåããã®ã¯ãç´æ¥é¢ä¿ã®ãªããã¡ã¤ã³ä»¥å¤ã®è²¬åã¨æãã¾ããä¸è¨ã®ã¨ã³ããªã§ç´¹ä»ãã¦ããschema-generatorããã¹ãã¼ãã®çæãã«é¢ããåé¡ã®é åããã¡ã¤ã³ã§ãã
ã¤ã¾ãã¨ãããã¢ããªã±ã¼ã·ã§ã³ã¯ä½ãããã®ãã¡ã¤ã³ã®ããã«åå¨ãã¦ãã¾ãããã¢ããªã±ã¼ã·ã§ã³ã®æ¬æã¯ãã¡ã¤ã³ã«ãããã¨è¨ã£ã¦ãéè¨ã§ã¯ãªãã¨ãããã¨ã§ãã
ã¨ã³ãã£ãã£
ã¾ãããã¡ã¤ã³å±¤ã®ãªãã¸ã§ã¯ãããèãã¦ããã¾ãããããã§ã¯ã¤ã¡ã¼ã¸ããããããã«å®éã®ã½ã¼ã¹ã示ããªãã解説ãã¾ãã
ãã¡ã¤ã³å±¤ã®ãªãã¸ã§ã¯ãã«å«ã¾ããã¨ã³ãã£ãã£*2ã¨ãããªã¥ã¼ãªãã¸ã§ã¯ããã解説ãã¾ãã
/** * ã¨ã³ãã£ãã£ã表ãã¤ã³ã¿ã¼ãã§ã¤ã¹ã */ public interface Entity<T extends Entity<T>> extends Cloneable { /** * ã¨ã³ãã£ãã£ã®èå¥åãåå¾ããã * * @return {@link EntityIdentifier} */ EntityIdentifier<T> getIdentifier(); /** * ã¨ã³ãã£ãã£ã®{@link #getIdentifier() èå¥å}ãç¨ãã¦ããã®ã¨ã³ãã£ãã£ã®åä¸æ§ãæ¯è¼ããã * * @param that æ¯è¼å¯¾è±¡ãªãã¸ã§ã¯ã * @return åãèå¥åãæã¤å ´åã¯{@code true} */ boolean equals(Object that); /** * ãã®ã¨ã³ãã£ãã£ã®ããã·ã¥ã³ã¼ããè¿ãã * <p>Effective Java 第äºç é ç®9ã«å¾ããequalsã¡ã½ããã * ãªã¼ãã¼ã©ã¤ãããã¨ãã¯å¿ ãhashCodeã¡ã½ããããªã¼ãã¼ã©ã¤ãããã</p> * * @return ããã·ã¥ã³ã¼ã */ int hashCode(); /** * ãã®ã¨ã³ãã£ãã£ã®è¤è£½ãçæããã * * @return ãã®ã¨ã³ãã£ãã£ã®è¤è£½ã */ T clone(); }
ã¨ã³ãã£ãã£ã¯ãèå¥ï¼è¦åãããã¨ãç®çã®ã¢ãã«ãªã®ã§ãEntityIdentifieråã®identifierããããã£ããè¦åããããã®â身å â(ã¢ã¤ãã³ãã£ãã£ã¨ãè¨ã)ã表ãèå¥åã¨ãã¦æã¡ã¾ãããã®ä»ã®å±æ§ã«ã¯é¢å¿ããªããããã¤ã³ã¿ã¼ãã§ã¤ã¹ã¨ãã¦ã¯è¦å®ãã¾ãããã¾ããã¨ã³ãã£ãã£ã®åä¸æ§å¤æã¯equalsã¡ã½ããã§è¡ããèå¥åãåä¸ãã©ããã§å¤æããã¾ãã
ãã¨ãã°ã以ä¸ã®ãããªä¸è¨ã®Entityã¤ã³ã¿ã¼ãã§ã¤ã¹ãå®è£ ãã製å(Product)ã¨ã³ãã£ãã£ãããå ´åã«ãp1ã¨p2ã®ã¤ã³ã¹ã¿ã³ã¹ã§èå¥å以å¤ã®å±æ§ãç°ãªãã®ã«ãequalsã¡ã½ããã§ã¯trueãè¿ãã¾ããããã¯åãèå¥åã§ããããåä¸ã¨å¤å®ããã¾ãã
// 第ä¸å¼æ°ã製åã®èå¥åã第äºå¼æ°ã製åã®ä¾¡æ ¼ Product p1 = new Product(1L, 100); // implements Entity<Product> Product p2 = new Product(1L, 105); // implements Entity<Product> p1.equals(p2); // trueã¨ãªãã®ãã¨ã³ãã£ãã£ã // ã¤ã¾ããp1.getIndentifier().equals(p2.getIndentifier())ãæãç«ã¤ãã©ããã§åä¸æ§ãå¤å®ãã¦ããã
ãã®ä¾ã§ããä¾¡æ ¼ã®å±æ§ãã¤ã¾ãèå¥å以å¤ã®å±æ§ã«é¢å¿ããªãçç±ã¯ãã¨ã³ãã£ãã£ã®ç®çãèå¥ã ãã«ããããã§ãã
DDDã®åæ¸ã«ã5æ³ã®é ã®ç§ã¨åãã ããããã¨ããä¸ããããã¾ãããããã¯å¹´é½¢ã身é·ãªã©ã®å±æ§ã¯å¤åãã¦ããããç§ã¨ããå人ã¨ãã¦ã®ã¢ã¤ãã³ãã£ãã£ã¯å¤ãããªãã¨ããæå³ã§ãããã¨ãã°ãå¤ç®æ¼±ç³ã¯ãçã¾ããã¨ããããå¤ç®æ¼±ç³ãã¨ããã¢ã¤ãã³ãã£ãã£ã¯åå¨ãããã®ä¸ãã亡ããªã£ãå¾ããå¤ç®æ¼±ç³ãã¨ããã¢ã¤ãã³ãã£ãã£ã¯åå¨ãç¶ããã®ã§ãããã®ä¾ã§ããããããã«ãå®ã¯ã¨ã³ãã£ãã£ã¯ã©ã¤ããµã¤ã¯ã«ãæã¤ãªãã¸ã§ã¯ãã§ããã©ã¤ããµã¤ã¯ã«ãDDDã§ã©ã®ããã«æ±ããã¯ãå¥ã®ã¨ã³ããªã«ãã¾ãã
身å
ã¨ããã°ãæ¥å¸¸ã§ãããããæ¬äººç¢ºèªãã¨ããè¡çºã§ããæ¬äººç¢ºèªã¯ã便å®ä¸ãååãä½æãªã©ã®è¤æ°ã®å±æ§ããå®å
¨ã«ä¸è´ãããã©ããã§å¤å®ãã¾ããããããæ¬æ¥ããã®ãããªå±æ§ã¯ãã©ã¤ããµã¤ã¯ã«ã®éä¸ã§ã¤ãã³ããçºçãå¤åãã¦ãããã®ã§ãããã¨ãã°ãå¼è¶ãã§ä½æå¤æ´ãçµå©ã§èåãå¤ãããªã©ãã¤ã¾ããå±æ§ã¯æµè»¢*3ããã¨è¨ãã¾ãã
å°ãä¹±æ´ãªãã¨ãè¨ãã¨ãåããã³ã·ã§ã³ã®é¨å±ã«åå§ååã®äººãå¼è¶ãã¦ããå ´åãå±æ§ã§èå¥ããæ¹æ³ã ã¨è¦èª¤ã£ã¦ãã¾ã(èå¥ã®ééã)å¯è½æ§ãããã¾ãããã®ãããªäºã¯ç¨ãªã®ã§ãå®ç¨ä¸åé¡ããªãããããã¾ãããããããå¤ãã®æ
å ±ãæ±ããé«ãè«çæ§ãåãããã½ããã¦ã¨ã¢ã§ã¯ãæµè»¢ãã¦ããå±æ§ãé ¼ãã«èå¥ããã®ã¯å±ããæ¹æ³ã ã¨ãããã¾ããããã¯ããªãã¸ã§ã¯ãã®èå¥ãééããè´å½çãªãã¼ã¿æ±æãæããã¨ãæå³ãã¾ããå°ã説æãé·ããªãã¾ãããããã®ãããªçç±ã§ãã¨ã³ãã£ãã£ã§ã¯å±æ§ã§èå¥ããã«ãä¸æã¨ãªãèå¥åã§èå¥ããã®ã§ãã
ã¨ã³ãã£ãã£ã§ã¯ãèå¥å以å¤ã®å±æ§ã«ã¯é¢å¿ãããã¾ãããããã¡ã¤ã³ãªãã¸ã§ã¯ãã¨ãã¦å¿ è¦ãªå±æ§ãèªç±ã«å®ç¾©ã§ãã¾ãããã¨ãã°ã以ä¸ã®ãããªé¡§å®¢(Customer)ã¨ããã¨ã³ãã£ãã£ãããã¨ãããã顧客åã¨ãã¦Stringã®nameããããã£ãæã¤ã®ãèªç¶ã§ãããã
public final class Customer implements Entity<Customer> { @Override public EntityIdentifier<Customer> getIdentifier(){ ... } // setterãå®ç¾©ãã¦ã¯ãªããªããä¸å¤å±æ§ã§ãªããã°ãªããªãã @Override public boolean equals(Object that){ ... } @Override public int hashCode(){ ... } @Override public Customer clone(){ ... } // èå¥å以å¤ã®å±æ§ãå®ç¾©ãã public String getName(){ ... } public void setName(String name){ ... } // setterãããå¯å¤å±æ§ }
ã¨ã³ãã£ãã£ã®èå¥åã¯ãã©ã¤ããµã¤ã¯ã«ãéãã¦ä¸å¤(å¤ãããªããã¨)ã§ãªããã°ãªããªãã®ã§ãsetterãªã©èå¥åãæ¸ãæããã¡ã½ããã¯å®ç¾©ããªãã»ããããã§ãããã
final classã¨ãã¦ããçç±ã¯ãå®è£
ç¶æ¿ã許ããã¨ã§ç¶æ¿ã®é層ãæ·±ããªããã¨ãé²æ¢ããæå³ãããã¾ããç¶æ¿ã®é層ãæ·±ãããã¨ãã³ã¼ããè¤éã«ãªãå¾åã ããã§ããã¾ããã¨ã³ãã£ãã£ã¨ãã¦ã®åä¸æ§ãæ
ä¿ããããã«ãgetIdentifierãequals, hashCodeã®æ¯ãèããå¤æ´ã§ããªããããã¦ãã¾ããå ´åã«ãã£ã¦ã¯ãããã®ã¡ã½ããã ãfinalã¡ã½ããã«ãã¦ãããã§ãããã
ä¸è¨ã®Customerã®nameããããã£ã¯setNameã¡ã½ããããããããå¯å¤å±æ§ã§ããå¤ã¯ã©ã¤ããµã¤ã¯ã«ã®éä¸ã§å¤åãã¾ãããã®å±æ§ãå¤ãã£ã¦ããCustomerã®èå¥åã§ããidentifierããããã£ãä¸å¤ã§ããã°ããã®ã¨ã³ãã£ãã£ã¯ãã¤ã§ãèå¥ãããã¨ãã§ãã¾ãã
ã¨ã³ãã£ãã£ã®èå¥åã¨å¯å¤å±æ§ã¯ããçµã¿åããã§ãããå¯å¤ã§ãããã¨ã¯å¥ã®åé¡ãå¼ãèµ·ããã¾ãããããã å¯å¤ã¨å
±æã®åé¡ã§ããå¯å¤å±æ§ãæã¤ãªãã¸ã§ã¯ãã§ãããå¯å¤ãªãã¸ã§ã¯ããã¯ãã¢ããªã±ã¼ã·ã§ã³å
ã®ãã¡ãã¡ã§å
±æããã¨ãä¸å
·åãªã©ã§æå³ããªãå±æ§ã®æ´æ°ãçºçããå ´åã«ããã®åå ãç¹å®ãããã¨ãå°é£ã§ãã詳ããã¯ãEffective Java 第äºç é
ç®15ããããåç
§ã
ã¨ã³ãã£ãã£ã¯ããã¡ã¤ã³ã®ç¶æ
ãä¿æããé常ã«éè¦ãªãªãã¸ã§ã¯ãã§ãããã¢ããªã±ã¼ã·ã§ã³å
ã§å
±æããããªãã¸ã§ã¯ããªã®ã§ããã®åé¡ã¨ã¯åã£ã¦ãåãã¾ãããã§ã¯ãã©ã®ããã«è§£æ±ºããã¨ããã§ãããããå
¸åçãªè§£æ±ºæ¹æ³ã¯Entityã«cloneãå®è£
ãããã¨ã§ããcloneã«ãã£ã¦è¤è£½ããã¤ã³ã¹ã¿ã³ã¹ãå
±æããããã«ããã°ããã§ãããã
public final class Customer implements Entity<Customer> { ... @Override public Customer clone(){ try { return (Customer) super.clone(); } catch (CloneNotSupportedException e) { throw new Error("clone not supported"); } } ... } public static void main(String[] args){ Customer c = new Customer("kato"); Customer c1 = convertUpperCase(c); // æååãæ´æ°ããã¦ãã¾ãã Customer c2 = convertUpperCase(c.clone()); // ã¯ãã¼ã³ããã¤ã³ã¹ã¿ã³ã¹ãªã®ã§æ´æ°ããã¦ãåé¡ã¯ãªãã } // 顧客åã大æå表ç¾ã«å¤æããã¡ã½ãã private static Customer convertUpperCase(Customer customer){ customer.setName(customer.getName().toUpperCase()); return customer; }
è£è¶³ã§ãããequals, hashCodeã¯ãjava.lang.Objectã§å®è£ ããã¦ããã¡ã½ããã§ãããããå®è£ æ¼ãã§ãã³ã³ãã¤ã«ã¨ã©ã¼ã«ãªãã¾ãããããã¯æ¬¡ã«ç´¹ä»ããValueObjectã®ä¾ã§ãåæ§ã§ãã®ã§ã注æãã¦ãã ããã
ããªã¥ã¼ãªãã¸ã§ã¯ã
次ã¯ãããªã¥ã¼ãªãã¸ã§ã¯ãã§ãã
/** * ããªã¥ã¼ãªãã¸ã§ã¯ãã表ãã¤ã³ã¿ã¼ãã§ã¤ã¹ã */ public interface ValueObject { /** * å ¨ã¦ã®ããããã£ã®ç価æ§ãç¨ãã¦ããã®ããªã¥ã¼ãªãã¸ã§ã¯ãã®ç価æ§ãæ¯è¼ããã * * @param that æ¯è¼å¯¾è±¡ãªãã¸ã§ã¯ã * @return ç価ã®å ´åã¯{@code true} */ boolean equals(Object that); /** * ãã®ã¨ã³ãã£ãã£ã®ããã·ã¥ã³ã¼ããè¿ãã * * @return ããã·ã¥ã³ã¼ã */ int hashCode(); }
ã¤ã³ã¿ã¼ãã§ã¤ã¹ã§å®ç¾©ããã¦ããã¡ã½ããã¯ãequalsã¨hashCodeã ãã§ãã
è¥å¹²è©±ããé¸ãã¾ãããåè¿°ãããå¯å¤ãªãã¸ã§ã¯ããã¨ã¯å対ã«å±æ§ãã©ã¤ããµã¤ã¯ã«ãéãã¦ä¸å¤ãªã®ãããä¸å¤ãªãã¸ã§ã¯ããã§ããããªã¥ã¼ãªãã¸ã§ã¯ãã¯ãä¸å¤ãªãã¸ã§ã¯ããã§ãããã¨ãæ¨å¥¨ããã¦ãã¾ããStringãBigDecimalã¯ããã®ã¤ã³ã¿ã¼ãã§ã¤ã¹ã¯å®è£
ãã¦ãã¾ããããããªã¥ã¼ãªãã¸ã§ã¯ãã§ãã
ããªã¥ã¼ãªãã¸ã§ã¯ãã§ã¯ãä¿æãã¦ãããã¹ã¦ã®å±æ§ãç価ãã©ããã§ããã®ããªã¥ã¼ãªãã¸ã§ã¯ãã®ç価ãå¤å®ãã¾ããhashCodeããªãå®è£
ãããã¯ãEffective Java 第äºç é
ç®9ãåç
§ãã¦ãã ããã
ãã¨ãã°ãä¸è¨ã®ãããªå¾æ¥å¡ã®ã¨ã³ãã£ãã£ã§ã¯ãå¾æ¥å¡ã®ååã«ã人ã®åå(firstNameã¨lastName)ã表ãããªã¥ã¼ãªãã¸ã§ã¯ã PersonNameã¯ã©ã¹ãç¨ãã¦ãã¾ããPersonNameã¯ã©ã¹ã®equalsã¡ã½ããã§ã¯ãfirstNameã¨lastNameã®ãããããã®å±æ§ãç価ãã©ãããå¤å®ãããã¹ã¦ã®å±æ§ãç価ã§ããã°equalsã¡ã½ããã¯trueãè¿ãã¾ããhashCodeã¡ã½ããã¯ãããããã®å±æ§ã®ããã·ã¥ã³ã¼ããç¨ãã¦ãPersonNameã®ããã·ã¥ã³ã¼ããç®åºãã¦è¿ãã¾ãã
// å¾æ¥å¡ã表ãã¨ã³ãã£ãã£ã®å®è£ public final class Employee implements Entity<Employee> { private final EntityIdentifier<Employee> identifier; private PersonName name; public Employee(EntityIdentifier<Employee> identifier, PersonName name) { Validate.notNull(identifier); Validate.notNull(name); this.identifier = identifier; this.name = name; } @Override public EntityIdentifier<Employee> getIdentifier() { return identifier; } @Override public Entity clone() { try { return (Entity) super.clone(); } catch (CloneNotSupportedException e) { throw new Error("clone not supported"); } } @Override public int hashCode() { return identifier.hashCode(); } @Override public boolean equals(Object o) { if (this == that) { return true; } if (that == null || o instanceof Entity == false) { return false; } return identifier.equals(((Entity) o).getIdentifier()); } public PersonName getName() { return name; } public void setName(PersonName name) { this.name = name; } } // 人ã®ååã表ãããªã¥ã¼ãªãã¸ã§ã¯ãã®å®è£ public final class PersonName implements ValueObject { private final String firstName; private final String lastName; /** * ã¤ã³ã¹ã¿ã³ã¹ãçæããã * * @param firstName å * @param lastName æ° */ public PersonName(String firstName, String lastName) { Validate.notNull(firstName); Validate.notNull(lastName); this.firstName = firstName; this.lastName = lastName; } @Override public boolean equals(Object o) { if (this == o) { return true; } if (o == null || getClass() != o.getClass()) { return false; } PersonName that = (PersonName) o; if (firstName.equals(that.firstName) == false) { return false; } if (lastName.equals(that.lastName) == false) { return false; } return true; } @Override public int hashCode() { int result = firstName.hashCode(); result = 31 * result + lastName.hashCode(); return result; } public String getFirstName() { return firstName; } public String getLastName() { return lastName; } }
次ã¯ãã¨ã³ãã£ãã£ã®èå¥åã§ããEntityIdentifierã¨ãã®ããã©ã«ãå®è£ ã§ããDefaultEntityIdentifierã§ãã
/** * ã¨ã³ãã£ãã£ã®èå¥åã表ãããªã¥ã¼ãªãã¸ã§ã¯ãã * * @param <T> ã¨ã³ãã£ãã£ã®åãã³ã³ãã¤ã«æã ãå©ç¨ã */ public interface EntityIdentifier<T extends Entity<T>> extends ValueObject { /** * ãã®èå¥åã®ã«ã¤ã³ããåå¾ããã * <p>é常ã¯ã¨ã³ãã£ãã£ã®FQCNãæ ¼ç´ããã¦ãã</p> * * @return ã«ã¤ã³ã */ String getKind(); /** * ãã®èå¥åã{@link UUID}ã«å¤æããã * * @return {@link UUID} */ UUID toUUID(); } /** * {@link EntityIdentifier}ã®ããã©ã«ãå®è£ ã * * @param <T> ã¨ã³ãã£ãã£ã®åãã³ã³ãã¤ã«æã®ã¿å©ç¨ã */ public final class DefaultEntityIdentifier<T extends Entity<T>> implements EntityIdentifier<T> { private String kind; private UUID uuid; /** * ã¤ã³ã¹ã¿ã³ã¹ãçæããã * * @param entityClass ã¨ã³ãã£ãã£ã¯ã©ã¹ãã«ã¤ã³ãã«ã¯FQCNãè¨å®ãããã * @param uuid UUID * @return {@link DefaultEntityIdentifier} */ public DefaultEntityIdentifier(Class<T> entityClass, UUID uuid) { this(entityClass.getName(), uuid); } /** * ã¤ã³ã¹ã¿ã³ã¹ãçæããã * * @param kind ã«ã¤ã³ã * @param uuid {@link UUID} */ public DefaultEntityIdentifier(String kind, UUID uuid) { Validate.notNull(kind); Validate.notNull(uuid); this.kind = kind; this.uuid = uuid; } @Override public String getKind() { return kind; } @Override public UUID toUUID() { return uuid; } @Override public int hashCode() { int result = kind != null ? kind.hashCode() : 0; result = 31 * result + (uuid != null ? uuid.hashCode() : 0); return result; } @Override public boolean equals(Object o) { if (this == o) { return true; } if (o == null || o instanceof DefaultEntityIdentifier == false) { return false; } DefaultEntityIdentifier that = (DefaultEntityIdentifier) o; if (kind.equals(that.kind) == false) { return false; } if (uuid.equals(that.uuid) == false) { return false; } return true; } }
EntityIdentifierã®æ£ä½ã¯UUIDã§ããããã以å¤ã«èå¥ã®æ å ±ãå¿ è¦ã«ãªã£ãå ´åã¯UUIDã®åã§ã¯ä¸ååã§ããçºãããã§ã¯ã¨ã³ãã£ãã£ã®èå¥åå°ç¨ã®åãç¨æãã¦ãã¾ããããã§ã¯ãã³ã³ãã¤ã«æã®åã§ãã£ãããã«ã¤ã³ãã¨ããããããã£ã§ã¯ã©ã¹åãåã£ã¦ãã¾ããããã©ã«ãã®å®è£ ã§äºè¶³ããªãå ´åã¯ãç¬èªã®å®è£ ãä½ãã¨ããã§ãããã
ããã§ã²ã¨éãå¿ è¦ãªã¤ã³ã¿ã¼ãã§ã¤ã¹ã¨ã¯ã©ã¹ã¯ç»å ´ããã®ã§ãããEntityã¤ã³ã¿ã¼ãã§ã¤ã¹ã§å®ç¾©ããã¦ããã¡ã½ããã¯ã以ä¸ã®ãããªæ½è±¡ã¯ã©ã¹ã«éª¨æ ¼ã®å®è£ ãåãã£ã¦å®ç¾©ãããã¨ãå¯è½ã§ããå®éã«Entityãå®è£ ããéã¯ãAbstractEntityãç¶æ¿ããã¨ããã§ãããã
/** * {@link Entity}ã®éª¨æ ¼å®è£ ã * * @author j5ik2o */ public abstract class AbstractEntity<T extends Entity<T>> implements Entity<T> { private final EntityIdentifier<T> identifier; protected AbstractEntity(EntityIdentifier<T> identifier) { Validate.notNull(identifier); this.identifier = identifier; } @Override public EntityIdentifier<T> getIdentifier() { return identifier; } @Override public T clone() { try { return (T) super.clone(); } catch (CloneNotSupportedException e) { throw new Error("clone not supported"); } } @Override public int hashCode() { return identifier.hashCode(); } @Override public boolean equals(Object that) { if (this == that) { return true; } if (that == null || that instanceof Entity == false) { return false; } return identifier.equals(((Entity) that).getIdentifier()); } }
// AbstractEntityãç¶æ¿ãã¦å®è£ ããEmployeeã¯ã©ã¹ public final class Employee extends AbstractEntity<Employee> { private PersonName name; public Employee(EntityIdentifier<Employee> identifier, PersonName name) { super(identifier); Validate.notNull(name); this.name = name; } public PersonName getName() { return name; } public void setName(PersonName name) { this.name = name; } }
ã²ã¨ã¾ãããã®ã¨ã³ããªã§ã¯ããã¾ã§ã
ããã§ã¯ããã¡ã¤ã³ã¨ãã£ã¦ããå±æ§ã ãã§æ¯ãèãããªããã ã®ãã¼ã¿ã¯ã©ã¹ã¨ãã¦ã®å´é¢ãã触ãã¦ãã¾ããã次ã¯æ¯ãèãã¨ãµã¼ãã¹ã®è©±ããã¾ãã
è£è¶³ï¼
schema-generatorã§ãããã§ç´¹ä»ããã¤ã³ã¿ã¼ãã§ã¤ã¹ã¨åçã®ã¤ã³ã¿ã¼ãã§ã¤ã¹ãããã¾ããã»ã¼åãä»æ§ãªã®ã§ãããå帰çã¸ã§ããªãã¯ã¹(T extends EntityãT extends ValueObject)ã使ããsameIdentityAsãsameValueAsã®å¼æ°ã«å
·ä½çãªå®è£
åãæå®ã§ããããã«ãã¦ãã¾ããããã¯ããã§ä¾¿å©ãªã®ã§ããããã®çºã ãã«Tã®åãã©ã¡ã¼ã¿ãå©ç¨ããã®ã¯é¢åãããããªãã¨ããèãæ¹ã«åºã¥ãæ¡ç¨ãã¦ãã¾ããã
https://github.com/tricreo/schema-generator/blob/master/src/main/java/jp/tricreo/schemagenerator/domain/model/Entity.java
https://github.com/tricreo/schema-generator/blob/master/src/main/java/jp/tricreo/schemagenerator/domain/model/ValueObject.java
è£è¶³ã®è£è¶³ï¼
EntityIdentifier
Jiemamyã§ã¯EntityRefã¨ããã¯ã©ã¹ãæ¡ç¨ãã¦ãã¾ãããç§ã®ã»ãã§ã¯èå¥åã«ãã®å½¹å²ãæãããæ¹éã«ãªã£ã¦ãã¾ããè¦ã¯ãä¾åé¢ä¿ã®ççºãé²ãã«ã¯åç
§ãç´æ¥ä¿æããã®ã§ã¯ãªããèå¥åãæã£ã¦ãå¾ã«ç´¹ä»ãããªãã¸ããªããéæ¥çã«åç
§ãåå¾ããæ¦ç¥ã®ã»ããæå©ã¨ãããã¨ã§ãã詳ããã¯å¥ã®ã¨ã³ããªã§ã
è£è¶³ã®è£è¶³ã®è£è¶³ï¼
ããã§ã¯ãã¾ãæ¯ãèãã«ã¤ãã¦è¨åãã¦ãã¾ããããµã¼ãã¹ã¨ä¸ç·ã«èªã£ãæ¹ãããã¨æã£ãããã§ãã次ã®ãµã¼ãã¹ã®ã¨ã³ããªãä¸ç·ã«èªãã§ããã£ãã»ããããã¨æãã¾ãã
ãããã¦èªã¿ãã
コードで学ぶドメイン駆動設計入門 〜振る舞いとサービス編〜 - じゅんいち☆かとうの技術日誌
コードで学ぶドメイン駆動設計入門 〜ファクトリ編〜 - じゅんいち☆かとうの技術日誌
コードで学ぶドメイン駆動設計入門 〜リポジトリ編〜 - じゅんいち☆かとうの技術日誌
コードで学ぶドメイン駆動設計入門 〜アグリゲート編〜 - じゅんいち☆かとうの技術日誌
*1:ã¦ããã¿ã¹è¨èªã¯è¨è¨ã®æ ¹å¹¹ãè¦å®ããå ±éè¨èªã¨ãã¦ã®æ¦å¿µã§ããä¾ãã°ãã·ã¹ãã åãã対象ã®æ¥åã®è¨èããåãæå³ã ããããããªè¨èãåå¨ãã¦ãããã¤ã¾ãæºããã§ããã¨ãããããã®ã¾ã¾ã¢ãã«åããã·ã¹ãã ããã®ãããªææ§ãªè¦ç´ ãåæ ãããã®ã«ãªã£ã¦ãã¾ãã¾ããããã«ã¦ããã¿ã¹è¨èªã¯ã¨ã¦ãéè¦ãªæ¦å¿µã ã¨æãã¾ãã
*2:ã¨ã³ãã£ãã£ã¨ãã£ã¦ãJPAã®ã¨ã³ãã£ãã£ã§ã¯ããã¾ãããJPAã¯ã¤ã³ãã©ã¹ãã©ã¯ãã£å±¤ã«ä½ç½®ãã¾ãã®ã§ãä¸æ¦ERè³ã¯è§ã«ç½®ãã¦èãã¾ãã
*3:移ãå¤ãã£ã¦ãããã¨ããªããã¨