When applying
RAII, constructor tends to have arguments to be fully autonomous afterward. When combined with factory method, there can be number of if-else with "new" and arguments like below pseudo code.
interface IWish
{
void MakeTrue();
}
class EscapeCave : IWish
{
public EscapeCave( string master, int nTh, string target ) { ... }
public void MakeTrue() { ... }
}
class BecomePrince : IWish
{
public BecomePrince( string master, int nTh, string target ) { ... }
public void MakeTrue() { ... }
}
class BecomeHuman : IWish
{
public BecomeHuman( string master, int nTh, string target ) { ... }
public void MakeTrue() { ... }
}
class Genie
{
static public IWish Create( string wish, string master, int nth, string target )
{
if( wish == "enscape cave" )
{
return new EscapeCave( master, nth, target ); // code repetition and become tedious and smelly
}
else if( wish == "become prince" )
{
return new BecomePrince( master, nth, target );
}
else if( wish == "become human" )
{
return new BecomeHuman( master, nth, target );
}
throw new ArgumentException( "Not supported wish" );
}
}
To remove code repetition - "new" and arguments, Type can be used with System.ComponentModel.TypeDescriptor.CreateInstance().
Note that the Type should have same constructor - same number of arguments and types. It may be too restrictive but sometimes it is desirable as only difference should be differenct behaviour with same arguments.
class Genie
{
static public IWish Create( string wish, string master, int nth, string target )
{
var typeDict = new Dictionary
{
{ "enscape cave", typeof(EscapeCave) },
{ "become prince", typeof(BecomePrince) },
{ "become human", typeof(BecomeHuman) }, // genie can add its capable wish by simply adding line in here
};
var typeWish = typeDict[ wish ];
return (IWish)System.ComponentModel.TypeDescriptor.CreateInstance(
provider: null, // reflection
objectType: typeWish,
argTypes: new Type[] { typeof(string), typeof(int), typeof(string)},
args: new object[] { master, nth, target }
}
}