Как избежать скрытия потомком
Прежде чем понять, когда и почему необходимо скрытие потомком, следует заметить, что чаще всего этого делать не стоит. Эта техника должна находиться в резерве главного командования. Когда есть полный контроль над структурой наследования на ранних этапах разработки системы, то предусловия дают лучший способ справиться с таксономией исключений.
Рассмотрим класс ELLIPSE. Эллипс имеет два фокуса, через которые можно провести прямую:
Рис. 6.9. Эллипс и фокусная линия
Класс ELLIPSE может соответственно иметь компонент focus_line.
Естественно, определить класс CIRCLE как наследника ELLIPSE: каждая окружность является эллипсом. Но для окружности два фокуса сливаются в одну точку - центр окружности, так что фокусная линия исчезает. (Вероятно, более корректно говорить о бесконечном множестве фокусных линий, любая прямая, проходящая через центр, может рассматриваться как фокусная линия, но на практике эффект будет тот же.)
Рис. 6.10. Круг и его центр
Хороший ли это пример для скрытия потомком? Должен ли класс CIRCLE сделать компонент focus_line закрытым, как здесь:
class CIRCLE inherit ELLIPSE export {NONE} focus_line end ...Вероятно, нет. В данном случае у разработчика родительского класса была вся необходимая информация для понимания того, что не все эллипсы имеют фокусную линию. Для компонентов, представляющих подпрограмму, следует ввести предусловие:
focus_line is -- Линия, проходящая через два фокуса require not equal (focus_1, focus_2) do ... end(Предусловие может быть абстрактным, использующим функцию distinct_focuses; с тем преимуществом, что класс CIRCLE может сам переопределить ее.)
Необходимость поддержки эллипсов без фокусной линии вытекает из анализа проблемы. Создать соответствующий класс с функцией focus_line, не имеющей предусловия, является ошибкой проекта. Переложить решение на скрытие потомком является попыткой скрытия ошибки. Как указывалось в конце обсуждения принципа Открыт-Закрыт, ошибочные решения должны фиксироваться, потомки не должны латать прорехи проекта.