Factory method

M

Mark

I have an abstract class, and a set of classes that inherit from my abstract
class. The fact that it is abstract is likely irrelevant. I have a static
factory method in my abstract class that creates subclasses. The
constructor in my subclasses must be able to call the constructor in my base
class. For the factory method in my abstract class to call the constructor
on my subclasses, the constructor in the subclass MUST be public (or
internal). They cannot be private or protected. However, doen't that
basically defeat the purpose of factory? I'd love to be able to make all
these constructors private or similar so that someone can't create subclass
instances without using the Factory. If this was all in a separate DLL, I
suppose I'd be saved by "internal", but we have small team of developers
working on projects where that type of seperation really shouldn't be
necessary.

Suggestions? Code sample below ...

Thanks in advance.

Mark


public abstract class MyBase
{
protected string first;

public MyBase(string first )
{
this.first = first;
}

public static MyBase Factory(int stateId)
{
switch (stateId)
{
case 700:
return new MySubClass1(first);
default:
throw new Exception("Bogus code!");
}
}
}
 
G

Guest

I've been looking at factories today too (as a work-around for the lack of
virtual constructors). It seems that factories work best when the class
doesn't use a parameterized constructor, but has a virtual method to
initialize the new instance. This creates a two-step process:

MyClass x = new MyClass() ;
x.Initialize ( ... ) ;

That first line means that you still need a specialized factory for each
class, yuck.

Ergo, I have devised the following scheme, which has its own shortcomings...

I defined an interface:

public interface IConstructable
{
void Constructor ( params object[] Params ) ;
}

(It sure would be nice if an interface could specify a constructor.)

And the following static factory method:

public static IConstructable
New
(
System.Type What
,
params object[] Params
)
{
IConstructable result = null ;

if ( What.GetConstructors().Length > 1 )
{
throw ( new System.ArgumentException ( string.Format
(
"Type {0} contains more than the default constructor."
,
What.Name
) ) ) ;
}

System.Reflection.ConstructorInfo con = What.GetConstructor ( new
System.Type[] {} ) ;

if ( con == null )
{
throw ( new System.ArgumentException ( string.Format
(
"Did not find a parameterless constructor for type {0}."
,
What.Name
) ) ) ;
}

if ( !con.IsPublic )
{
throw ( new System.ArgumentException ( string.Format
(
"Did not find a public parameterless constructor for type
{0}."
,
What.Name
) ) ) ;
}

result = (IConstructable) con.Invoke ( new object[] {} ) ;

result.Constructor ( Params ) ;

return ( result ) ;
}

Then to use it for a class:

class A : IConstructable
{
private string str ;

public virtual void
Constructor
(
params object[] Params
)
{
this.str = (string) Params [ 0 ] ;
}

public override string
ToString
(
)
{
return ( this.str ) ;
}
}

And to make an instance thereof (this is the fugly part):

A a = (A) New ( typeof(A) , "A" ) ;

This one factory method works with any class that implements IConstructable,
as if 'twere a virtual constructor. But the class's Constructor method will
need to do type checking on the parameters, yuck.

Perhaps I can have it use a struct for the parameters, hmm...

Note that _ideally_ the class would not define a constructor, at most it may
define a public parameterless constructor.

Again, this was to work-around the lack of virtual constructors, so yes, an
uninformed user may call new on the class and mess things up, but I'm still
working on't.
 
N

Nick Malik [Microsoft]

Here's the Flaw
A a = (A) New ( typeof(A) , "A" ) ;

You used 'new'

The point of a factory is that the calling class NEVER uses 'new'

Your design is not a factory. It is interesting. Clever perhaps. I don't
expect to use it.
But it is definitely not a factory.

--
--- Nick Malik [Microsoft]
MCSD, CFPS, Certified Scrummaster
http://blogs.msdn.com/nickmalik

Disclaimer: Opinions expressed in this forum are my own, and not
representative of my employer.
I do not answer questions on behalf of my employer. I'm just a
programmer helping programmers.
--
PIEBALD said:
I've been looking at factories today too (as a work-around for the lack of
virtual constructors). It seems that factories work best when the class
doesn't use a parameterized constructor, but has a virtual method to
initialize the new instance. This creates a two-step process:

MyClass x = new MyClass() ;
x.Initialize ( ... ) ;

That first line means that you still need a specialized factory for each
class, yuck.

Ergo, I have devised the following scheme, which has its own
shortcomings...

I defined an interface:

public interface IConstructable
{
void Constructor ( params object[] Params ) ;
}

(It sure would be nice if an interface could specify a constructor.)

And the following static factory method:

public static IConstructable
New
(
System.Type What
,
params object[] Params
)
{
IConstructable result = null ;

if ( What.GetConstructors().Length > 1 )
{
throw ( new System.ArgumentException ( string.Format
(
"Type {0} contains more than the default constructor."
,
What.Name
) ) ) ;
}

System.Reflection.ConstructorInfo con = What.GetConstructor ( new
System.Type[] {} ) ;

if ( con == null )
{
throw ( new System.ArgumentException ( string.Format
(
"Did not find a parameterless constructor for type {0}."
,
What.Name
) ) ) ;
}

if ( !con.IsPublic )
{
throw ( new System.ArgumentException ( string.Format
(
"Did not find a public parameterless constructor for type
{0}."
,
What.Name
) ) ) ;
}

result = (IConstructable) con.Invoke ( new object[] {} ) ;

result.Constructor ( Params ) ;

return ( result ) ;
}

Then to use it for a class:

class A : IConstructable
{
private string str ;

public virtual void
Constructor
(
params object[] Params
)
{
this.str = (string) Params [ 0 ] ;
}

public override string
ToString
(
)
{
return ( this.str ) ;
}
}

And to make an instance thereof (this is the fugly part):

A a = (A) New ( typeof(A) , "A" ) ;

This one factory method works with any class that implements
IConstructable,
as if 'twere a virtual constructor. But the class's Constructor method
will
need to do type checking on the parameters, yuck.

Perhaps I can have it use a struct for the parameters, hmm...

Note that _ideally_ the class would not define a constructor, at most it
may
define a public parameterless constructor.

Again, this was to work-around the lack of virtual constructors, so yes,
an
uninformed user may call new on the class and mess things up, but I'm
still
working on't.
 
N

Nick Malik [Microsoft]

The base class should not be bound to the list of possible inheriting
children. The base class must not create the children. That defeats the
purpose.

The child object can have a public constructor. That doesn't mean that you
will use it. If you don't want a public constructor, then define a Factory
Method in the base class and, in the child classes, implement the factory
method to return the object.

You won't be able to "enforce" that the child object cannot have a public
constructor. Why would you want to? But you can provide a mechanism that
the child class must implement that returns an object that derives from the
base type. The users of the class will always use this method, which means
you no longer have to worry about it. If a child class shouldn't have a
public constructor, write it so that the contstructor is private.

The constructor in your subclasses can call the constructor in your base
class. See this topic from Jon's site:
http://www.yoda.arachsys.com/csharp/constructors.html

To implement a factory method, in the base class define an abstract method
that returns an object of the base type.

<Warning -- uncompiled air code>

public abstract myBaseWidget
{
private myBaseWidget(int myParam)
{
}
public abstract myBase CreateWidget();
}

public myChildWidget : myBaseWidget
{
private myChildWidget() : base(4)
{
// go do constructor things
}
public myChildWidget CreateWidget()
{
// this is your factory method!
return new myChildWidget();
}
}



--
--- Nick Malik [Microsoft]
MCSD, CFPS, Certified Scrummaster
http://blogs.msdn.com/nickmalik

Disclaimer: Opinions expressed in this forum are my own, and not
representative of my employer.
I do not answer questions on behalf of my employer. I'm just a
programmer helping programmers.
--
 
S

Steve Walker

"Nick Malik said:
To implement a factory method, in the base class define an abstract method
that returns an object of the base type.

<Warning -- uncompiled air code>

public abstract myBaseWidget
{
private myBaseWidget(int myParam)
{
}
public abstract myBase CreateWidget();
}

public myChildWidget : myBaseWidget
{
private myChildWidget() : base(4)
{
// go do constructor things
}
public myChildWidget CreateWidget()
{
// this is your factory method!
return new myChildWidget();
}
}

Hmm. How do you create an instance of myChildWidget in order to call the
non-static CreateWidget method?
 
N

Nick Malik [Microsoft]

Some mornings... I write stuff that I am embarrassed to look at later :-}

even 10 minutes later

You are correct, of course. The factory method either has to be static (in
which case, it isn't inherited) or part of another class altogether.

(duh!)
Sorry.

--
--- Nick Malik [Microsoft]
MCSD, CFPS, Certified Scrummaster
http://blogs.msdn.com/nickmalik

Disclaimer: Opinions expressed in this forum are my own, and not
representative of my employer.
I do not answer questions on behalf of my employer. I'm just a
programmer helping programmers.
 
S

Steve Walker

"Nick Malik said:
Some mornings... I write stuff that I am embarrassed to look at later :-}

even 10 minutes later

:O)

Me too.
You are correct, of course. The factory method either has to be static (in
which case, it isn't inherited) or part of another class altogether.

I find that where this happens always a thought-provoking decision.
Polymorphism is great, but at some point you have to bite the bullet and
decide exactly what it is you're going to create an instance of, and it
always seems somehow intellectually unsatisfying. I think the
subconscious appeal of the factory pattern is that you can encapsulate a
bit of code which you'd rather not see :blush:)

If you can justify taking the hit of using reflection, it's beautiful. I
once wrote a "generic business rules in database" type of system which
instantiated tree structures of rule subclasses by reflection, using
class names from a database. That was neat, but the logic for
determining which class to instantiate is seldom fits so well with that
approach.
 
J

Jon Skeet [C# MVP]

Nick Malik said:
Here's the Flaw


You used 'new'

The point of a factory is that the calling class NEVER uses 'new'

And it doesn't - it uses New, which is a method. Note the difference in
case.
Your design is not a factory. It is interesting. Clever perhaps. I don't
expect to use it.
But it is definitely not a factory.

It's not quite the normal factory pattern, but I think it's still a
factory.
 
G

Guest

.... and, in the child classes, implement the factory
method to return the object.

I don't want to have to define a method in the child class that simply calls
the parent class' method. The traditional factory pattern solves some issues,
but I don't think it's designed to solve the problem of having to write
seemingly unnecessary repetitive code, whether that be a constructor or a
factory method.

My scheme allows the child class to _not_ have to define such methods (the
children will receive a the compiler-provided default constructor). Based on
class A in my previous message one can create:

class C : A
{
}

Which an app can instantiate with:

C c = (C) New ( typeof(C) , "C" ) ;

As you can see, there is no "needlessly duplicated code" in class C.

On the other hand, class B may add a new field, and therefore provides its
own Constructor method:

class B : A
{
private int num ;

public override void
Constructor
(
params object[] Params
)
{
base.Constructor ( Params ) ;
this.num = (int) Params [ 1 ] ;
}

public override string
ToString
(
)
{
return ( base.ToString() + this.num.ToString() ) ;
}
}

In conclusion...

If the child class does not define new fields (only new methods) it ought to
be able to use the parent class' constructor, inititalizer, factory,
whatever, and my scheme accomplishes this (although the code to instantiate
is ugly).

P.S. Over the weekend I tried to use a struct as the parameter to
Constructor without success, but that's a subject for a new thread.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Top