2017-12-01 3 views
1

を投影し、私は多くの相互依存の部分でプロジェクトを持っている:

myProject 
    - core 
    - core_web (depends on core) 
    - app1_core (depends on core) 
    - app1_web (depends on app1_core and core_web) 
    - app2_core (depends on core) 
    - app2_web (depends on app2_core and core_web) 

私はcorecore_webで定義された典型的なMVC片持ち:サービス、コントローラ、リポジトリ、JPAをエンティティなど

されるよう-app1プロジェクトはすべて、このコアのものを使用しています - 私はいくつかの@Configuration魔法で出て作業することができますapplication.propertiesといくつかの特定の構成を除き、追加の作品はありません。しかし、フィールドとListフィールドをエンティティに追加します。 DTO、工場、コントローラー、サービスなどは、デザインの観点からみれば、まるで不快感を感じる混乱のようなものになります。これを処理する、より良い、DRY-er、より良いベストプラクティスの方法があるのでしょうか?あるいは、エンティティにいくつかのフィールドを追加するだけで、ほぼすべてのクラスをコアコードから継承する必要がありますか? (簡潔さと素晴らしさのためにここにLombokを使用して)簡単な例として、ここではcoreから@Entity

です:

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

に余分なフィールドを追加仕事の。まともな、優雅な、重複しない、と私はエンティティの両方のクラスをスキャンしないように春に指示する限り、それはすべて良いです。それは退屈な取得を開始し、どこが、例えば、サービスコードの追加を開始するときされています。今、メイン質問

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に拡張されたBrideServiceという新しいクラスを作成し、super.createAccount()を呼び出しますか?だから私は今もその余分なフィールドを持つコマンドオブジェクトが必要ですか?バリデーターは余分なフィールドを処理する必要があるので、私はAccountValidatorクラスを継承していますか?あなたが見ることができるように、私は、この地味な継承されたクラスの滑りやすい斜面を取得し、ある時点でそれらを一般的に扱えるはずのすべてのクラスに1つまたは2つのフィールドのロジックを追加する目的にのみ役立ちます。つまり、それが多型の目的ですよね?だから、私はAccountをどこにでも使って、サービスなどは "ちょうどいいですか?"この絡み合った混乱のどこかにアダプタのパターンがうまくいくのでしょうか?アドバイスを事前に感謝します。

答えて

1

継承は滑りやすい斜面です。 Accountを拡張しないことをお勧めします。あなたは1つのフィールドを追加しているだけで、あまりにも多くのクラスを作成する価値はほとんどありません。私に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