From: Joel VanderWerf Date: 2004-11-14T17:21:35+09:00 Subject: Re: [ANN] Copland to Needle article on RubyGarden (LONG) 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. Should the Printer class be designed to think about managing collections of printers? I'm trying to wean myself off of practices like that ;) > Incidentally, because the class itself IS the service, service models > are actually rather inconsequential. Ignoring that fact, however, you > could do the following and the Printer class would have no knowledge of > which model was being used for it: > > reg.define do |b| > b.printers1( :model => :prototype ) { Printer } > b.printers2( :model => :threaded ) { Printer } > b.printers3( :model => :singleton_deferred_initialize ) { Printer } > ... > end That's true, you don't have to use Printer.get. Printer.new is still the same as it always was, and so all of the existing service models will work normally with Printer. But if you're using Printer.new and Printer.get(kind) in the same container, then there are two (or more) service models of Printer operating together, and you can't guarantee that at most one printer of each kind exists. It's not really a multiton pattern any more. (That may be perfectly ok in some cases--this Printer example is really too vague to tell.) 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 :)