I'm working on an internal project for my company, and part of the project is to be able to generate various "Math Problems" increating a factory design for math problems. The purpose of the factory is:
- To generateThe problems, must specify the level ofbe generated with a certain difficulty in the factory(or
level
). To do this, I've got an abstract method called ConfigureLevels. - EachI set an abstract method called
ProblemFactory
contains abstracts methods as ConfigureXLevels andGenerate
, this one must be implemented in a concrete class.
This is the factory design which I'm talking to.
Here is the abstract ProblemFactory
.
- ProvidesThe abstract factory provide a
Random
variable. - 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:=IConfiguration
which works like a container of objects usefulusefull to generate the problem (for example binary and times tables both needs twoBound
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 about create addition problems, check how I'm overriding some ConfigureXLevel
from the abstract ProblemFactory
. The factory create additions problems, and returns IConfiguration
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 selected for the level
int y = //..
Operators op = Operator//.Addition.
return BinaryProblemProblemA.CreateProblemCreateProblemA(x, y, op);
}
protectedpublic override IConfigurationbool ConfigureEasyLevelCanConfigureMediumLevel()
{
//return thetrue;
same of ConfigureMediumLevel }
protected override IConfiguration ConfigureEasyLevel()
but with others values{
throw new NotImplementedException();
}
protected override IConfiguration ConfigureMediumLevel()
{
BinaryProblemConfiguration configuration = new BinaryProblemConfiguration();
configuration.Bound1 = new Bound<int>(1002, 100010);
configuration.Bound2 = new Bound<int>(102, 10010);
configuration.Operators = new List<Operators>() { Operators.Addition, Operators.Subtraction, Operators.Multiplication, Operators.Division };
return configuration;
}
protected override IConfiguration ConfigureHardLevel() {
{
// the same of ConfigureMediumLevel() but withthrow othersnew valuesNotImplementedException();
}
}
And this is a BinaryProblemConfiguration
public class BinaryProblemConfiguration : IConfiguration
{
public Bound<int> Bound1 { get; set; }
//Bounds for Number1public ofBound<int> aBound2 binary{ problemget; set; }
public Bound<int>List<Operators> Bound2Operators { get; set; }
// Bounds… public BinaryProblemConfiguration() Number2{ }
… 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.
Bound
class contains Min
and Max
values. For example is I select Levels.Medium
, I must receive a problem with the specific range or bound in Number1 and Number2 (Number 1 + Number 2 = X
)
AdditionProblemFactory factory = new AdditionProblemFactory();
BinaryProblem problem = (BinaryProblem)factory.Generate(Levels.Medium);
Here is the part which I don't know what should I should modify inof the design. Random is on ProblemFactory, but maybeMaybe is better to move the random variable to IConfiguration
IConfiguration and generate numbers there.
If you prefer to download it. Don't worry, it's so small. http://www.mediafire.com/?z5j9hu1szpuu2u5Here is the current project, don't worry it's so compact (Factories => Infrastructure.FactoryCore | Configurations => Infrastructure.ConfigurationCore | BinaryProblem => ExerciseA):