I have a factory object ChallengeManager
to generate instances of a Challenge
object for a game I'm building. There are many challenges. The constructors for each Challenge
class derivation are different, however there is a common interface among them, defined in the base class.
When I call manager.CreateChallenge()
, it returns an instance of Challenge
, which is one of the derived types.
Ideally, I would like to keep the code for the object construction inside the derived class itself, so all the code related to that object is co-located. Example:
class Challenge {}
class ChallengeA : Challenge {
public static Challenge MakeChallenge() {
return new ChallengeA();
}
}
class ChallengeB : Challenge {
public static Challenge MakeChallenge() {
return new ChallengeB();
}
}
Now, my ChallengeManager.CreateChallenge()
call only needs to decide the class to call MakeChallenge()
on. The implementation of the construction is contained by the class itself.
Using this paradigm, every derived class must define a static MakeChallenge()
method. However, since the method is a static one, I am not able to make use of an Interface here, requiring it.
It's not a big deal, since I can easily remember to add the correct method signature to each derived class. However, I am wondering if there is a more elegant design I should consider.
I really like the pattern you are describing and use it often. The way I like to do it is:
abstract class Challenge
{
private Challenge() {}
private class ChallengeA : Challenge
{
public ChallengeA() { ... }
}
private class ChallengeB : Challenge
{
public ChallengeB() { ... }
}
public static Challenge MakeA()
{
return new ChallengeA();
}
public static Challenge MakeB()
{
return new ChallengeB();
}
}
This pattern has many nice properties. No one can make a new Challenge
because it is abstract. No one can make a derived class because Challenge
's default ctor is private. No one can get at ChallengeA
or ChallengeB
because they are private. You define the interface to Challenge
and that is the only interface that the client needs to understand.
When the client wants an A
, they ask Challenge
for one, and they get it. They don't need to worry about the fact that behind the scenes, A
is implemented by ChallengeA
. They just get a Challenge
that they can use.