In my most recent article, I mentioned a great new feature in Rails 5.1, delegate_missing_to
. With delegate_missing_to
, any method that you can’t find on one object is called on another object, instead:
But, like Gavin mentioned in the comments, this seems like an odd way to avoid inheritance. Why not just use a subclass? You’d get the same effect, and you don’t have to add a whole new feature. It seems like a weird thing to add.
There must be a reason delegate_missing_to
was added, though. And for Rails features, pull requests are a great way to find those reasons. In this pull request, DHH mentioned why he suggested the feature:
Here’s a common pattern if you want to build a decorator:
That seems like a pretty good place to start digging.
Why decorators?
When you build a decorator, you’re changing the way an object acts, without creating a new subclass. For example, in the code from earlier:
You’d say that “Player decorates user,” because a Player almost acts like a User, but has an extra method, points
. And it does this without inheritance.
Why would you need something like this? That’s a tough question to answer, because like many design patterns, it’s not always clear where you’d want to use it instead of something else.
When would you use a decorator?
Decorators could just be a more complicated way to do inheritance. I mean, which of these two lines of code is better?
Clearly the second one, right? Here, creating Player as a decorator instead of a subclass is just a waste of code.
But sometimes, you want to add functionality to an object later on, far away from where you created the object. For example, what if you had code like this?
Now, you can create the user however you want, in whatever method you want. The code that creates the User object doesn’t know or care that a Player class even exists. And you can still use the original User object if you don’t want those extra methods anymore.
This helps you separate behavior into different classes. Each class can focus on how the User object would be used in a specific situation – a Player, an Employee, a Developer. With inheritance, it’s easy for all this stuff to get jumbled together.
MrChris mentioned another benefit to decorators in the comments:
When you decorate an object, you can only call the public methods on that object. When you subclass, you can call any method, even private ones. That can make subclasses break more frequently, because they can accidentally rely on their parents’ implementation details. Those details will usually change more often than the public methods.
Decorators can be especially useful when you’re breaking apart large classes. With decorators, it’s easier to follow the Single-Responsibility Principle – each decorator can do one thing and do it well, and you can combine decorators to get more complex behavior.
There are a lot of ways to share behavior in Ruby. You can subclass, you can combine modules, you can even grab methods off one class and attach them to another if you want to. The decorator pattern, though, gives you something a little different. You’re just using instance variables and method calls, the building blocks of any object-oriented language. From those fundamentals, you can have flexible behavior while your app is running – all without overcomplicating your code.