Domanda

Mi scuso in anticipo per la domanda prolissa.Feedback particolarmente apprezzato qui...

Nel mio lavoro, facciamo molte cose con intervalli di date (date periodi, se vorrai).Dobbiamo effettuare misurazioni di ogni tipo, confrontare la sovrapposizione tra due periodi di date, ecc.Ho progettato un'interfaccia, una classe base e diverse classi derivate che finora soddisfano bene le mie esigenze:

  • IDatePeriod
  • DataPeriodo
  • Calendario mensile
  • Settimana del calendario
  • Anno fiscale

Ridotta all'essenziale, la superclasse DatePeriod è la seguente (omette tutte le caratteristiche affascinanti che sono alla base del motivo per cui abbiamo bisogno di questo insieme di classi...):

(Pseudocodice Java):

class datePeriod implements IDatePeriod

protected Calendar periodStartDate
protected Calendar periodEndDate

    public DatePeriod(Calendar startDate, Calendar endDate) throws DatePeriodPrecedenceException
    {
        periodStartDate = startDate
        . . . 
        // Code to ensure that the endDate cannot be set to a date which 
        // precedes the start date (throws exception)
        . . . 
        periodEndDate = endDate
    {

    public void setStartDate(Calendar startDate)
    {
        periodStartDate = startDate
        . . . 
        // Code to ensure that the current endDate does not 
        // precede the new start date (it resets the end date
        // if this is the case)
        . . . 
    {


    public void setEndDate(Calendar endDate) throws datePeriodPrecedenceException
    {
        periodEndDate = EndDate
        . . . 
        // Code to ensure that the new endDate does not 
        // precede the current start date (throws exception)
        . . . 
    {


// a bunch of other specialty methods used to manipulate and compare instances of DateTime

}

La classe base contiene una serie di metodi e proprietà piuttosto specializzati per manipolare la classe del periodo di date.Le classi derivate cambiano soltanto il modo in cui sono fissati i punti di inizio e di fine del periodo in questione.Ad esempio, per me ha senso che un oggetto CalendarMonth effettivamente "sia" DatePeriod.Tuttavia, per ovvi motivi, un mese di calendario ha una durata fissa e ha date di inizio e di fine specifiche.Infatti, mentre il costruttore della classe CalendarMonth corrisponde a quello della superclasse (in quanto ha un parametro startDate e endDate), questo è in realtà un sovraccarico di un costruttore semplificato, che richiede solo un singolo oggetto Calendar.

Nel caso di CalendarMonth, fornendo Qualunque date risulterà in un'istanza di CalendarMonth che inizia il primo giorno del mese in questione e termina il scorso giorno di quello stesso mese.

public class CalendarMonth extends DatePeriod

    public CalendarMonth(Calendar dateInMonth)
    {
        // call to method which initializes the object with a periodStartDate
        // on the first day of the month represented by the dateInMonth param,
        // and a periodEndDate on the last day of the same month.
    }

    // For compatibility with client code which might use the signature
    // defined on the super class:
    public CalendarMonth(Calendar startDate, Calendar endDate)
    {
        this(startDate)
        // The end date param is ignored. 
    }

    public void setStartDate(Calendar startDate)
    {
        periodStartDate = startDate
        . . . 
    // call to method which resets the periodStartDate
    // to the first day of the month represented by the startDate param,
    // and the periodEndDate to the last day of the same month.
        . . . 
    {


    public void setEndDate(Calendar endDate) throws datePeriodPrecedenceException
    {
        // This stub is here for compatibility with the superClass, but
        // contains either no code, or throws an exception (not sure which is best).
    {
}

Mi scuso per il lungo preambolo.Considerata la situazione di cui sopra, sembrerebbe che questa struttura di classe violi il principio di sostituzione di Liskov.Anche se è possibile utilizzare un'istanza di CalendarMonth in ogni caso in cui si potrebbe utilizzare la classe DatePeriod più generale, il comportamento di output dei metodi chiave sarà diverso.In altre parole, bisogna essere consapevoli che si sta utilizzando un'istanza di CalendarMonth in una determinata situazione.

Mentre CalendarMonth (o CalendarWeek, ecc.) aderiscono al contratto stabilito attraverso l'uso della classe base di IDatePeriod, i risultati potrebbero diventare orribilmente distorti in una situazione in cui è stato utilizzato CalendarMonth e ci si aspettava il comportamento del vecchio DatePeriod...(Nota che TUTTI gli altri metodi originali definiti nella classe base funzionano correttamente: è solo l'impostazione delle date di inizio e fine che differisce nell'implementazione di CalendarMonth).

Esiste un modo migliore per strutturarlo in modo tale da mantenere la corretta aderenza all'LSP, senza compromettere l'usabilità e/o la duplicazione del codice?

Nessuna soluzione corretta

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top