From: Pat Maddox Date: 2007-11-18T07:08:26+09:00 Subject: Re: Composition: Build objects from other objects On Nov 16, 2007 9:36 PM, Raul Parolari wrote: > Thufir wrote: > > > > then can you make the vw_bug go "vroooooom" and so forth? What would be > > the usual way to do this in ruby? When a car is instantiated, should an > > engine object get passed to the initializer method? > > > > thanks, > > > > Thufir > > I do not like (at first view) the idea of this design; it leads to, as > Konrad has correctly observed, to start the car by saying: > > vw_bug.engine.vroom() > > Should the car user know that he has to tell the car to ask the engine > to rev up? Uhm.. > > Another take is the following; let's use a module Engine: > > module Engine > attr_accessor :type > > def initialize > @type = "generic engine" > end > > def vroom > puts "vroooooom" > end > end > > class Vehicle > include Engine > > def initialize > super > end > end > > class Car < Vehicle > def initialize > super > end > end > > vw_bug = Car.new > vw_bug.vroom > > I am not crazy of the 'Engine' Module, but I definitely like to ask the > VW to wroom, without worrying about what is inside, > > Raul > > -- > Posted via http://www.ruby-forum.com/. > > I think this is a pretty bad approach. Consider the following example (keep in mind I know nothing about cars): module Engine attr_reader :engine def initialize @engine = :generic end def vroom puts "vrooooooom" end end module Transmission attr_reader :transmission def initialize @transmission = :silky_smooth end def vroom puts "smooth like butta" end end class Car include Engine include Transmission def initialize super end end By "composing" it with modules like that, we end up with a seriously broken car - one with no engine! Clearly this approach won't work. Part of it is due to how you set stuff up in initialize...but anyway, the point is that you don't really use modules for this kind of composition. A far better approach would be to have different engine and transmission objects. class Engine def vroom "vrooooooom" end end class Transmission def vroom "smooth like butta" end end class Car def initialize(engine, transmission) @engine = engine @transmission = transmission end def vroom "we go #{@engine.vroom}, #{@transmission.vroom}" end end c = Car.new Engine.new, Transmission.new c.vroom # => "we go vrooooooom, smooth like butta" if you want to create a car with its parts already initialized, you can create a factory method: def Car.basic self.new Engine.new, Transmission.new end The basic idea is that you don't really want to make the car object responsible for a bunch of stuff...you want a bunch of little objects that know how to do one thing well. Pat