Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

interfacelike design pattern in ruby

I am asking for help regarding a design pattern. I am very used to interfaces in java, and I dont know how to get a similar mechanism in ruby. What it need is kind of interface which has a method e.g. contacts. In order to get contacts I need to make a call against an api, this could be google, linkedid or whatever webservice. So I d like to use an interface which provides me the contacts method and i dont want to know anything about the provider beyond.

My first attempt looks like this (pseudo code):

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

But I am really not sure, if this is the "ruby way to go".

Help, suggestions and recommendations are welcome. Best, Phil

like image 558
dc10 Avatar asked Jan 21 '13 08:01

dc10


2 Answers

Strategy pattern could be applied here

class 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
like image 119
Hoa Avatar answered Oct 05 '22 22:10

Hoa


I really like @Bui The Hoa's answer, but I'll add the following:

I like this approach a lot, especially the raising of the error in the base Provider class. However I don't think having the case statement in the Impl is good Strategy pattern use. It violates the single purpose principle as it makes the implementation responsible for keeping track of all possible provider. It also violates the open-close principle of classes being open to extension but not to change, because when you add a new providers you'd have to change the case statement.

Why not just do

impl = Impl.new(Google.new)

Since the raise "Unknown provider" error would be taken care of this way:

impl = Impl.new(BadProvider.new) => Error
like image 37
pixelearth Avatar answered Oct 05 '22 23:10

pixelearth