Riepilogo
Ho cercato di capire la coesione di alcune funzionalità nella nostra base di codice. Ho affrontato questo design in modi diversi, e ultimamente sono convinto di aver preso l'approccio sbagliato, poiché ho applicato in modo errato il Principio di Responsabilità Unica.
Problema
Il dominio del problema è un pozzo, altrimenti noto come un buco rotondo nel terreno. Il codice attuale è simile a questo ... Ho un set di dati in un oggetto solo dati ...
Nota: questo non è il codice completo, ma solo i nomi dei metodi per evitare problemi ...
public class WellData
{
public string Name { get; set; }
public ICollection<SurveyPoint> SurveyPoints { get; set; }
public ICollection<GeometryItem> GeometryItems { get; set; }
public ICollection<TemperaturePoint> WellTemperature { get; set; }
public ICollection<FluidPoint> WellFluids { get; set; }
}
Ho rotto la funzionalità che opera su questi dati in diverse piccole classi. Come da sotto ...
public class ReferenceWellSurvey
{
ICollection<SurveyPointCalculate> _calculatedSurveyPoints;
double GetTvdAtDepth(double depth) {}
double GetAzimuthAtDepthRad(double depth) {}
double GetInclinationAtDepthRad(double depth){}
double GetTortuosityPeriodAtDepth(double depth ) {}
double GetTortuosityAmplitudeAtDepth(double depth ) {}
}
public class ReferenceWellGeometry
{
ICollection<GeometryItem> _geometryItems;
double GetFrictionAtDepth(double depth) {}
double GetHoleIdAtDepth(double depth) {}
}
public class ReferenceWellTemperature
{
ICollection<TemperaturePoint> _wellTemperatures;
double GetTemperatureAtDepth(double depth) {}
double GetSurfaceTemperature(double depth) {}
}
Etc.
Mi sono reso conto ultimamente guardando il nostro codice che devo rimettere insieme tutto questo per renderlo utilizzabile dove ne ho bisogno nella logica dell'applicazione. Qualcosa come ....
public class ReferenceWellData
{
private IReferenceWellGeometry _refWellGeometry;
private IReferenceWellTemperature _refWellGeometry;
private IReferenceWell _refWellGeometry;
private IReferenceFluid _refWellFluid;
//Proxy functions from each class to glue it all back together…
}
Alcune cose che mi hanno portato all'attuale situazione. La classe data well contiene diverse raccolte di informazioni e se tutto è in una classe la maggior parte delle funzioni funzionerà solo su un piccolo sottoinsieme di dati. All'epoca sentivo che avrebbe creato una bassa coesione, ora alcuni mesi dopo, sento che queste cose in realtà appartengono tutte insieme. Inoltre, nel mio codice sono presenti diverse classi che devono chiamare solo un metodo della classe ReferenceWellSurvey, GetTvdAtDepth (). In realtà quello che ho fatto non ha risolto questo problema.
Dopo aver riflettuto su questo argomento e dopo aver letto questo articolo di Wikipedia link , sto iniziando a vedere che ho commesso alcuni peccati di programmazione.
• Bassa coesione
• Costruttore over injection in codice dove cerco di incollare le cose insieme
• Fornire una classe che dipende dall'accesso GetTvdAtDepth ad altri metodi di cui non ha bisogno, violando il principio di segregazione dell'interfaccia.
Soluzione
Sto cercando quel disegno Goldilox che non dà troppa responsabilità a nessuna classe (No God Objects), pur mantenendo un buon grado di coesione.
Le mie attuali riflessioni su come risolvere questo problema sono le seguenti. Spostare la funzionalità che opera sui dati del pozzo nella stessa classe. Questo dovrebbe aiutare a rendere questa funzionalità più vicina alla coesione comunicazionale / informativa.
public class WellData : IWellData
{
public string Name { get; set; }
public ICollection<SurveyPoint> SurveyPoints { get; set; }
public ICollection<GeometryItem> GeometryItems { get; set; }
public ICollection<TemperaturePoint> WellTemperature { get; set; }
public ICollection<FluidPoint> WellFluids { get; set; }
// Operates on SurveyPoint collection
double GetTvdAtDepth(double depth) {}
double GetAzimuthAtDepthRad(double depth) {}
double GetInclinationAtDepthRad(double depth){}
double GetTortuosityPeriodAtDepth(double depth ) {}
double GetTortuosityAmplitudeAtDepth(double depth ) {}
//Operates on WellGeometry collection
double GetFrictionAtDepth(double depth) {}
double GetHoleIdAtDepth(double depth) {}
//Operates on WellTemperature collection
double GetTemperatureAtDepth(double depth) {}
double GetSurfaceTemperature(double depth) {}
}
Successivamente per affrontare il problema di diverse classi che necessitano di una sola funzione, potrei trasformare questa funzione in un'interfaccia separata IGetTvdAtDepth. In questo modo, le mie classi che hanno bisogno di quella funzionalità possono dipendere solo da questa interfaccia, che posso ereditare nella mia interfaccia WellData, e implementarla lì, ma non legare le altre mie classi a tutte le funzionalità della mia classe WellData.
Riflessioni su questo approccio rispetto all'approccio originale? Una cosa che mi preoccupa di fare le cose è che nella mia API sto usando un'iniezione bastard per soddisfare le dipendenze richieste di questa classe ... In questo momento ho tre dipendenze richieste, un calcolatore Survey e una classe speciale che fa riferimento ai dati a diverse profondità misurate. Mi piacerebbe andare via da questo, ma questo sembra puntare a far sì che i servizi facciano più del lifting ...