В Построении объектно-ориентированного программного обеспечения Мейера (1988) он определяет принцип открытия / закрытия следующим образом:
- Модуль будет считаться открытым, если он все еще доступен для расширения. Например, должна быть возможность добавить поля к структурам данных, которые он содержит, или новые элементы к набору функций, которые он выполняет.
- Модуль считается закрытым, если он доступен для использования другими модулями. Это предполагает, что модуль получил четкое, стабильное описание (интерфейс в смысле скрытия информации).
Он продолжает говорить:
Если вы снова откроете модуль, вы также должны снова открыть все его клиенты, чтобы обновить их, так как они полагаются на старую версию. … [Эта проблема] возникает каждый раз, когда модуль должен быть расширен новой функцией или элементом данных, вызывая изменения в прямых и косвенных клиентах. ... При классических подходах к проектированию и программированию нет возможности писать модули, которые бы были как открытыми, так и закрытыми.
Решение этой проблемы Мейера состоит в следующем: никогда не расширять библиотечный модуль, изменяя существующие классы; вместо этого напишите новый модуль, который подклассирует существующие классы, и у которых новые клиенты зависят от этого нового модуля.
Теперь, в 1988 году, я писал игрушечные (процедурные) программы на Turbo Pascal и Blankenship Basic, и мой профессиональный опыт 21-го века связан с JVM, CLR и динамическими языками, поэтому я не знаю, что имел в виду Мейер. по "классическим подходам к дизайну и программированию".
Один конкретный пример Мейера о том, почему клиентские модули должны быть открыты вновь (оператор switch для перечисления, в котором теперь больше членов, требующих большего числа случаев), кажется достаточно разумным, но он почти не оправдывает утверждение, что каждый раз, когда вы добавляете функциональность в библиотеку Модуль, вам необходимо обновить все его клиенты .
Есть ли историческая причина, по которой это утверждение казалось самоочевидным в 1988 году? Скажем, добавление функций или структур данных в статическую библиотеку C изменило макет так, что даже с обратно совместимыми API-интерфейсами клиенты должны были перекомпилироваться? Или Мейер действительно просто говорит о механизме обеспечения обратной совместимости API?
Ответы:
Насколько я могу судить, на этот вопрос ответил сам Бертран Мейер, и ответ таков: это утверждение не является точным. С классическими подходами к проектированию и программированию действительно может быть способ написания модулей, которые являются открытыми и закрытыми.
Чтобы это выяснить, вам нужно изучить второе издание этой книги (опубликованное девять лет спустя, в 1997 году). Согласно предисловию ко второму изданию , это
В частности, заявление, которое вас смущает, ушло. Там по- прежнему является принцип Открыт-Закрыт глава «§3.3 Пять принципов», и дополнительно подробное обсуждение этой темы в «§ 14.7 Введение в Inheritance» , но заявление от первого издания не существует больше.
Вместо этого основное внимание уделяется тому, как это более удобно и идиоматично в ОО-подходе по сравнению с предыдущими способами.
Поскольку вы также, кажется, задаетесь вопросом о том, что здесь имел в виду «классические подходы» Мейера, вы можете найти объяснение их в §4.7. Традиционные модульные структуры . В этом разделе объясняется, что они означают «библиотеки процедур» и «пакеты» (для последнего автор говорит, что термин взят из Ada и упоминает другие языки, имеющие эту функцию - кластеры в CLU и модули в Modula).
Если вы думаете об этом, ни один из этих подходов изначально не был предназначен для помощи в написании кода, который придерживается принципа открытого-закрытого типа. Это может привести автора к их несколько преждевременной оценке, которая позже была исправлена во втором издании.
Что касается того, что конкретно заставило автора изменить свое мнение об этом утверждении между первым и вторым изданием, я думаю, что можно найти ответ, опять же, в самой книге, а именно в части F: Применение метода в различных языках и средах » . В этой главе автор обсуждает, как объектно-ориентированные методы могут использоваться в старых языках:
В частности, в этой части Мейер подробно объясняет, как можно было бы реализовать наследование (с некоторыми оговорками и ограничениями, но все же) в C и даже в Fortran.
Видите ли, это действительно требует пересмотра этого утверждения из первого издания. Кажется практически невозможным объяснить, как примириться «с классическими подходами ... нет пути» с реалистичными примерами того, как именно это можно сделать.
источник