When I read more about Ruby metaprogramming, most of the time we found at least two solutions to solve a problem. Please look at two examples below:
class Base
def self.has_many(*args)
# ...
end
end
class Student < Base
has_many :books
end
Another style:
module Base
def self.included(klass)
klass.extend ClassMethods
end
module ClassMethods
def has_many(*args)
# ...
end
end
end
class Student
include Base
has_many :books
end
But when we design api, we have to decide which one to use, but I would like to ask your ideas and some of best practices that most people have already implemented in their libraries.
If your API is providing the base functionality which will be extended by the client, then you should prefer inheritance.
If your API is going to extend various clients with their own base functionality, then you should go for composition.
You've got a lot of theories around that question.
I tend to prefer composition because it makes behavior a lot more reusable that way but if you look at Rails, you'll have to subclass ActiveRecord::Base class every time you want to an object in your database. If you look at DataMapper, it's the opposite as they just required you to include DataMapper::Resource.
Inheritance vs Composition (via modules) is a big topic and the question you'll have to ask yourself will come down to: how can I achieve the greater decoupling between the components I provide and another user existing code base?
Ruby supports single inheritance only. Therefore if API client must inherit your base class, they lose the ability to inherit other classes. Using module inclusion you make possible a code like:
class Student < Person
include Base
has_many :books
end
And thus you can "inherit" both Person and Base.
However, classical inheritance syntax looks more natural and less "magic"
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With