Вопрос

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

Ruby, как язык без типов, не допускает классических полиморфных функций на основе типов, как это делает C ++.В качестве обходного маневра коллега часто прибегал к коду такого рода:

  def initialize starting_value
    if starting_post.kindof? Foo
      @starting_id = get_id_from_foo starting_value
    elsif starting_post.kindof? Bar
      @starting_id = get_id_from_bar starting_value
    else
      raise "illegal type"
    end
  end

Распространение этого кода по нашей кодовой базе (а не только по инициализаторам) приводит к тому, что я бы назвал "беспорядочным полиморфизмом".Это часто срабатывает, но иногда создает очень запутанные ситуации.

У меня есть три вопроса по этому поводу.

  • Есть ли официальное название для этого как анти-шаблон?"Беспорядочный интерфейс?", "Беспорядочный полиморфизм?" или что-то еще?
  • Насколько плохо, по мнению людей, это делать?
  • Существует ли систематический способ рефакторинга это?Проблема, с которой мы сталкиваемся при обычном рефакторинге многие тесты, которые мы создаем, используют это свободная типизация, и поэтому нам пришлось бы изменить оба тесты и реализации одновременно и, следовательно, не будет иметь эффекта каркаса обычного тестирования на основе рефакторинг.Я думаю, что на самом деле можно было бы "усилить" этот свободный полиморфизм, и абстрагировать код в функцию, а не сразу его удалять.Но будет ли это хорошей идеей?
Это было полезно?

Решение

Разве вы не можете определить какой-нибудь метод get_id, чтобы идентификатор возвращал сам себя, объект возвращал идентификатор, а имя делало все, что ему нужно для получения идентификатора?Тогда вы всегда можете канонизировать все, что, как вы знаете, будет одним из трех.Аналогично с методами get_name и get_object, если они необходимы.

То есть вы определили неявный интерфейс ThingWhatHasAnID и сделали его утиным типом параметра вашей функции.

Если я чего-то не упускаю, я бы назвал этот антишаблон "упущенной возможностью создать абстракцию".

Другие советы

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

def initialize starting_value
  @starting_id = starting_value.id
end

Определить id делать все, что угодно из различных get_id_from_* методы, используемые для этого.Случай незаконного типа уже будет поднят, потому что вы получите NoMethodError .

Что касается того, как это назвать, я бы назвал это "процедурным программированием на языке OO".

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top