Supponiamo di costruire un sistema per la gestione di strutture di dominio di grandi dimensioni come i prestiti bancari o il contratto di assicurazione. Alla radice del modello di dominio è una classe di prestito. Serve come un punto di ingresso per i livelli del modello di dominio, ad es. parti di prestito, informazioni sulla raccolta, parti contrattuali, garanzie, assicurazioni associate, ...
Diciamo che il nostro software può gestire diversi tipi di prestiti (ad esempio, credito immobiliare e credito al consumo). La classe di prestito ha un loanType di attributo (Enum) che descrive il tipo di prestito a cui stiamo parlando (ad esempio, RealEstateLoan, ConsumerLoan, InvestmentGoodsLoan, ...).
A seconda del tipo di prestito, le singole classi del modello di dominio dovrebbero esporre un comportamento specifico (ad esempio, una parte di prestito in un RealEstateLoan richiede determinati tipi di garanzie, in una ConsumerLoan sono ammesse solo persone fisiche come mutuatari, ...).
Il punto importante è che il tipo di root del modello di dominio dovrebbe influenzare il comportamento di alcuni (non tutti) nodi foglia del modello (ad esempio la classe ContractualParty che è diversi livelli oltre alla classe di prestito).
La nostra prima implementazione usava semplici istruzioni switch come
public class ContractualParty extends DomainObject
public Loan getLoanRoot() {
// navigation magic to navigate through several layers of domain
// objects all the way to the root Loan object
return root;
}
public List<PartyType> getAllowedTypes {
switch (getLoanRoot().getLoantype()) {
case ConsumerLoan: return new ArrayList<PartyType> (PartyType.NaturalPerson, PartyType.Couple) break;
case InvestmentGoodsLoan: return new ArrayList<PartyType> (PartyType.Company) break;
...
}
}
Ovviamente ci sono carenze di questo tipo di design in quanto non si adatta bene quando la complessità del dominio aumenta e / o se il numero di differenze comportamentali nelle singole classi aumenta.
Quello che mi piacerebbe ottenere è un'implementazione che: - consente di introdurre nuovi tipi di prestito nel sistema senza rompere quelli vecchi - è di tipo sicuro (o il più sicuro possibile) quando si introducono nuovi tipi di prestito nell'enumerazione LoanType. Invece di passare da una pagina all'altra di riferimenti alle dichiarazioni switchType o loanType, ... il compilatore mi dice dove sono necessarie le estensioni quando si introduce un nuovo tipo di prestito
Abbiamo iniziato a pensare di introdurre sottoclassi di prestito. Le sottoclassi potrebbero quindi introdurre metodi che contengono la logica dipendente da loanType come Loan.getAllowedPartyType (). I singoli oggetti del dominio potrebbero quindi "chiedere" la loro istanza di prestito per l'elenco dei tipi di partito autorizzati. Ciascuna sottoclasse di prestiti potrebbe implementare questi metodi in base alle proprie regole specifiche. Il problema con questo approccio ci è sembrato che le sottoclassi di prestito iniziassero ad assorbire la logica da tutti gli oggetti del dominio e gli oggetti del dominio avrebbero relegato semplicemente molte richieste all'oggetto radice di prestito.
Una leggera svolta su questo progetto sarebbe l'introduzione di una nuova interfaccia, la classe base astratta Loantype che offrirebbe la logica di business specifica del tipo agli oggetti del dominio. Invece di sottoclassi della classe di prestito, otterrebbe un riferimento su un'istanza di Loantype che potrebbe quindi essere utilizzata dai singoli oggetti di dominio. Tuttavia, questa è solo una leggera differenza rispetto al primo progetto e presenta lo stesso problema di capovolgere la struttura del dominio e svuotare la logica del dominio dai singoli oggetti del dominio.
Apprezzerei i tuoi pensieri, idee, indicazioni, ... su come progettare queste classi di dominio.