Pregunta

Disculpas de antemano por una pregunta larga. Comentarios especialmente apreciados aquí. . .

En mi trabajo, hacemos muchas cosas con rangos de citas (fecha períodos, Si tu quieres). Necesitamos tomar todo tipo de medidas, comparar superposición entre dos períodos de fecha, etc. He diseñado una interfaz, una clase base y varias clases derivadas que satisfacen mis necesidades hasta la fecha:

  • Idateperíodo
  • Periodía
  • Mes calendario
  • Calendario de la semana
  • Año fiscal

Despletado de sus elementos esenciales, la superclase DatePeriod es la siguiente (omite todas las características fascinantes que son la base de por qué necesitamos este conjunto de clases ...)::

(Pseudocódigo 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 clase base contiene un montón de métodos y propiedades bastante especializados para manipular la clase de período de fecha. Las clases derivadas cambian solamente La forma en que se establecen los puntos de inicio y finalización del período en cuestión. Por ejemplo, tiene sentido para mí que un objeto Calendarmonth de hecho "es" Dateperiod. Sin embargo, por razones obvias, un mes calendario es de duración fija y tiene fechas de inicio y finalización específicas. De hecho, si bien el constructor para la clase Calendarmonth coincide con la de la superclase (en el sentido de que tiene un parámetro de fecha inicial y de fecha final), de hecho, esta es una sobrecarga de un constructor simplificado, que requiere solo un objeto calendario.

En el caso de Calendarmonth, proporcionando ningún La fecha dará como resultado una instancia de calendarmonth que comience el primer día del mes en cuestión y termina en el ultimo día de ese mismo mes.

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

Disculpas por el largo preámbulo. Dada la situación anterior, parece que esta estructura de clase viola el principio de sustitución de Liskov. Si bien uno puede usar una instancia de CalendarMonth en cualquier caso en el que se pueda usar la clase DatePeriod más general, el comportamiento de salida de los métodos clave será diferente. En otras palabras, uno debe ser consciente de que uno está usando una instancia de calendarmonth en una situación dada.

Mientras que el calendarmonth (o calendarweek, etc.) se adhiere al contrato establecido a través del uso de IdatePeriod de la clase base, los resultados podrían volverse terriblemente sesgados en una situación en la que se usó el calendarmonth y se esperaba el comportamiento de un período de fecha antiguo. . . (Tenga en cuenta que todos los otros métodos funky definidos en la clase base funcionan correctamente: es solo la configuración de fechas de inicio y finalización que difieren en la implementación de calendarmonth).

¿Existe una mejor manera de estructurar esto de tal manera que se pueda mantener una adherencia adecuada para LSP, sin comprometer la usabilidad y/o el código de duplicación?

No hay solución correcta

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top