------art_10748_12732931.1165158172401
Content-Type: text/plain; charset=ISO-8859-1; format=flowed
Content-Transfer-Encoding: 7bit
Content-Disposition: inline

On 12/3/06, Pat Maddox <pergesu / gmail.com> wrote:
>
> On 12/3/06, Robert Dober <robert.dober / gmail.com> wrote:
> > On 12/3/06, James Edward Gray II <james / grayproductions.net> 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.


Hmm I think your mail has shown a flaw in my reasoning, thanks :)
My point was that this basic rule explains why James had to come up with
some clumsy (his opinion) code ;) - and that seems wrong.
Let us imagine, for the sake of argument, that the Rule where not there and
that base classes should now about there subclasses (but not there
implementation details, maybe that is where I was just wrong, now thinking
about it??? SmallTalk seems to implement knowledge about subclasses in the
superclass)

Than one could write
class Factory
      class << self
              subclasses.each do
                      |subclass|
                      define_method subclass.downcase.to_sym { subclass.new}
             end
     end
end

now I think this might not at all have to do with OO design, but with
Retrospection, which might or might not be considered harmful, but is not a
contradiction to the OOP paradigm.
So James' code is complicated because Ruby's introspection does not know
about subclasses, or does it BTW?


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


or you could just store the information about the new subclass in a Bar
class instance variable for  potential use, that excellent example of your's
mad it clear for me that we were talking Introspection and not OOP.

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.


Sometimes code is the best reasoning! But it might be a good approach to
think about in that kind of context to use #inherited to enhance the
metadata available. Nice.

Pat
>
>
Cheers
Robert
-- 
"The real romance is out ahead and yet to come. The computer revolution
hasn't started yet. Don't be misled by the enormous flow of money into bad
defacto standards for unsophisticated buyers using poor adaptations of
incomplete ideas."

- Alan Kay

------art_10748_12732931.1165158172401--