From: Robert Klemme Date: 2005-04-12T16:14:38+09:00 Subject: Re: Factory design "David A. Black" schrieb im Newsbeitrag news:Pine.LNX.4.61.0504111508240.7304@wobblini... > Hi -- > > On Tue, 12 Apr 2005, Claus Spitzer wrote: > > > Greetings! > > A friend of mine has recently started using Ruby, and has run into a > > little problem. He is trying to create different objects depending on > > the contents of a string. His intuition is to use factory design for > > this, and he'd like to know if there is a Ruby Way to do this. > > > > Below is his original e-mail. > > Regards... > > -CWS > > > > ----8<---- > > > > In any case, I have an identifier on my log file that looks like "2005-01-04 > > 23:34:12 begin_phase". If I see this, I want to create a "Phase" object. If > > it says "2005-01-04 23:52:16 begin_interruption", then I want to create an > > interruption instead. > > > > My intuition is that this is a typical Factory Design Pattern, so I would > > create a Ruby class method that creates the appropriate type based on the > > results of the string and returns it. However, someone familiar with Ruby > > told me that Ruby's dynamic typing and duck typing is such that this kind of > > solution "feels incorrect". > > > > Does anyone have suggestions as to what I can do? Thanks! > > I wouldn't worry about the matter of duck typing here. The concept of > duck typing, as I understand it, is essentially an explanatory tool > for getting people to understand, visualize, and make use of the fact > that class and type are not the same as each other in Ruby (a fact > that can be summed up very quickly but that in fact has huge > ramifications). Duck typing doesn't mean you never instantiate > objects of a particular class, nor that you never parse a string :-) > > For this project, I don't think any (webbed) toes will be stepped on > if you do something like: > > require 'scanf' > > File.open("input.dat") do |fh| > fh.scanf("%d-%d-%d %d:%d:%d begin_%s") do |y,mo,d,h,mi,s,klass| > c = Object.const_get(klass.capitalize).new > # etc. > end > end > > (to illustrate with a simple line-by-line treatment). If one needs more flexibility (for example because several tags should create instances of the same class or whatever) then a hash in between serves well: FACTORIES = { "phase" => Phase, "interruption" => Interruption, # ... } if /begin_(\w+)/ =~ line obj = FACTORIES[$1].new end Or, even more flexible FACTORIES = { "phase" => lambda {|line| Phase.new line}, "interruption" => lambda {|*| Interruption.new}, # ... } if /begin_(\w+)/ =~ line obj = FACTORIES[$1].call line end Kind regards robert