Refactoring: Extract Mixin
I think I might have a previously uncatalogued refactoring here. This is an alpha version. If at least a few people find it useful, I'll do a proper writeup. Here goes:
This refactoring is applicable with languages that support mixins, like Ruby.
class Human << Mammal
def walk()
...
end
end
class Penguin << Bird
def walk()
...
end
end
By factoring out the walk() method into a mixin, we can eliminate the code duplication:
module Biped
def walk()
...
end
end
class Human << Mammal
include Biped
end
class Penguin << Bird
include Biped
end
You have two classes or mixins with similar features.
Create a mixin module, and move the common features to the mixin.
This refactoring is applicable with languages that support mixins, like Ruby.
Motivation
The primary purpose of Extract Mixin is to eliminate code duplication. In this respect, this refactoring is very similar to Extract Superclass. There are some noteworthy differences:- Mixins are not a part of the inheritance hierarchy. Thus, it is possible to mix any number of mixins into a class, or into other mixins. Consequently, mixins are more flexible than class hierarchies.
- Mixins can create instance variables, but this introduces the risk of naming conflicts. Therefore, this refactoring is safest with methods that get all their variables as parameters to the method call.
Mechanics
- Run the test suite to ensure that everything works as it should.
- Create a new file containing an empty mixin module.
- Include the mixin in the original class (or original mixin).
- Run the tests
- Move methods, one by one, to the mixin module. Run the tests after each move.
- Examine the methods left in the class(es). If there are common parts, use Extract Method to extract those parts into separate methods, then move the methods to the mixin. Run the test suite to verify that everything works.
Example
The following two classes both have a walk() method, but they are in different inheritance hierarchies:class Human << Mammal
def walk()
...
end
end
class Penguin << Bird
def walk()
...
end
end
By factoring out the walk() method into a mixin, we can eliminate the code duplication:
module Biped
def walk()
...
end
end
class Human << Mammal
include Biped
end
class Penguin << Bird
include Biped
end
Comments
I'll do a writeup of the corollary to Extract Mixin, i.e. Replace Mixin With Class, in a few days. I should have done it earlier, but I developed a sudden fanatic interest in process simulation, and haven't been able to think about anything else for a couple of weeks.
on, but forgot to put a link to it in the page template.
Thanks for pointing it out.