When we start our programming life, our code is very short, but sooner or later there comes a time when we realise it has become too long. This is the time when we need to make a decision how are we going to split our code in to smaller objects. And there are three ways of doing that:
With inheritance
With composition
With mixins
Inheritance:
I'll make an example about life. One common thing all living things have is that they reproduce. So we'll make life our superclass. All living things inherit that property of life. So if we make a class Animal, we can have it inherit all the methods life has. All we need to do is tell the computer that Animal class is less than Life class (Animal < Life
) when we declare it.
class Life
def reproduction
puts "Let's make more of us"
end
end
class Plant < Life
def photosynthesis
puts "Let's use some carbon dioxide"
end
end
class Animal < Life
def move
puts "Let's go somewhere"
end
end
plant_object = Plant.new
plant_object.reproduction
plant_object.photosynthesis
animal_object = Animal.new
animal_object.reproduction
animal_object.move
And our output is:
And so it works. It's that simple.
Downside of inheritance is that subclasses get all the methods from superclass, and so do all the subclasses of subclass and so on. This can cause massive headaches when applications are big.
So what we can do is, we can get only method we need from a separate class and put it in our own.
Composition:
When we use composition we create an instance of another class within our own class to get the method we want. In this case we can control what methods we get from other class, and we can get them from more than one, not like with inheritance where we can only pick one superclass and then we get everything with it, including the rubbish we don't need. So let's see how it's done.
class Life
def reproduction
puts "Let's make more of us"
end
end
class Plant
def seed
life_object = Life.new
life_object.reproduction
end
def photosynthesis
puts "Let's use some carbon dioxide"
end
end
class Animal
def mate
life_object = Life.new
life_object.reproduction
end
def move
puts "Let's go somewhere"
end
end
plant_object = Plant.new
plant_object.seed
plant_object.photosynthesis
animal_object = Animal.new
animal_object.mate
animal_object.move
And we get the same result. Notice that we created a new method in Animal class called 'mate', so this is what we are then calling, and it is than the mate
method that in turn calls the method reproduction
.
This is very useful if we only need a small piece of other class, like one method that we could use in ours.
But if we want more than one method and we want to apply it to multiple classes we can use something called modules.
Mixins:
Modules are just like classes but different. I'm not going to go deep into differences between the two, but what's important for us to know now is that we can't make an instance of a module. What we do with them is to include them in our classes, with the magic word, yes you guessed it include
. If we do that, then all of the methods in the module are available in the class. Like here in our example, reproduction is available in Plant class because we said include Life
.
module Life
def reproduction
puts "Let's make more of us"
end
end
class Plant
include Life
def photosynthesis
puts "Let's use some carbon dioxide"
end
end
class Animal
include Life
def move
puts "Let's go somewhere"
end
end
plant_object = Plant.new
plant_object.reproduction
plant_object.photosynthesis
animal_object = Animal.new
animal_object.reproduction
animal_object.move
If we were to add another method in module Life, like for example has_cells
, than all of the classes were we included Life, would have gained the method. Imagine you need to create a class Cat
. You could simply include the module in it and that would be it. The best thing about mixins is that you can include as many modules as you want, even though it's not the best idea to have countless modules added, but anyway, you can do it. Compared to inheritance, where you're limited to one class to inherit from, this gives you more options.
On the bottom line, mixins seem to be the way of choice in ruby world, and inheritance seems to be quite the opposite, but like everything else in the world, it all comes down to personal opinion. Use whatever suits you, but be aware of the what your choice gives and takes.