From: Pat Maddox Date: 2006-12-03T20:02:04+09:00 Subject: Re: Factory pattern, abstract base class On 12/3/06, Robert Dober wrote: > On 12/3/06, James Edward Gray II wrote: > > > > On Dec 2, 2006, at 5:15 PM, Daniel Berger wrote: > > > > > Perhaps my whole approach is wrong. What is the proper way to achieve > > > what I'm after (without resorting to making Bar a module)? > > > > This works, but is probably poor style: > > > Which would follow from one of the basic rules of OOP, if memory serves: > A Class does not know anything about its subclasses, be it abstract or not. > OP I suggest that you rethink your design, AFAIK that would not be very > flexible concerning new subclasses right? Of course every rule has exceptions. For example, in Beck's Test-Driven Development, after a bit of refactoring you end up with something like (converted to Ruby :) class Money class << self def dollar(amount) Dollar.new amount end def franc(amount) Franc.new amount end end end The reasoning behind this is that since the clients only go through Money, you can change the underlying inheritance structure without breaking anything. Indeed, he goes on to get rid of the Dollar and Franc classes entirely, and the factory methods turn into: def dollar(amount) new amount, "USD" end In the case of the Money class, client code shouldn't have a dependency on Dollar or Franc classes. Adding a factory method onto the Money class simplifies client code and promotes refactoring. It's impossible to tell if OP's situation would be a good use for this kind of thing, given the lack of explanation and the nondescriptive names :) I would prefer to have explicit factory methods though, instead of a single new method that can return an instance of any number of classes. As far as it not being flexible with subclasses, a little bit of metaprogramming clears that up: class Bar def self.factory_methods(*names) names.each do |n| (class << self; self; end).instance_eval do define_method(n) { Kernel.const_get(n.to_s.capitalize).send(:new) } end end end end class Bar factory_methods :baz, :zap end Gives you Bar.baz and Bar.zap which return a new Baz and Zap instance, respectively. Hell you could even use the inherited callback to do it automatically: class Bar def self.inherited(subclass) (class << self; self; end).instance_eval do define_method(subclass.to_s.downcase) { subclass.new } end end end Then when you do class Baz < Bar; end you automatically get Bar.baz I'll be honest, I really just saw this whole thing as an opportunity to do some fun meta-foo :) Use at your own risk. Pat