Sto sviluppando un'applicazione basata sul web che tratta il monitoraggio delle unità di flotta.
In realtà ho già sviluppato il sistema ma negli ultimi sei anni le cose sono cambiate un po '. Normalmente le specifiche del software riguardavano il monitoraggio dei veicoli in tempo reale e quindi l'esecuzione di vari rapporti.
Come mai nel corso degli anni abbiamo avuto così tanti clienti in Europa che alcuni di loro volevano un comportamento personalizzato come inserire la data in cui sono state acquistate varie licenze e la data in cui scadono in modo da ricevere una notifica per ogni veicolo quando è il momento di acquistare nuova licenza, vignetta, assicurazione e così via ..
Tutto sembrava essere molto buono fino al momento in cui alcuni clienti hanno deciso di acquistare solo 100 dispositivi GPS, ma vogliono comunque che il resto dei 27 (ad esempio) veicoli entrino nel sistema in modo da ricevere notifiche sulla vignetta, date di scadenza di assicurazione e licenza. Quindi ho dovuto aggiungere una nuova variabile come
boolean hasGps;
Le cose sono andate ancora peggio. Alcuni clienti volevano collegare dispositivi GPS ai rimorchi dei veicoli in modo che possano monitorarli. Quindi l'unico modo per rendere ciò possibile è registrare i rimorchi come veicoli e utilizzare la stessa classe in cui ho dovuto aggiungere una nuova variabile di campo come:
boolean isTrailer;
Bene ... ancora una volta le cose sono diventate davvero brutte quando a un'azienda piaceva il sistema di misuratori di portata che colleghiamo ai veicoli e teniamo traccia del combustibile esaurito in modo che volessero avere un dispositivo GPS e un dispositivo misuratore di portata integrati nel loro GAS stazione. Ancora una volta ho dovuto aggiungere una nuova variabile come:
boolean isGasTank;
In questi giorni il capo ha deciso che la società inizierà a vendere dispositivi di localizzazione personali per guardie e cani da guardia.
Quindi ... ho deciso di riscrivere la logica del business e avere il codice più pulito. Tuttavia, in uno scenario reale sembra davvero difficile realizzare un buon design OOP.
Diciamo che abbiamo i seguenti tipi di unità di flotta in cui è possibile collegare un dispositivo GPS:
Veicolo, rimorchio, GasStationTank, nave, persona, animale
Tutte queste unità non hanno alcun comportamento. Hanno solo uno stato e campi di definizione.
L'unica eccezione in cui un dispositivo GPS non può essere collegato è l'oggetto Veicolo perché, come accennato, inseriamo alcuni veicoli fantasma in cui l'unico rilevamento riguarda le date di scadenza di varie licenze, vignette e assicurazioni.
La classe Vehicle ha la maggior parte dei campi dove le altre classi hanno solo id e alias . Alcuni dei campi del veicolo sono:
maxSpeed, fuelPer100, giri, misuratore di flusso, fuelNorms. serbatoi, digitaliEventi, analogEventi, parkingDefinition, workingDefinition,
Ecco cosa ho fatto finora:
public enum FleetUnitType {
VEHICLE, TRAILER, NONE_GPS_UNIT, GAS_STATTION_TANK, MOVING_NON_VEHICLE_UNIT
}
Classe astratta
public abstract class FleetUnit {
private final String id;
private String alias;
private String group;
private Optional<GpsDevice> gpsDevice;
private long dateTimeAddedToSystem;
private FleetUnit linkedFleetUnit;
public FleetUnit(String id, String alias, String group) {
if(id == null) throw new NullPointerException();
else
{
this.id = id;
}
this.alias = (alias == null ? id : alias);
this.group = group;
}
public abstract FleetUnitType getType();
}
Classe del veicolo che implementa la classe FleetUnit
public class Vehicle extends FleetUnit {
public static final double VBAT_CONST = 0.175;
private int maxSpeed;
private double urbanFuel100;
private double suburbanFuel100;
private double fuelPerHour;
double maxAccumulatorValueForZeroRevolution;
private Optional<Revolutions> revolutions;
private Optional<FlowMeter> flowMeter;
private Optional<FuelNorm> fuelNorm;
private final Map<Integer, FuelTank> fuelTanks;
private final Map<Integer, DigitalEvent> digitalEvents;
private ParkingDefinition parkingStartDefinition;
private WorkingDefinition workingStartDefinition;
public Vehicle(String id, String alias, String group, VehicleMetaData vMetaData) {
super(id, alias, group);
this.fuelTanks = new HashMap<>();
this.digitalEvents = new HashMap<>();
parkingStartDefinition = ParkingDefinition.ENGINE_OFF;
workingStartDefinition = WorkingDefinition.ENGINE_ON;
}
@Override
public FleetUnitType getType() {
if(super.getGpsDevice().isPresent()) return FleetUnitType.VEHICLE;
return FleetUnitType.NONE_GPS_DEVICE;
}
public static enum EngineState
{
MOVING, PARKED, STOPPED, WORKING, CONTACT, UNKNOWN
}
public static enum ParkingDefinition
{
ENGINE_OFF, TACHOGRAPH
}
public static enum WorkingDefinition
{
ENGINE_ON, MIN_DISTANCE_TRAVELED
}
public static enum MotoHoursCalculation
{
ACCUMULATOR, KANSHINA
}
}
Come puoi vedere, questi oggetti non hanno un comportamento ma semplicemente uno stato che è utile per vari rapporti come la distanza percorsa oggi o il combustibile esaurito e così via ...
Quindi alla fine la domanda è: dovrei mantenere questo disegno e poi fare il resto delle lezioni concrete per implementare la classe FleetUnit o dovrei fare qualcosa di completamente diverso?