红宝石中的界面式设计模式

问题描述 投票:8回答:4

我正在寻求有关设计模式的帮助。我非常习惯java中的接口,我不知道如何在ruby中获得类似的机制。它需要的是一种具有例如方法的接口。联系人。为了获得联系我需要打电话给api,这可能是google,linkedid或任何web服务。所以我想使用一个界面,它为我提供了联系方式,我不想知道任何关于提供者的信息。

我的第一次尝试看起来像这样(伪代码):

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

但我真的不确定,如果这是“红宝石的方式”。

欢迎提供帮助,建议和建议。最好,菲尔

ruby design-patterns
4个回答
6
投票

战略模式可以在这里应用

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

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方法是Impl实例的工厂方法,它添加了给定模块的方法。只需确保模块实现相同的方法名称并返回兼容的值。


2
投票

模块通常用于排除多个对象的常见行为。我相信在这种情况下你需要的只是鸭子打字。只需在Java解决方案中共享接口的所有类中实现方法contacts

请注意,此解决方案允许您将不同类型的对象保存在单个集合中,当您迭代它们时(或者您希望使用这些公共接口对象的任何其他方式),您只需调用此contacts方法,而不是关心他们到底是什么类型的。

如果在实现此接口的所有类中需要一些常见行为,则可以创建基于contacts方法存在的模块,并将其包含在可以使用它的所有类中。


2
投票

我非常喜欢@Bui The Hoa的答案,但我会添加以下内容:

我非常喜欢这种方法,特别是在基类Provider类中引发错误。但是我不认为在Impl中使用case语句是好的策略模式使用。它违反了单一目的原则,因为它使实施负责跟踪所有可能的提供者。它还违反了开放式扩展但不改变的类的开放式原则,因为当你添加新的提供者时,你必须改变case语句。

为什么不这样做呢

impl = Impl.new(Google.new)

由于引发“未知提供者”错误将以这种方式处理:

impl = Impl.new(BadProvider.new) => Error
© www.soinside.com 2019 - 2024. All rights reserved.