BorlandTalk.com Forum Index BorlandTalk.com
Borland discussion newsgroups
 
Archives   FAQFAQ   SearchSearch   MemberlistMemberlist   UsergroupsUsergroups   RegisterRegister 
 ProfileProfile   Log in to check your private messagesLog in to check your private messages   Log inLog in 

Painted myself into a (factory) corner

 
Post new topic   Reply to topic    BorlandTalk.com Forum Index -> Delphi OO design
View previous topic :: View next topic  
Author Message
marek jedlinski
Guest





PostPosted: Mon Nov 10, 2003 10:16 pm    Post subject: Painted myself into a (factory) corner Reply with quote



In a fairly simple application, several layers of indirection away from the
application.MainForm (where I used to perform all major tasks in my newbie
days Wink I have an object that validates the data collected by other objects
and uses a factory to instantiate a worker object to perform the actual
dirty work. The purpose of the whole operation is to insert a piece of
information into files in a formatted manner, and the worker object
(TInjector) is the one that performs the actual work on physical files.

The factory returns workers of two sibling classes: one handles plain text
files, the other handles HTML files (the parsing and formatting algorithms
are of course very different). So I pass an ID to the factory and receive
the type of worker object I need.

Problem: each of the two worker object types has a slightly different set
of properties. They have a few common properties, which I can set without
knowing the real class of the worker object. But they also have a string
property Template which looks the same on the outside, but requires
different values for text and HTML. Finally, the worker that deals with
HTML files has an additional property which must be set and which the
text-only worker does not have. So right now my code looks like this
(abbreviated):

// The factory returns a TTextInjector or a THTMLInjector
// depending on the FileTypeID parameter:
Injector := InjectorFactory.CreateInjector( FileTypeID );
Injector.DateFormat := FDateFormat; {common for all injectors}

// and then, the ugly part...
if ( Injector is TTextInjector ) then
Injector.Template := FTextTemplate
else
if (Injector is THTMLInjector) then
begin
{problem 1: same property, different value:}
Injector.Template := FHTMLBodyTemplate;

{problem 2: special property, only in THTMLInjector:}
(Injector as THTMLInjector).HeadTemplate := FHTMLHeadTemplate;
end;

I guess I tried to decouple things that don't want to be decoupled. What
can I do to avoid this typecasting? It's not so bad overall, because if I
were to add a third kind of injector, e.g. to handle XML files, this is
still the only place in the code which I'd have to change - but it
indicates a problem I'm sure to encounter in larger, more complex projects.

I have thought of callbacks, where the injector would trigger an event to
ask for a property value, but this would only move the typecasting to a
different place, or I'd have to have as many events as there are
combinations of injector types and their properties.

The injector could read its properties from a config object, but the object
would have to be global, and would have to hold all the config values that
get used by various objects along the way.

Incidentally, I've found a good summary of this problem at
http://www.industriallogic.com/papers/learning.html:

"Consider the MazeFactory example. The MazeFactory contains a method called
MakeRoom, which takes as a parameter one integer, representing a room
number. What happens if you would also like to specify the room's color &
size? Would this mean that you would need to create a new Factory Method
for your MazeFactory, allowing you to pass in room number, color and size
to a second MakeRoom method?

"Of course, nothing would prevent you from setting the color and size of
the Room object after is has been instantiated, but this could also clutter
your code, especially if you are creating and configuring many objects. How
could you retain the MazeFactory and keep only one MakeRoom method but also
accomodate different numbers of parameters used by MakeRoom to both create
and configure Room objects?"

And, of course, I don't have a good answer :)

..marek

--
No ads, no nags freeware: http://www.tranglos.com
(KeyNote, PhoneDeck, KookieJar, Oubliette)


Back to top
Joanna Carter (TeamB)
Guest





PostPosted: Mon Nov 10, 2003 10:39 pm    Post subject: Re: Painted myself into a (factory) corner Reply with quote



marek jedlinski wrote:

Quote:
I guess I tried to decouple things that don't want to be decoupled.
What can I do to avoid this typecasting? It's not so bad overall,
because if I were to add a third kind of injector, e.g. to handle XML
files, this is still the only place in the code which I'd have to
change - but it indicates a problem I'm sure to encounter in larger,
more complex projects.

Try setting the properties in the constructors of the two classes within the
factory. Or do you only know the values from outside of the factory?

Joanna

--
Joanna Carter (TeamB)

Consultant Software Engineer
TeamBUG support for UK-BUG
TeamMM support for ModelMaker



Back to top
marek jedlinski
Guest





PostPosted: Mon Nov 10, 2003 10:58 pm    Post subject: Re: Painted myself into a (factory) corner Reply with quote



On Mon, 10 Nov 2003 22:39:20 -0000, "Joanna Carter (TeamB)"
<joannac (AT) btinternetXX (DOT) com> wrote:

Quote:
Try setting the properties in the constructors of the two classes within the
factory. Or do you only know the values from outside of the factory?

The latter, yes. I would have to pass the properties to the factory method.
And worse, since the factory-created classes differ in the number of
properties, I'd either have to pass *all* the properties or have overloaded
factory methods.

Perhaps if the factory accessed a global config object that held all the
properties (they're configurable by the user, loaded from an ini file),
this would be a cleaner solution?

..marek





Back to top
Joanna Carter (TeamB)
Guest





PostPosted: Mon Nov 10, 2003 10:58 pm    Post subject: Re: Painted myself into a (factory) corner Reply with quote

marek jedlinski wrote:

Quote:
Perhaps if the factory accessed a global config object that held all
the properties (they're configurable by the user, loaded from an ini
file), this would be a cleaner solution?

Then surely the Factory should be aware of the configuration used to set up
its objects?

Joanna

--
Joanna Carter (TeamB)

Consultant Software Engineer
TeamBUG support for UK-BUG
TeamMM support for ModelMaker



Back to top
marek jedlinski
Guest





PostPosted: Mon Nov 10, 2003 11:22 pm    Post subject: Re: Painted myself into a (factory) corner Reply with quote

On Mon, 10 Nov 2003 22:58:58 -0000, "Joanna Carter (TeamB)"
<joannac (AT) btinternetXX (DOT) com> wrote:

Quote:
| Perhaps if the factory accessed a global config object that held all
| the properties (they're configurable by the user, loaded from an ini
| file), this would be a cleaner solution?

Then surely the Factory should be aware of the configuration used to set up
its objects?

I may not have a good understanding of the factory concept, then. It sounds
reasonable to say the factory should be aware of the configuration. But in
practice:

- the application reads its command line, which may specify some settings,
such as the location of the config file
- the application determines the location of the config file (current user?
all users? app's own folder? ini file or registry? etc). The application
also sets default values if no config data is present.
- the application loads the configuration. The configuration has a number
of settings which pertain to various behaviors at different levels. There
is a setting for "Pplace icon in system tray", and then there is a setting
that specifies the templates for text and HTML files.

(In reality, I have a generic TAppConfig class that handles all these
tasks, so that just by creating an instance I have the config fully set
up.)

Then, in a far and away unit somewhere, we have the factory which only
needs to know two or three of those settings, and shouldn't care where they
come from. So, what to do? Give the factory knowledge of the config object?
Or just give it the location of the config data, so that the factory can
load only the information it needs?


..marek



Back to top
Joanna Carter (TeamB)
Guest





PostPosted: Mon Nov 10, 2003 11:39 pm    Post subject: Re: Painted myself into a (factory) corner Reply with quote

marek jedlinski wrote:

Quote:
Then, in a far and away unit somewhere, we have the factory which only
needs to know two or three of those settings, and shouldn't care
where they come from. So, what to do? Give the factory knowledge of
the config object?

That would be my choice.

Joanna

--
Joanna Carter (TeamB)

Consultant Software Engineer
TeamBUG support for UK-BUG
TeamMM support for ModelMaker



Back to top
Bryan Crotaz
Guest





PostPosted: Tue Nov 11, 2003 12:32 pm    Post subject: Re: Painted myself into a (factory) corner Reply with quote

Or several small config objects owned by TGlobalConfig, and give each
factory the appropriate config object.

Bryan


"Joanna Carter (TeamB)" <joannac (AT) btinternetXX (DOT) com> wrote

Quote:
marek jedlinski wrote:

| Then, in a far and away unit somewhere, we have the factory which only
| needs to know two or three of those settings, and shouldn't care
| where they come from. So, what to do? Give the factory knowledge of
| the config object?

That would be my choice.

Joanna

--
Joanna Carter (TeamB)

Consultant Software Engineer
TeamBUG support for UK-BUG
TeamMM support for ModelMaker





Back to top
Zlatko Ivankovic
Guest





PostPosted: Tue Nov 11, 2003 12:51 pm    Post subject: Re: Painted myself into a (factory) corner Reply with quote

marek jedlinski wrote:
Quote:
On Mon, 10 Nov 2003 22:58:58 -0000, "Joanna Carter (TeamB)"
[email]joannac (AT) btinternetXX (DOT) com[/email]> wrote:


| Perhaps if the factory accessed a global config object that held all
| the properties (they're configurable by the user, loaded from an ini
| file), this would be a cleaner solution?

Then surely the Factory should be aware of the configuration used to set up
its objects?


I may not have a good understanding of the factory concept, then. It sounds
reasonable to say the factory should be aware of the configuration. But in
practice:

- the application reads its command line, which may specify some settings,
such as the location of the config file
- the application determines the location of the config file (current user?
all users? app's own folder? ini file or registry? etc). The application
also sets default values if no config data is present.
- the application loads the configuration. The configuration has a number
of settings which pertain to various behaviors at different levels. There
is a setting for "Pplace icon in system tray", and then there is a setting
that specifies the templates for text and HTML files.

(In reality, I have a generic TAppConfig class that handles all these
tasks, so that just by creating an instance I have the config fully set
up.)

Then, in a far and away unit somewhere, we have the factory which only
needs to know two or three of those settings, and shouldn't care where they
come from. So, what to do? Give the factory knowledge of the config object?
Or just give it the location of the config data, so that the factory can
load only the information it needs?



I am using Registry pattern to store this kind of data.

Zlatko


Back to top
John Elrick
Guest





PostPosted: Tue Nov 11, 2003 1:26 pm    Post subject: Re: Painted myself into a (factory) corner Reply with quote

"marek jedlinski" <eristic (AT) lodz (DOT) pdi.net> wrote


SNIP

Quote:

Incidentally, I've found a good summary of this problem at
http://www.industriallogic.com/papers/learning.html:

"Consider the MazeFactory example. The MazeFactory contains a method
called
MakeRoom, which takes as a parameter one integer, representing a room
number. What happens if you would also like to specify the room's color &
size? Would this mean that you would need to create a new Factory Method
for your MazeFactory, allowing you to pass in room number, color and size
to a second MakeRoom method?

"Of course, nothing would prevent you from setting the color and size of
the Room object after is has been instantiated, but this could also
clutter
your code, especially if you are creating and configuring many objects.
How
could you retain the MazeFactory and keep only one MakeRoom method but
also
accomodate different numbers of parameters used by MakeRoom to both create
and configure Room objects?"

And, of course, I don't have a good answer Smile

unit uintf_Configurable;

IConfigurable = interface
procedure setRoomNumber(const aNumber: integer);
end;

IConfigurableColor = interface(IConfigurable)
procedure setColor(const aColor: TColor);
end;

IConfigurableSize = interface(IConfigurable)
procedure setSize(const aSize: integer);
end;

IConfigurator = interface
procedure configure(const aConfigurable: IConfigurable);
end;

....
end.


IMazeFactory = interface
function makeNew(const aConfigurator: IConfigurator): IRoom;
end;


TRoom = class(TInterfacedObject, IRoom, IConfigurable)
....
constructor Create(const aConfigurator: IConfigurator);
end;


constructor TRoom.Create(const aConfigurator: IConfigurator);
begin
inherited Create;
aConfigurator.configure(Self);
end;


procedure TConfigurator.configure(const aConfigurable: IConfigurable);
var
localColor: IConfigurableColor;
localSize: IConfigurableSize;
begin
aConfigurable.setRoomNumber(FRoomNumber);

if Supports(aConfigurable, IConfigurableColor, localColor) then
localColor.setColor(FColor);

if Supports(aConfigurable, IConfigurableSize, localSize) then
localColor.setSize(FSize);
end;

"Software Engineering is a science that believes that any problem can be
solved with one more layer of indirection"


John



Back to top
Display posts from previous:   
Post new topic   Reply to topic    BorlandTalk.com Forum Index -> Delphi OO design All times are GMT
Page 1 of 1

 
Jump to:  
You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot vote in polls in this forum


Powered by phpBB © 2001, 2006 phpBB Group
SEO toolkit © 2004-2006 webmedic.