I like using command objects as the ‘crux’ of my controllers. They encapsulate behavior without making models or controllers thick.
I think of commands as reactions to a signal (event). To produce a command I think first of the signal it is responding to. Let’s use an example:
class WidgetController < ApplicationController # We're assuming there's sufficient complexity in publishing # a widget to warrant a command. def update publish_command.execute(params[:widget]) if params[:publish] end private def publish_command Widget::PublishCommand.new(WidgetParamsParser.new) end end
The ‘signal’ that WidgetController emits is ‘Publish the widget’. It sends the only thing which is topical to this signal, the widget in question. This is a contextual dependency.
The command inverts control, passing it a parameter parser that knows how to deal with the representation used. This is a constructional dependency. In this particular case, I think it would be preferable to extract the builder for the PublishCommand because it’s no concern of the controller’s. Constructional dependencies have nothing to do with the signal.
I make the distinction between constructional and contextual dependencies so that I can communicate the intent of the command more clearly. By default I place constructional dependencies in the initialize method, or I define getter/setter dependencies, often with a clear default.
Another approach to construction injection defaults is highlighted here.
If we used some kind of orthogonal dependency injection framework, we could define a container that configures the common constructional dependencies for us. But that’s a topic of another post :D
For completeness, here’s a stub of Widget::PublishCommand
module Widget class PublishCommand def initialize(representation_parser) @representation_parser = representation_parser end def execute(widget_representation) normalized_widget = @representation_parser.parse(widget_representation) # complex stuff with widgets here end end
About the AuthorMore Content by Rasheed Abdul-Aziz