2017-12-01 5 views
1

내가 많은 상호 의존 조각 프로젝트가 프로젝트 엔티티 등

대로 - 더 app1 프로젝트는이 모든 핵심 재료를 사용 - 좀 @Configuration 마법 해결할 수있을 것입니다 application.properties 일부 특정 구성을 제외하고 추가 조각이 없습니다.

그러나 필드와 List 필드는 엔터티에 추가됩니다. DTO, 공장, 컨트롤러, 서비스 등 모든 곳에서 추가 계단식 효과가 나타납니다. 디자인 관점에서 보았을 때 혼란스러운 상속의 혼란이 있습니다. DRY-er, best-practice-y 방식을 더 잘 처리 할 수있는 방법이 있습니까? 아니면 단지 엔티티에 몇 개의 필드를 추가하기 위해 거의 모든 클래스를 핵심 코드에서 상속해야합니까? 이제

package com.example.core; 

@Data 
@Entity 
@NoArgsConstructor 
@AllArgsConstructor 
@Table(name = "ACCOUNT") 
@ToString(of = {"id", "emailAddress", "name"}) 
@EqualsAndHashCode 
public class Account implements Serializable { 

    private static final long serialVersionUID = 1L; 

    @Embedded 
    private Address address; 

    @Id 
    @GenericGenerator(
      name = "SEQ_ACCOUNT_ID", 
      strategy = "org.hibernate.id.enhanced.SequenceStyleGenerator", 
      parameters = { 
        @Parameter(name = "sequence_name", value = "SEQ_ACCOUNT_ID"), 
        @Parameter(name = "initial_value", value = "1"), 
        @Parameter(name = "increment_size", value = "1") 
      } 
    ) 
    @GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "SEQ_ACCOUNT_ID") 
    @Column(name = "ACCOUNT_ID", updatable = false, nullable = false, unique = true) 
    private Long id; 

    @Column(name = "EMAIL", nullable = false, length = 200, unique = true) 
    private String emailAddress; 

    public void setEmailAddress(String emailAddress) { 
     this.emailAddress = StringUtils.lowerCase(emailAddress); 
    } 

    @JsonIgnore 
    @Column(name = "PASSWORD_HASH", nullable = false, length = 256) 
    private String passwordHash; 

    @Column(name = "NAME", nullable = false, length = 200) 
    private String name; 

    @Column(name = "PHONE", nullable = false, length = 30) 
    private String phoneNumber; 

    @Column(name = "URL") 
    private String url; 
} 

내가이 금액을 기대 app2

package com.example.app2; 

@Data 
@NoArgsConstructor 
@Table(name = "ACCOUNT") 
@ToString(callSuper = true) 
@EqualsAndHashCode(callSuper = true) 
public class Bride extends Account { 
    @Column(name = "WEDDING_DATE") 
    private Date weddingDate; 
} 

에 추가 필드를 추가하는 간단한 예를 들어

, 여기 @Entity core에서이기 (간결함과의 awesomeness 여기 Lombok 사용) 일의. 괜찮은, 우아하고, 많이 복사하지 않습니다. 그리고 Spring에게 엔티티에 대한 두 클래스를 모두 스캔하지 않는다고 말하면 모든 것이 좋습니다.

package com.example.core; 

@Service 
public class AccountService { 

    private AccountRepository accountRepository; 

    @Autowired 
    public AccountService(AccountRepository accountRepository) { 
     this.accountRepository = accountRepository; 
    } 

    /* the command object here would mirror Account, but contain some code 
    * to handle input validation and the like. I know I could just use the 
    * entity class, but I've been bitten by using entity classes as DTOs or 
    * command objects before, so I'd like to keep them separate. 
    */ 
    public Account createAccount(CreateAccountCommand createAccountCommand) { 
     Account account = new Account(); 
     account.setEmailAddress(createAccountCommand.getEmailAddress()); 
     account.setPasswordHash(createPasswordHash(createAccountCommand.getPassword())); 
     account.setName(createAccountCommand.getName()); 
     account.setPhoneNumber(createAccountCommand.getPhoneNumber()); 
     account.setUrl(createAccountCommand.getUrl()); 
    } 
} 

이제 주요 질문 : 어디 지루한 내가 예를 들어, 서비스 코드를 추가 시작하면됩니다 얻기 시작 어떻게 (읽기 :해야한다) 내가 Bride에 추가 필드를 처리? AccountService을 확장하고 super.createAccount()을 호출하는 BrideService이라는 새 클래스를 만드시겠습니까? 그럼 이제 그 안에 추가 필드가있는 명령 개체가 필요합니까? 그리고 유효성 검사기는 추가 필드를 처리해야하므로 AccountValidator 클래스에서 상속 받습니까? 보시다시피, 나는 어떤 지점에서 일반적으로 처리 할 수 ​​있어야하는 모든 클래스에 하나 또는 두 개의 필드 논리를 추가하는 목적에 만 사용되는 지저분한 상속 된 클래스의 미끄러운 슬로프를 얻습니다. 그게 다형성의 목적입니다. 맞죠? 그래서 나는 장소와 서비스, 등등에 온통 Account을 사용할 수 있습니다. "그냥 작동합니까?" 이 얽힌 엉망에 어딘가에 어댑터 패턴이 작동할까요? 어떤 조언을 주셔서 미리 감사드립니다.

답변

1

상속은 미끄러운 경사입니다. 나는 당신이 Account을 확장하지 않을 것을 제안 할 것이고, 단지 하나의 필드를 추가 할 뿐이며, 그만큼 더 많은 클래스를 만들 가치는 거의 없습니다. 내게 Bride은 실제로 Account처럼 느껴지지 않습니다. 아마도 BrideAccount이 더 나은 이름이 될 것입니다. 그러나 대신 컴포지션을 사용할 수 있습니까?

@Entity 
public class BrideAccount { 

    @ID 
    Integer id; 

    @Column(name = "WEDDING_DATE") 
    private Date weddingDate; 

    Account account; 
} 

이 컨트롤러를 모두 확장 할 필요는 없지만 다시 사용할 수는 있습니다.

다른 옵션은 계정의 인터페이스를 만들고 모든 컨트롤러가 인터페이스를 사용하고 필요한 것만 확장하도록하는 것입니다.

하지만 필요하지 않으면 수업을 추가하지 않는 것이 좋습니다. Account 클래스에 필드를 추가 할 수 있다면 모든 계정에서 사용하지 않는 것입니다. 예를 들어 수퍼 세트 클래스에서와 같이 IMO를 사용하는 것이 좋습니다. 어떤 필드를 사용하고 어떤 필드를 사용하지 않는지에 대해 정말로 신중해야합니다. AccountType과 같은 다른 필드는 계정 유형이 무엇인지 알려주는 목적으로 필요할 수 있습니다. 그러면 결혼 필드가 사용 중인지 알 수 있습니다. 이것은 CreateAccountCommand에도 필요합니다. 나는 비슷한 질문에 대답했다 : Dynamically constructing composition object. 일반적으로 복잡한 유형 계층 구조에 대한 경험으로 인해 해결 된 것보다 많은 문제가 발생하기 때문에 더 많은 클래스를 작성하지 않는 것이 기본값입니다.

+1

굉장한 대답과 정확하게 내가 찾고 있었던 것. 고맙습니다. – Andy