On Sat, 20 Aug 2005, Andrew S. Townley wrote:

> Hello everyone,
>
> Trying to get my head around some of the subtleties of Ruby.  I've done
> quite a bit of C/C++/Java and some Python programming, and the normal
> way that I'd solve this problem (in pseudo-Java) would be:
>
> interface SomeFeature
> {
> 	void execute();
> }
>
> public class FeatureFactory
> {
> 	private static class FeatureImpl implements SomeFeature
> 	{
> 		public FeatureImpl(String initParam1,
> 				String initParam2)
> 		{
> 		...
> 		}
>
> 		public void execute() { ... }
> 	}
>
> 	public SomeFeature createFeature()
> 	{
> 		return new FeatureImpl("param1", "param2");
> 	}
> }
>
> I've seen some of the previous threads on the list (starting from here:
> http://blade.nagaokaut.ac.jp/cgi-bin/scat.rb/ruby/ruby-talk/60616), but
> I don't see anything immediately obvious as to how to encapsulate the
> creation of my concrete implementations of a common interface (even with
> duck typing, there's an implied interface).
>
> The main issue here is that I want to prevent the client code from
> instantiating their own objects.  The objects should be created only by
> a factory of some sort (who has implementation-specific configuration
> information about how to bootstrap them).
>
> It would appear that if you have 'require'd the appropriate files (or
> can), you can create any instances you want.  Is there a way to
> accomplish what I'm trying to do beyond saying "don't do that" in the
> documentation?
>
> Any assistance would be appreciated.
>
> Thanks in advance,

     harp:~ > cat a.rb
     module Factory
       @classes = {
         'a' => (
             Class::new do
               class << self
                 def foo; 42; end
               end
               def bar; 42.0; end
             end
         ),
         'b' => (
             Class::new do
               class << self
                 def foo; 'FORTY-TWO'; end
               end
               def bar; 'forty-two'; end
             end
         ),
       }
       def self::new(*a, &b)
         class_for(a.shift)::new(*a, &b)
       end
       def self::class_for typename
         @classes[typename]
       end
     end

     a_obj = Factory::new 'a'
     b_obj = Factory::new 'b'

     a_class = Factory::class_for 'a'
     b_class = Factory::class_for 'b'

     p a_obj.bar
     p b_obj.bar

     p a_class::foo
     p b_class::foo



     harp:~ > ruby a.rb
     42.0
     "forty-two"
     42
     "FORTY-TWO"


obviously you would want 'class_for' to be private - but this illustrates the
general idea.

hth.

-a
-- 
===============================================================================
| email :: ara [dot] t [dot] howard [at] noaa [dot] gov
| phone :: 303.497.6469
| Your life dwells amoung the causes of death
| Like a lamp standing in a strong breeze.  --Nagarjuna
===============================================================================