I'm creating a system to generate math problems. As you know in mathematics, there are several different kinds of problems: Binary problems, fractions, decimals, comparating two numbers, etc.I'm creating an abstract problem factory, where this one is like a black box, which receives a Configuration as input, and returns the Problem as output.Problem: This contains the properties which needs the problem generated.Configuration: This is the range parameters or conditions to generate a Problem.Factory: He is in charge of creating the new Problem.Here I have my factory interface and marker interfaces:public abstract class Problem { }public abstract class Configuration { }public interface IProblemFactory{    Configuration Configuration { get; set; }    Problem CreateProblem();}This is a base class for factories, because I need the Random class. All my classes which implement this one, must have the same seed, so I have a static instance.public abstract class ProblemFactoryBase<P, C> : IProblemFactory    where P : Problem    where C : Configuration{    private const int DEFAULT_SEED = 100;    protected C _config;    private static Random _random;    public ProblemFactoryBase()    {        if (_random == null) _random = new Random(DEFAULT_SEED);    }    public ProblemFactoryBase(C config)    {        _config = config;        if (_random == null) _random = new Random(DEFAULT_SEED);    }    protected Random Random { get { return _random; } }    public C Configuration    {        get { return _config; }        set { _config = value; }    }    #region IProblemFactory Implementation    Configuration IProblemFactory.Configuration    {        get { return _config; }        set        {            C config = value as C;            if (config == null) throw new InvalidCastException(config);            _config = config;        }    }    protected abstract P CreateProblem(C config);    #endregion    public Problem CreateProblem()    {        if (_config == null) throw new InvalidOperationException(config);        return CreateProblem(_config);    }    public static void SetSeed()    {        _random = new Random(DEFAULT_SEED);    }}Note that the ProblemFactoryBase<P, C> class is a generic type, and implements the abstract method when the type is constructed.When I have an implementation of all of this. For example, a module for a BinaryProblems like 2+3 would be:public class BinaryConfiguration : Configuration{    public Range<int> Range1 { get; set; }    public Range<int> Range2 { get; set; }    public List<Operators> Operators { get; set; }    public BinaryConfiguration(Range<int> range1, Range<int> range2, List<Operators> operators)    {        this.Range1 = range1;        this.Range2 = range2;        this.Operators = operators;    }public class BinaryProblem : Problem{    public BinaryProblem(decimal x, decimal y, Operators op, decimal response)    {        this.X = x;        this.Y = y;        this.Response = response;    }    public decimal X { get; private set; }    public decimal Y { get; private set; }    public decimal Response { get; private set; }}public enum Operators{    Addition, Substract, Multiplication, Division}And the most important part, here is a concrete factory. The class specifies the type parameters for the base generic class. Why? Because I supposed is the best way to implement the concrete values, I mean I don't have to cast any value right now. public class BinaryFactory : ProblemFactoryBase<BinaryProblem, BinaryConfiguration>{    protected override BinaryProblem CreateProblem(BinaryConfiguration config)    {        var x = GenerateValueInRange(config.Range1);        var y = GenerateValueInRange(config.Range2);        var index = Random.Next(config.Operators.Count);        var op = config.Operators[index];        return new BinaryProblem(x, y, op, x + y);    }    private decimal GenerateValueInRange(Range<int> range)    {        return Random.Next(range.Min, range.Max);    }}And to implement it is:        BinaryConfiguration configuration = new BinaryConfiguration() {.. }        IProblemFactory factory = new BinaryFactory(configuration);        var a = factory.CreateProblem();It's doing what I like, because I want to put several factories in an array, but at the same time, the implementation of ProblemFactoryBase is good to me because there's no necessity for casting types.I'm still learning design patterns. Maybe there are another ways to improve it or I'm not following an advice. What is your feedback?
I have a problem ...factory
c#;design patterns