I'm creating a factory design for math problems. The purpose of the factory is:
- The problems must be generated with a certain difficulty (or
level). To do this, I've got an abstract method called ConfigureLevels. - I set an abstract method called
Generate, this one must be implemented in a concrete class.
This is the factory design which I'm talking to.

Here is the abstract ProblemFactory.
- The abstract factory provide a
Randomvariable. - Also contains a
CanConfigureXLevel()which by default returns false, but if you want that will be available, just override it to true.ConfigureXLevel()is an abstract method which knows how to configure the level (returnsIConfigure). - Contains a dictionary which contains the available levels (
key:=Levels,value:=IConfigurationwhich works like a container of objects usefull to generate the problem (for example binary and times tables both needs two bound objects)).
_
public abstract class ProblemFactory
{
private IDictionary<Levels, IConfiguration> Configurations = new Dictionary<Levels, IConfiguration>();
protected Random Random = new Random();
public ProblemFactory()
{
LoadLevels();
}
protected abstract Problem Generate();
public virtual bool CanConfigureEasyLevel() { return false; }
public virtual bool CanConfigureMediumLevel() {return false; }
public virtual bool CanConfigureHardLevel() {return false; }
protected abstract IConfiguration ConfigureEasyLevel();
protected abstract IConfiguration ConfigureMediumLevel();
protected abstract IConfiguration ConfigureHardLevel();
private void LoadLevels()
{
if (CanConfigureEasyLevel()) {
Configurations.Add(Levels.Easy, ConfigureEasyLevel());
}
if (CanConfigureMediumLevel()) {
Configurations.Add(Levels.Medium, ConfigureMediumLevel());
}
if (CanConfigureHardLevel()) {
Configurations.Add(Levels.Hard, ConfigureHardLevel());
}
}
private void Configure(Levels level)
{
if (!Configurations.ContainsKey(level)) throw new InvalidOperationException("Level not available");
// ..
}
}
And here is a concrete class, check how I'm overriding some ConfigureXLevel from the abstract ProblemFactory. The factory create additions problems, and it should know how to calculates.
public class AdditionProblemFactory : ProblemFactory
{
public AdditionProblemFactory(Levels level)
: base(level) { //.. }
public override Problem Generate(IConfiguration configuration)
{
int x = //.. x must receive a random number according to the configuration
int y = //..
Operators op = //..
return ProblemA.CreateProblemA(x, y, op);
}
public override bool CanConfigureMediumLevel()
{
return true;
}
protected override IConfiguration ConfigureEasyLevel()
{
throw new NotImplementedException();
}
protected override IConfiguration ConfigureMediumLevel()
{
BinaryProblemConfiguration configuration = new BinaryProblemConfiguration();
configuration.Bound1 = new Bound<int>(2, 10);
configuration.Bound2 = new Bound<int>(2, 10);
configuration.Operators = new List<Operators>() { Operators.Addition, Operators.Subtraction, Operators.Multiplication, Operators.Division };
return configuration;
}
protected override IConfiguration ConfigureHardLevel()
{
throw new NotImplementedException();
}
}
And this is a BinaryProblemConfiguration
public class BinaryProblemConfiguration : IConfiguration
{
public Bound<int> Bound1 { get; set; }
public Bound<int> Bound2 { get; set; }
public List<Operators> Operators { get; set; }
public BinaryProblemConfiguration() { }
public BinaryProblemConfiguration(Bound<int> bound1, Bound<int> bound2, List<Operators> operators)
{
this.Bound1 = bound1;
this.Bound2 = bound2;
this.Operators = operators;
}
}
The matter is in the Generate method from AdditionProblemFactory and TimesTablesProblemFactory, x, y and operator variables should receive random numbers according to the Level IConfiguration.
Here is the part I don't know what I should modify of the design. Maybe is better move the random variable to IConfiguration and generate numbers there.
Here is the current project, don't worry it's so compact (Factories => Infrastructure.FactoryCore | Configurations => Infrastructure.ConfigurationCore | BinaryProblem => ExerciseA):