for sure this is not the best title. I’m creating a system to generate math problems. The developer must implement two interfaces:
Problem: This contains the properties which needs the problem generated.Configuration: This is the range parameters to generate aProblem.
These are the interfaces:
public abstract class Problem
{
}
public abstract class Configuration
{
}

And here is one example for the BinaryProblem.
public class BinaryProblem : Problem
{
public decimal X { get; set; }
public decimal Y { get; set; }
public BinaryProblem(decimal x, decimal y)
{
this.X = x; // Number 1
this.Y = y; // Number 2
}
}
public class BinaryProblemConfiguration : Configuration
{
// Range for X
public int XMin { get; set; }
public int XMax { get; set; }
// Range for Y
public int YMin { get; set; }
public int YMax { get; set; }
public BinaryProblemConfiguration() { }
}
Can you see that line between Problem and Configuration? I need to put many Modules which implements those two interfaces.
So, I need a way to generate them. I was thinking in create an abstract class where contains:
protected static Random: Almost all configurations needs a random class to create the numbers (I.E.random.Next(X1, Y1);). And it’s necessary to be static because a need to create the numbers using the same seed always.public abstract TProblem Generate(TConfiguration config); // where : TProblem : Problem, new(), TConfiguration : Configuration
And implement this abstract class in each problem type.
My question is: Is this a good way to start to solve this solution or what other solution do I have to do?
EDIT: One example which I was trying to is:
This is my abstract class, I mean my idea is when you instanciate this class, you specify the generic values:
public interface IProblemFactory
{
Problem CreateProblem();
}
public abstract class ProblemBaseFactory<TProblem, TConfiguration> : IProblemFactory
where TProblem : Problem
where TConfiguration : Configuration
{
private const int SEED = 100;
protected TConfiguration _config;
protected static Random _random;
public ProblemBaseFactory(TConfiguration config)
{
_config = config;
if (_random == null) _random = new Random(SEED);
}
public void SetSeed(int newSeed)
{
_random = new Random(newSeed);
}
public Problem CreateProblem()
{
return CreateProblem(_config);
}
public abstract TProblem CreateProblem(TConfiguration config);
}
public class BinaryProblemFactory : ProblemBaseFactory<BinaryProblem, BinaryProblemConfiguration>
{
public override BinaryProblem CreateProblem(BinaryProblemConfiguration config)
{
var x = GenerateValueInRange(_config.Range1);
var y = GenerateValueInRange(_config.Range2);
return new BinaryProblem(x, y, Operators.Addition);
}
private decimal GenerateValueInRange(Range<int> range)
{
return _random.Next(range.MinValue, range.MaxValue);
}
}
I think it’s good to aggregate values that used together. In your case object Range will be useful. Something like (without verification min <= max):
After that BinaryProblemConfiguration will look like this:
What you actually implementing is products factory. So I Intermediary is not very descriptive name for it:
Create factory for each type of products. Each factory knows what type of product it creates and what type of configuration it needs. E.g:
Factory creation:
Pass created problem factory somewhere as IProblemFactory:
Also there no special need for configuration object. I think that creator of product should have knowledge how to create product. So I’d rather go with properties XRange and YRange added to factory: