![](/i/fill.gif) |
![](/i/fill.gif) |
|
![](/i/fill.gif) |
|
![](/i/fill.gif) |
| ![](/i/fill.gif) |
| ![](/i/fill.gif) |
|
![](/i/fill.gif) |
|
![](/i/fill.gif) |
| ![](/i/fill.gif) |
| ![](/i/fill.gif) |
|
![](/i/fill.gif) |
I have noticed that whenever I wind up using the Factory pattern, I wind up
with a listing of all the classes somewhere in a central place, namely the
factory method that instantiates the appropriate class. It seems to me this
kind of defeats the entire purpose of the method.
I would suggest a language feature to overcome this.
A class can be marked "factory" and if it has no parent classes that are
marked factory, then it is abstract, but one is allowed to invoke "new" on
the class.
If "new XYZ(alpha, beta)" is invoked and XYZ is a factory class, then all
other (loaded) classes marked "factory" with a parent of "XYZ" are
inspected. They are inspected in a breadth-first manner (with individual
nodes at the same level being invoked in an undefined order), except that
the most-derived classes are invoked before the less-derived classes. I.e.,
breadth-first, but starting from the leaves. Each compatible constructor is
invoked, and the first one that doesn't throw an exception is the one used.
If all throw an exception, then the original "new" statement throws an
exception.
Potential problems: Getting the order right. The overhead of throwing
exceptions (would be better if they could return a null, for example).
Defining how this might work for languages without metadata. Figuring out
the right semantics if one of the child classes is in a dynamically-loaded
library that's not currently in a state in which its elements can be invoked
(i.e., not loaded from disk yet, uninitialized, etc). Do we have to allocate
enough memory for the biggest child class to be filled in? Do we reallocate
memory each time we try a child?
Benefits: You can extend an abstract class without needing to have a static
factory method. There would be no need for a central list of subclasses of a
particular class (which is what dynamic dispatch was supposed to avoid in
the first place).
Thoughts?
--
Darren New, San Diego CA, USA (PST)
Linux: Now bringing the quality and usability of
open source desktop apps to your personal electronics.
Post a reply to this message
|
![](/i/fill.gif) |
| ![](/i/fill.gif) |
| ![](/i/fill.gif) |
|
![](/i/fill.gif) |
|
![](/i/fill.gif) |
| ![](/i/fill.gif) |
| ![](/i/fill.gif) |
|
![](/i/fill.gif) |
On Sun, 25 Apr 2010 23:53:50 +0200, Darren New <dne### [at] san rr com> wrote:
> I have noticed that whenever I wind up using the Factory pattern, I wind
> up with a listing of all the classes somewhere in a central place,
> namely the factory method that instantiates the appropriate class. It
> seems to me this kind of defeats the entire purpose of the method.
Decentralization is not the purpose of the Factory pattern. Still, it is
sometimes useful to decouple even the factory from knowledge about the
specific concrete classes, especially if there are many of them.
> Thoughts?
Another way is to make the factory store a dictionary of construction
methods/functors/prototypes, and register classes/objects into the factory
from elsewhere. This also lets you add new classes/objects to the factory
at runtime. In C++, the registration part can be set up to happen
automatically with minimal effort; I am not sure about other languages.
In languages with reflection, you could have the factory look up a class
name, check if the class belongs to the right hierarchy for that factory,
and then simply call a static factory method (or just the default
constructor) defined in that class.
--
FE
Post a reply to this message
|
![](/i/fill.gif) |
| ![](/i/fill.gif) |
| ![](/i/fill.gif) |
|
![](/i/fill.gif) |
|
![](/i/fill.gif) |
| ![](/i/fill.gif) |
| ![](/i/fill.gif) |
|
![](/i/fill.gif) |
Fredrik Eriksson wrote:
> Decentralization is not the purpose of the Factory pattern.
Uh, sure it is, in the same sense that inheritance is decentralization. What
do *you* think it's for? Maybe it's good for something else too.
> Still, it is
> sometimes useful to decouple even the factory from knowledge about the
> specific concrete classes, especially if there are many of them.
Right.
>> Thoughts?
>
> Another way is to make the factory store a dictionary of construction
> methods/functors/prototypes, and register classes/objects into the
> factory from elsewhere. This also lets you add new classes/objects to
> the factory at runtime. In C++, the registration part can be set up to
> happen automatically with minimal effort; I am not sure about other
> languages.
>
> In languages with reflection, you could have the factory look up a class
> name, check if the class belongs to the right hierarchy for that
> factory, and then simply call a static factory method (or just the
> default constructor) defined in that class.
Ah, now you're talking about implementations in current languages. I was
talking about a language feature for future languages that would basically
automate this whole process. Working with a language where it isn't built
in, thinking about the ways I've used it and seen it used, and trying to
come up with a way to eliminate the "registration" aspect and basically make
it seamless, in the same way that exceptions and OO are seamless in C++ but
you have to do them manually in C.
Plus, that's no longer "New". It's a separate method that returns a pointer.
I.e., you're still calling a factory method instead of just instantiating a
class and having it automatically instantiate the right subclass.
Of course, in some languages like Smalltalk (and Python, I think?) "new" is
just a method that returns a reference, and that reference doesn't have to
be the same class you invoked "new" on, so in that sense much of the hard
work is done. The base class would just implement "look up the right
subclass" process in its constructor and do the factory work there.
Altho, I suppose with MI (so you can inherit the "Factory" methods anywhere)
and static library initialization (so you can invoke those implicitly to do
registration when the class gets loaded) you could come very close to doing
this with nothing but a library.
--
Darren New, San Diego CA, USA (PST)
Linux: Now bringing the quality and usability of
open source desktop apps to your personal electronics.
Post a reply to this message
|
![](/i/fill.gif) |
| ![](/i/fill.gif) |
| ![](/i/fill.gif) |
|
![](/i/fill.gif) |
|
![](/i/fill.gif) |
| ![](/i/fill.gif) |
| ![](/i/fill.gif) |
|
![](/i/fill.gif) |
On Mon, 26 Apr 2010 19:10:18 +0200, Darren New <dne### [at] san rr com> wrote:
> Fredrik Eriksson wrote:
>> Decentralization is not the purpose of the Factory pattern.
>
> Uh, sure it is, in the same sense that inheritance is decentralization.
> What do *you* think it's for? Maybe it's good for something else too.
Perhaps a poor choice of words on my part. I would say that the Factory
pattern is about decoupling/abstraction, but I suppose you could call that
decentralization.
My point was that the issue of having to lump information about all the
concrete classes together in one place is orthogonal; the Factory pattern
is not intended to decentralize that part, even if you *can* sometimes do
it.
> Altho, I suppose with MI (so you can inherit the "Factory" methods
> anywhere) and static library initialization (so you can invoke those
> implicitly to do registration when the class gets loaded) you could come
> very close to doing this with nothing but a library.
MI is not necessary -- nor even helpful -- for this.
--
FE
Post a reply to this message
|
![](/i/fill.gif) |
| ![](/i/fill.gif) |
| ![](/i/fill.gif) |
|
![](/i/fill.gif) |
|
![](/i/fill.gif) |
| ![](/i/fill.gif) |
| ![](/i/fill.gif) |
|
![](/i/fill.gif) |
Fredrik Eriksson wrote:
> On Mon, 26 Apr 2010 19:10:18 +0200, Darren New <dne### [at] san rr com> wrote:
>> Fredrik Eriksson wrote:
>>> Decentralization is not the purpose of the Factory pattern.
>>
>> Uh, sure it is, in the same sense that inheritance is
>> decentralization. What do *you* think it's for? Maybe it's good for
>> something else too.
>
> Perhaps a poor choice of words on my part. I would say that the Factory
> pattern is about decoupling/abstraction, but I suppose you could call
> that decentralization.
Yeah. My thought was that the factory pattern is there to support the basic
idea of multiple implementations of the same concept. You have a class
called "data connection", and depending on the parsing of the URL you pass
at instantiation, you either get back a subclass that's "http connect" or
"ftp connection" or "https connection" or whatever.
Decentralizing which of those subclasses is chosen is something that's not
automated in any language I know of. Decentralizing the method dispatch to
the appropriate methods of the subclass once instantiated *is* automated.
> My point was that the issue of having to lump information about all the
> concrete classes together in one place is orthogonal; the Factory
> pattern is not intended to decentralize that part, even if you *can*
> sometimes do it.
Right. And that's just my point. I'm saying "the factory pattern could be
made more useful if there were explicit language support for it", just like
dyanmic dispatch or Singleton pattern is more useful when there's explicit
language support.
>> Altho, I suppose with MI (so you can inherit the "Factory" methods
>> anywhere) and static library initialization (so you can invoke those
>> implicitly to do registration when the class gets loaded) you could
>> come very close to doing this with nothing but a library.
>
> MI is not necessary -- nor even helpful -- for this.
My thought was that you could have a "Factory" mix-in that during
initialization would register itself with the appropriate subclass, and then
the "Factory" base class would invoke the routine it knew was in each
factory subclass because it knows it's in the factory mix-in. I.e., you
could automate it much better by having a lump of routines and data that
with a simple declaration get incorporated into your class without you
having to worry about it. Then all you'd have to do is (for example) parse
the URL and see if the scheme is one you handle, rather than writing the
same code to register yourself in the superclass' list of classes to try, etc.
You could do the same thing at runtime with a sufficiently powerful
reflection library, I suppose, but that would seem to be overhead that you
could cure at either compile time or load time (if you wanted to dynamically
load new libraries for new schemas as necessary).
Remember, subroutines are a design pattern. Stacks are a design pattern. OOP
is a design pattern. Exceptions are a design pattern. It's all design
patterns until your language builds it in.
--
Darren New, San Diego CA, USA (PST)
Linux: Now bringing the quality and usability of
open source desktop apps to your personal electronics.
Post a reply to this message
|
![](/i/fill.gif) |
| ![](/i/fill.gif) |
| ![](/i/fill.gif) |
|
![](/i/fill.gif) |
|
![](/i/fill.gif) |
| ![](/i/fill.gif) |
|
![](/i/fill.gif) |