From: Jamis Buck Date: 2004-11-15T01:57:46+09:00 Subject: Re: [ANN] Copland to Needle article on RubyGarden (LONG) Joel VanderWerf wrote: > Jamis Buck wrote: > >> Joel VanderWerf wrote: > > ... > >>>> However, you could also create a service factory. It would do just >>>> as you did, with a Hash for caching created instances. >>>> >>>> class Printer >>>> def self.get( name ) >>>> @printers ||= Hash.new >>>> @printers[ name ] ||= new( name ) >>>> end >>>> >>>> private_class_method :new >>>> def initialize( name ) >>>> ... >>>> end >>>> end >>>> >>>> reg.define.printers { Printer } >>>> >>>> p1 = reg.printers.get( :monochrome ) >>>> p2 = reg.printers.get( :monochrome ) >>>> assert_same p1, p2 >>> >>> >>> >>> >>> This feels like it breaks encapsulation: the Printer class shouldn't >>> know about the service model that the container is using for it. In >>> this case, the service model may be an unavoidable consequence of how >>> the Printer class works, and so it should be enforced by the class >>> itself. >> >> >> >> The Printer class doesn't know about its service model. Am I >> misunderstanding you? What in the code given above causes you to think >> that the service model is known to the Printer class itself? > > > The Printer.get implementation is what I would call a service model: it > defines a protocol where a request for a key returns a Printer unique to > that key. But I've only been using the phrase "service model" for, oh, > about 10 hours. True. The nature of a factory is such that it will be the arbiter of how its products are obtained. Thus, in that since, the factory enforces a lifecycle model for the services it returns. > > Should the Printer class be designed to think about managing collections > of printers? I'm trying to wean myself off of practices like that ;) Well, I may have muddied the waters by having the Printer class be the factory class as well. Ruby works well for things like that--I prefer to think of it as "the factory is designed to think about managing collections of its products." It's a very powerful design pattern, not at all conflicting with dependency injection. Done right, the two patterns can be very complimentary. I believe what you are asking for (and what I'm still looking for a nice solution to) is a way for Needle itself to become the factory for these kinds of services. Right now, the most elegant solution I've found is to create lambda services that return curried functions, which when invoked return the desired services. The drawback is that the curried functions are outside of the control of Needle's service models, so you have to further wrap those services in other services... > Anyway, having this logic manually coded within an application class > (whether in the service or in the container) is too much like my rewrite > of Jim's original example. It seems to me that logic should be embedded > in the DI framework, as a model option. Eventually :) Eventually, indeed. :) Please, dig into Needle's internals and see if you can find a way to implement this. I'll do the same. With enough eyes and brains working on this puzzle, an acceptible solution is sure to emerge. - Jamis -- Jamis Buck jgb3@email.byu.edu http://www.jamisbuck.org/jamis