Flip
Flip

Reputation: 6761

Ruby: How to refactor very similar classes?

I've got a bunch of classes that are very similar to each other. The only difference is in a part of the class name, some pathes, and other classes that call, that belong in the same group.

So for example I have a XDispatcher which uses a XImporter, and a YDispatcher which uses a YImporter, where the Dispatchers and Importers are identical save for the names and any fragment using the name, such as pathes, calls to other classes of that grouping.

class XDispatcher
  def initialize
    path = Rails.root.join('x_dispatcher/files')
  end

  def run
    # do stuff
    # importer = XImporter.new()
  end
end

class YDispatcher
  def initialize
    path = Rails.root.join('y_dispatcher/files')
  end

  def run
    # do stuff
    importer = YImporter.new()
  end
end

EDIT: Shame on me..I totally blended out inheritance and extension. In order to keep this question interesting, I would like to see some fancy stuff or experimental ways to solve this 'problem'.

Upvotes: 0

Views: 139

Answers (3)

eiko
eiko

Reputation: 5345

If the only difference is a name, you shouldn't even bother with inheritance. Just initialize your Dispatcher with a name and then pass it where you need it:

class Dispatcher
  def initialize name
    @name = name
    path = Rails.root.join("#{@name}_dispatcher/files")
  end

  def run
    # do stuff
    # importer = Importer.new(@name)
  end
end

Dispatcher.new("x").run
Dispatcher.new("y").run

Upvotes: 3

ReggieB
ReggieB

Reputation: 8212

I'd suggest:

class Dispatcher
  class << self
     attr_accessor :file_path, importer_class
  end

  def path 
    @path ||= Rails.root.join(self.class.file_path)
  end

  def importer
    @importer ||= self.class.importer_class.new
  end

  def run
    # do stuff
  end
end

class XDispatcher < Dispatcher
  file_path = 'x_dispatcher/files'
  importer_class = XImporter
end

class YDispatcher < Dispatcher
  file_path = 'y_dispatcher/files'
  importer_class = YImporter
end

Two main reasons:

  1. It removes the reliance on constants - and particularly the issue of them not being present in the parent class - or if they are, them being overwritten in the child class
  2. It removes the reliance on the initialize method needing to have to do more than load initial data - which in my opinion is bad practice

Upvotes: 1

Lukas Baliak
Lukas Baliak

Reputation: 2869

Maybe you can do something like this.

class Dispatcher
  def initialize
    path = Rails.root.join(self.class::RAILS_ROOT_PATH)
  end

  def run
    # do stuff
    importer = self.class::IMPORTER_CLASS.new
    # process
  end
end

class XDispatcher < Dispatcher
  RAILS_ROOT_PATH = 'x_dispatcher/files'
  IMPORTER_CLASS = XImporter
end

class YDispatcher < Dispatcher
  RAILS_ROOT_PATH = 'y_dispatcher/files'
  IMPORTER_CLASS = YImporter
end

Upvotes: 2

Related Questions