Заранее извиняюсь за многословный вопрос.Обратная связь особенно ценится здесь.,.
В моей работе мы много чего делаем с диапазонами дат (дата периоды , если хотите).Нам нужно проводить все виды измерений, сравнивать перекрытия между двумя периодами дат и т. Д. Я разработал Интерфейс, базовый класс и несколько производных классов, которые хорошо соответствуют моим потребностям на сегодняшний день:
- IDatePeriod
- DatePeriod
- CalendarMonth
- CalendarWeek
- FiscalYear
В сущности суперкласс DatePeriod выглядит следующим образом (опускаетсявсе интересные функции, которые являются основой для того, почему нам нужен этот набор классов ...):
(псевдокод 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
}
Базовый класс содержит набор довольно специализированныхметоды и свойства для манипулирования классом периода даты.Производные классы изменяют только способ установки начальной и конечной точек рассматриваемого периода.Например, для меня имеет смысл, что объект CalendarMonth действительно "is-a" DatePeriod.Однако по понятным причинам календарный месяц имеет фиксированную продолжительность и имеет определенные даты начала и окончания.Фактически, хотя конструктор для класса CalendarMonth совпадает с конструктором суперкласса (в том смысле, что он имеет параметры startDate и endDate), на самом деле это перегрузка упрощенного конструктора, для которого требуется только один объект Calendar.
В случае CalendarMonth предоставление любой даты приведет к созданию экземпляра CalendarMonth, который начинается в первый день рассматриваемого месяца и заканчивается last день того же месяца.
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).
{
}
Извинения за длинную преамбулу.Учитывая ситуацию выше, казалось бы, эта классовая структура нарушает принцип подстановки Лискова.В то время как один МОЖЕТ использовать экземпляр CalendarMonth в любом случае, в котором можно использовать более общий класс DatePeriod, поведение вывода ключевых методов будет другим.Другими словами, нужно знать, что в данной ситуации используется экземпляр CalendarMonth.
Хотя CalendarMonth (или CalendarWeek и т. Д.) Придерживаются контракта, установленного с помощью использования базового класса IDatePeriod, результаты могут стать ужасно искаженными в ситуации, когда использовался CalendarMonth и поведение простого старого DatePeriodожидалось .,,(Обратите внимание, что ВСЕ другие фанки-методы, определенные в базовом классе, работают правильно - это только установка даты начала и окончания, которая отличается в реализации CalendarMonth).
Есть ли лучший способ структурировать это такоеможно ли обеспечить надлежащее соблюдение LSP без ущерба для удобства использования и / или дублирования кода?