Межфазная схема дизайна в рубине

Я прошу помощи в отношении шаблона проектирования. Я очень привык к интерфейсам в java, и я не знаю, как получить аналогичный механизм в ruby. Для этого нужен вид интерфейса, который имеет способ, например. контакты. Чтобы получить контакты, мне нужно сделать вызов против api, это может быть google, linkedid или любой веб-сервис. Поэтому я хотел бы использовать интерфейс, который предоставляет мне метод контактов, и я не хочу ничего знать о провайдере.

Моя первая попытка выглядит так (псевдокод):

Module AbstractContact
 def contacts
 #do some stuff with @data
 @data
 end
end
class Impl
 include AbstractContact
 def build_provider(provider)
 if provider == :google
 #get the data from google
 gdata= api_call
 @data = gdata
 elsif provider == :linkedin
 end
 end
end
c=Impl.new
c.build_provider
c.contacts

Но я действительно не уверен, если это "рубиновый путь".

Помощь, предложения и рекомендации приветствуются. Лучший, Фил

4 ответа

Есть несколько хороших подходов к этому. Один из них заключается в инкапсуляции различных функций в модули:

module Google
 def contacts
 puts 'contacts from Google'
 end
end
module LinkedIn
 def contacts
 puts 'contacts from LinkedIn'
 end
end
class Impl
 def self.create provider
 o = new
 o.extend(provider)
 end
end
Impl.create(Google).contacts
Impl.create(LinkedIn).contacts

Вывод:

contacts from Google
contacts from LinkedIn

Здесь метод create на Impl - это метод factory для экземпляров Impl, который добавляет в методы из данного модуля. Просто убедитесь, что модули реализуют те же имена методов и возвращают совместимые значения.


Здесь можно применить шаблон стратегии.

def Provider
 def contacts
 raise "Abstract method called"
 end
end
class Google < Provider
 def contacts
 data = # Google API call
 end
end
class LinkedIn < Provider
 def contacts
 data = # LinkedIn API call
 end
end
class Impl
 def initialize(provider)
 case provider
 when :google
 @provider = Google.new
 when :linkedin
 @provider = LinkedIn.new
 else
 raise "Unknown provider"
 end
 end
 def contacts
 @provider.contacts
 end
end
impl = Impl.new(provider)
impl.contacts


Модули обычно используются для исключения общего поведения нескольких объектов. Я считаю, что все, что вам нужно в этом случае, это утка. Просто реализуйте метод contacts во всех классах, которые будут использовать интерфейс в решении Java.

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

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


Мне очень нравится @Bui The Hoa answer, но я добавлю следующее:

Мне очень нравится этот подход, особенно повышение ошибки в базовом классе Provider. Тем не менее, я не думаю, что применение case в Impl является хорошим вариантом использования стратегии. Он нарушает принцип единой цели, поскольку он заставляет реализацию отвечать за отслеживание всех возможных поставщиков. Это также нарушает принцип открытого-закрытого класса, открытый для расширения, но не изменяющийся, потому что, когда вы добавляете новых поставщиков, вам придется изменить оператор case.

Почему бы просто не сделать

impl = Impl.new(Google.new)

Так как ошибка рейза "Неизвестный поставщик" будет решена таким образом:

impl = Impl.new(BadProvider.new) => Error

licensed under cc by-sa 3.0 with attribution.