On Tue, 26 Jul 2005, Joe Van Dyk wrote: > On 7/25/05, Ara.T.Howard <Ara.T.Howard / noaa.gov> wrote: >> On Tue, 26 Jul 2005, Lyndon Samson wrote: >> >>> Factory is a very common pattern in the java world, in some places >>> it's almost considered 'Evil (TM)' to have any sort of knowledge of >>> object construction. >>> >>> In the Ruby world, where Classes and Objects seem to be de-emphasised, >>> constructing an object with .new doesn't seem to be held as such a bad >>> thing. >>> >>> I know there are a few IOC containers in the RubyWorld, but they dont >>> seem to be overly popular. >>> >>> Why might this be so? >> >> probably because 'new' is a method and really doesn't give any clue as to how >> an object is contructed - this is how i generally implement factory >> >> class Factory >> class TypeA; end >> class TypeB; end >> class TypeC; end >> >> def Factory::new(arg, *a, &b) >> klass = >> case arg >> when /a/ >> TypeA >> when /b/ >> TypeB >> when /b/ >> TypeC >> end >> klass::new(*a, &b) >> end >> end >> >> although the returned type might depend on file extension or something else. >> since 'new' is just a method on a class object it's always free to return >> anything it likes. the nice thing about this is that, in ruby, __every__ call >> to new is, by definition, the factory pattern - it just so happens that there >> is a default implementation inherited by class 'Class'. simplicity. > > > Would you mind giving an example of how you'd use that class? How > does it benefit the programmer? well, __that__ class isn't useful to anyone ;-) but if you have something like this perhaps class JobRunner class AbstractJobRunner def initialize job @job = job @logger = Logger::new end def run @job.run 'logger' => @logger end def download_input src, dst raise NotImplementedError end def upload_output src, dst raise NotImplementedError end end class FTPJobRunner < AbstractJobRunner def download_input src, dst ... end def upload_output src, dst ... end end class HTTPJobRunner < AbstractJobRunner def download_input src, dst ... end def upload_output src, dst ... end end class SCPJobRunner < AbstractJobRunner def download_input src, dst ... end def upload_output src, dst ... end end class << self def new job klass = case job.input when %r|^ftp://| FTPJobRunner when %r|^scp://| SCPJobRunner when %r|^http://| HTTPJobRunner end klass::new job end end end class Job def initialize command, input, output ... end end then all over your code just reads job_runner = JobRunner::new job job_runner.run and you don't really care what kind of JobRunner it is... if this stuff were in a library, and more kinds of JobRunners are later added, client code need not change. of course there are about a million ways to do this in ruby, but an object factory is nice wherever your code needs an object that does 'x' based on 'y' - you can encapsulate that logic and, later, change it only in one place with a factory. the built-in uri class does something similar: jib:~/eg/ruby > irb -r uri irb(main):001:0> URI::parse 'http://foobar' => #<URI::HTTP:0x..fdba9cc00 URL:http://foobar> irb(main):002:0> URI::parse 'ftp://foobar' => #<URI::FTP:0x..fdba9bc06 URL:ftp://foobar> irb(main):003:0> URI::parse 'scp://foobar' => #<URI::Generic:0x..fdba9ac16 URL:scp://foobar> of course it's using 'parse' instead of 'new' - but the idea is the same. you just want a url-type object, but you don't really care what kind of object it is so long as it supports some set of methods you'll be using later - nice with duck typing ;-) hth. -a -- =============================================================================== | email :: ara [dot] t [dot] howard [at] noaa [dot] gov | phone :: 303.497.6469 | My religion is very simple. My religion is kindness. | --Tenzin Gyatso ===============================================================================