Question

Excuses à l'avance pour une question de longue haleine. Les commentaires particulièrement appréciés ici. . .

Dans mon travail, nous faisons beaucoup de choses avec des gammes de dates (date périodes, si vous voulez). Nous devons prendre toutes sortes de mesures, comparer le chevauchement entre deux périodes de date, etc. J'ai conçu une interface, une classe de base et plusieurs classes dérivées qui répondent bien à mes besoins:

  • Idateperiod
  • Dateyperiod
  • Mois du calendrier
  • Calendarweek
  • Exercice fiscal

Dépouillé à ses éléments essentiels, la superclasse Dateperiod est la suivante (omet toutes les fonctionnalités fascinantes qui sont la base des raisons pour lesquelles nous avons besoin de cet ensemble de classes ...):

(Java pseudocode):

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 de base contient un tas de méthodes et de propriétés plutôt spécialisées pour manipuler la classe de date de date. Les classes dérivées changent seulement La manière dont les points de début et de fin de la période en question sont fixés. Par exemple, il est logique pour moi qu'un objet Calendarmonth en effet "est-a" dateperiod. Cependant, pour des raisons évidentes, un mois civil est de durée fixe et a des dates de début et de fin spécifiques. En fait, alors que le constructeur de la classe Calendarmonth correspond à celui de la superclasse (en ce qu'il a un paramètre startDate et Enddate), il s'agit en fait d'une surcharge d'un constructeur simplifié, qui ne nécessite qu'un seul objet calendrier.

Dans le cas de Calendarmonth, fournissant n'importe quel La date se traduira par une instance Calendarmonth qui commence le premier jour du mois en question, et se termine sur le dernière jour de ce même mois.

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).
    {
}

Excuses pour le long préambule. Compte tenu de la situation ci-dessus, il semblerait que cette structure de classe viole le principe de substitution de Liskov. Bien que l'on puisse utiliser une instance de Calendarmonth dans tous les cas où l'on peut utiliser la classe DatePeriod plus générale, le comportement de sortie des méthodes clés sera différent. En d'autres termes, il faut savoir que l'on utilise une instance de Calendarmonth dans une situation donnée.

Alors que Calendarmonth (ou Calendarweek, etc.) adhèrent au contrat établi par l'utilisation de la classe de base de la période d'iDate, les résultats pourraient devenir horriblement biaisés dans une situation dans laquelle le calendrier a été utilisé et le comportement de la vieille date de la durée. . . (Notez que toutes les autres méthodes funky définies sur la classe de base fonctionnent correctement - ce n'est que le réglage des dates de début et de fin qui diffèrent dans l'implémentation de Calendarmonth).

Existe-t-il une meilleure façon de structurer cela de telle sorte que l'adhésion appropriée à la LSP pourrait être maintenue, sans compromettre l'utilisabilité et / ou le code duplicité?

Pas de solution correcte

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top