Come progettare una classe di servizio datetime business che esegue due tipi di calcoli basati su un argomento passato in

0

Contesto

Sto facendo una classe di servizio che funziona essenzialmente come un calcolatore di business datetime. Cioè, può eseguire vari calcoli come ad esempio la data è X giorni lavorativi da una determinata data, quando è l'inizio della prossima data di lavoro, è una data specifica in orario di lavoro, ecc.

Il problema è che questa classe deve prendere vari parametri che lo rendono un po 'più complesso. In particolare, le ore di lavoro e le festività definite dall'utente vengono passate quando la classe viene inizializzata; tutti i metodi che eseguono questi calcoli datetime aziendali devono tenere conto di tali orari di lavoro e festività. Le ore di lavoro sono definite da un dizionario che mappa i giorni della settimana alle ore di lavoro di ciascuno di quei giorni. Ciò significa che questa classe deve gestire orari di lavoro "non standard", come martedì-giovedì 14: 00-01: 00, venerdì-sabato 16: 00-03: 00. (Sto definendo ciò che un programma di lavoro "standard" e "non standard" si basa su una metrica che ho elaborato - non è importante per questa domanda come sono definiti).

Le pianificazioni di lavoro standard sono facili da gestire, mentre le pianificazioni di lavoro non standard rendono le cose più complesse. Ho pensato a come affrontare questo problema e sono giunto alla conclusione che l'implementazione di questi calcoli dovrebbe differire tra i piani di lavoro standard e non standard. Cioè, per ogni metodo, se abbiamo a che fare con una pianificazione di lavoro standard, fai X; se abbiamo a che fare con una pianificazione non standard, fai Y.

Domanda

Qual è la migliore pratica per impostare questa classe? Ecco le opzioni a cui posso pensare:

  1. Ogni metodo dovrebbe avere solo un'istruzione if / else:

    if (standardWorkSchedule)
    {
        // do standard work schedule stuff
    }
    else
    {
        // do non-standard work schedule stuff
    }
    
  2. Crea un'interfaccia, IBusinessDateTime , con tutti i metodi per i calcoli aziendali datetime. Quindi, crea due classi di servizio distinte, StandardBusinessDateTime : IBusinessDateTime e NonStandardBusinessDateTime : IBusinessDateTime , che implementano questa interfaccia. StandardBusinessDateTime implementerà la logica di pianificazione del lavoro standard per i suoi metodi, mentre NonStandardBusinessDateTime implementerà la logica di pianificazione del lavoro non standard. Infine, crea una classe intermedia aggiuntiva, BusinessDateTime : IBusinessDateTime , che includa il piano di lavoro e determini se è standard o non standard. Ovunque che utilizza questa classe di servizio è sufficiente chiamare i metodi di questa classe intermedia e scaricare il lavoro effettivo nelle altre due classi. Se è standard, usa StandardBusinessDateTime ; se non è standard, usa NonStandardBusinessDateTime .

Non ho molta familiarità con i modelli di progettazione, quindi è possibile che sto descrivendo un problema abbastanza comune e di base, e le soluzioni che ho proposto sono schemi di progettazione comunemente utilizzati. Sento che l'opzione 2 è la soluzione migliore, ma voglio solo assicurarmi. Inoltre, sono sicuro che ci sono altre e forse migliori soluzioni - apprezzo ogni aiuto che posso ottenere con questo.

Infine, voglio sottolineare che sono non a chiedere una delle seguenti cose :

  • Come implementare un calcolatore di data / ora aziendale

  • Come definire pianificazioni di lavoro standard e non standard

  • Se dovessi occuparmi anche di pianificazioni di lavoro non standard

posta Drew 02.02.2018 - 00:20
fonte

2 risposte

1

Bene che tu abbia letto sui modelli, ti aiuteranno in futuro sicuramente.

Pochi commenti alla tua soluzione.

1) Usa il metodo statico piuttosto che il costruttore. Non dovresti avere nessuno stato all'interno della tua fabbrica, quindi non hai bisogno di molte istanze.

2) Restituisci l'implementazione concreta da te in fabbrica sulla base di parametri dall'input

Dovresti quindi essere in grado di fare qualcosa di simile

IBusinessDateTime businessDateTime = BusinessDateTimeFactory.getInstance(... params)
businessDateTime.calculate(params for calculation);

Perché lo vuoi? Perché ora tutti gli utenti del sistema non devono preoccuparsi dell'implementazione degli algoritmi. Ogni volta che ti rendi conto che vuoi cambiarlo devi solo cambiare il metodo di fabbrica, non i suoi consumatori (che si basano sul contratto di interfaccia).

3) Ma supponiamo che tu voglia lasciare che altri programmatori calcolino le date sulla loro strada. Puoi lasciare che aggiungano un'altra condizione al tuo metodo di fabbrica. Ma a volte una soluzione migliore e più sicura è quella di lasciare passare l'algoritmo. Specifica l'interfaccia dell'algoritmo e la aggiungi al tuo metodo. All'interno del metodo ci si basa su metodi di interfaccia. L'implementazione concreta sarà approvata dal consumatore del tuo metodo.

    
risposta data 02.02.2018 - 10:22
fonte
0

Ho esaminato la strategia e gli schemi di fabbrica grazie al commento di @ kadiii e ho deciso di implementare una strategia / ibrido di fabbrica, che è essenzialmente l'opzione 2 nella mia domanda. Sulla base di ciò che ho letto sui due schemi di progettazione, tradizionalmente entrambi si affidano a qualsiasi codice applicativo li stia utilizzando per determinare quale implementazione viene utilizzata. Non voglio attribuire questo onere ovunque venga utilizzata questa classe di servizio, quindi la lascio a BusinessDateTime per farlo.

La classe "factory", BusinessDateTime , ha un campo privato:

private IBusinessDateTime implementation;

Nel costruttore, ho impostato questo campo in base al tipo di pianificazione del lavoro:

public BusinessDateTime(WorkSchedule schedule, moreParams...)
{    
    if (schedule.StandardWorkSchedule)
    {
        this.implementation = new StandardBusinessDateTime();
    }
    else
    {
        this.implementation = new NonStandardBusinessDateTime();
    }
    // more initialization
}

E poi per ciascuno dei miei metodi di interfaccia in BusinessDateTime , faccio solo

public DateTime SomeBusinessDateCalculation()
{
    return this.implementation.SomeBusinessDateCalculation();
}

Ci sono un paio di singhiozzi da capire, come passare i dati avanti e indietro tra BusinessDateTime e le classi di implementazione, ma penso che questa sia una buona soluzione.

    
risposta data 02.02.2018 - 03:17
fonte

Leggi altre domande sui tag