Соответствует ли образец в Scala принципу Открытого / Закрытого?

Если я добавляю новый класс case, означает ли это, что мне нужно выполнить поиск по всему коду сопоставления с образцом и выяснить, где должен обрабатываться новый класс? Недавно я изучал язык, и когда я читал о некоторых аргументах за и против сопоставления с образцом, я не понял, где его следует использовать. Смотрите следующее:

Pro: Одерский1 и Одерский2

Con: Beust

Комментарии довольно хороши и в каждом случае. Так что шаблон соответствует чему-то, что должно вызывать энтузиазм или что-то, чего я должен избегать? На самом деле, я думаю, что ответ "это зависит от того, когда вы его используете", но каковы некоторые положительные варианты использования для этого и какие есть отрицательные?

3 ответа

Решение

Джефф, я думаю, у тебя правильная интуиция: это зависит.

Объектно-ориентированные иерархии классов с диспетчеризацией виртуальных методов хороши, когда у вас есть относительно фиксированный набор методов, которые необходимо реализовать, но много потенциальных подклассов, которые могут наследоваться от корня иерархии и реализовывать эти методы. В такой установке относительно легко добавить новые подклассы (просто реализовать все методы), но относительно сложно добавить новые методы (необходимо изменить все подклассы, чтобы убедиться, что они правильно реализуют новый метод).

Типы данных с функциональностью, основанной на сопоставлении с образцом, хороши, когда у вас есть относительно фиксированный набор классов, которые принадлежат к типу данных, но многие потенциальные функции работают с этим типом данных. В такой конфигурации относительно легко добавить новые функциональные возможности для типа данных (просто сопоставление с шаблоном во всех его классах), но относительно сложно добавить новые классы, которые являются частью типа данных (необходимо изменить все функции, которые соответствуют на тип данных, чтобы убедиться, что они правильно поддерживают новый класс).

Каноническим примером ОО-подхода является программирование GUI. Элементы GUI должны поддерживать очень небольшую функциональность (рисовать себя на экране - минимум), но новые элементы GUI добавляются постоянно (кнопки, таблицы, диаграммы, ползунки и т. Д.). Каноническим примером подхода сопоставления с образцом является компилятор. Языки программирования обычно имеют относительно фиксированный синтаксис, поэтому элементы дерева синтаксиса изменяются редко (если вообще когда-либо), но постоянно добавляются новые операции над деревьями синтаксиса (более быстрая оптимизация, более тщательный анализ типов и т. Д.).

К счастью, Scala позволяет комбинировать оба подхода. Классы case могут быть сопоставлены с шаблоном и поддерживать диспетчеризацию виртуальных методов. Обычные классы поддерживают диспетчеризацию виртуальных методов и могут быть сопоставлены с шаблоном путем определения экстрактора в соответствующем сопутствующем объекте. Программист должен решить, когда каждый подход подходит, но я думаю, что оба полезны.

Хотя я уважаю Седрика, он совершенно не прав в этом вопросе. При желании сопоставление с образцом в Scala может быть полностью инкапсулировано из изменений класса. Хотя верно то, что изменение класса case потребовало бы изменения любых соответствующих экземпляров сопоставления с образцом, это только при использовании таких классов наивным способом.

Сопоставление с образцом в Scala всегда делегирует деконструктору объекта-компаньона класса. В случае класса case этот деконструктор генерируется автоматически (вместе с методом фабрики в объекте-компаньоне), хотя все еще возможно переопределить эту автоматически сгенерированную версию. Вы всегда можете установить полный контроль над процессом сопоставления с образцом, изолируя любые шаблоны от потенциальных изменений в самом классе. Таким образом, сопоставление с образцом - это просто еще один способ доступа к данным класса через безопасный фильтр инкапсуляции, как и любой другой метод.

Таким образом, мнению доктора Одерского следует доверять, особенно с учетом огромного объема исследований, которые он провел в области объектно-ориентированного программирования и проектирования.

Что касается того, где его следует использовать, то это полностью соответствует вкусу. Если это делает ваш код более кратким и понятным, используйте его! В противном случае нет. Для большинства объектно-ориентированных программ сопоставление с образцом не требуется. Однако, как только вы начнете интегрировать более функциональные идиомы (Option, Listи т. д.) Я думаю, вы обнаружите, что сопоставление с образцом значительно уменьшит синтаксические издержки, а также улучшит безопасность, предлагаемую системой типов. В общем, в любое время, когда вы хотите извлечь данные при одновременном тестировании некоторого условия (например, извлечение значения из Some), сопоставление с образцом, вероятно, будет полезным.

Сопоставление с образцом определенно хорошо, если вы занимаетесь функциональным программированием. В случае ОО, есть несколько случаев, когда это хорошо. В примере самого Седрика это зависит от того, как вы print() метод концептуально. Это поведение каждого Term объект? Или это что-то за пределами этого? Я бы сказал, что это снаружи, и имеет смысл сделать сопоставление с образцом. С другой стороны, если у вас есть Employee класс с различными подклассами, плохой выбор дизайна для сопоставления с образцом его атрибута (скажем, имени) в базовом классе.

Также сопоставление с образцом предлагает элегантный способ распаковки членов класса.

Другие вопросы по тегам