2009-04-03 3 views
4

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

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 

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

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

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

Это приложение Rails? –

ответ

7

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

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

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

4

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

def initialize starting_value 
    @starting_id = starting_value.id 
end 

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

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