I'm having a hard time creating a design (due to my lack of experience). I need a little of help to create the Model.
It's a mathematics system. I've created an IProblem
interface with a function IsCorrect
, this function helps me to know if the result is correct or not (by parameter). It also has a function CreateAnswer()
because some problems have 1, 2 or many answers.
public interface IProblem
{
bool IsCorrect(IAnswer answer);
IAnswer CreateAnswer();
}
IAnswer
is an interface which contains the answer, it can be a string, integer, decimal, several, multiple choice, etc..
public interface IAnswer
{
}
public class IntegerAnswer : IAnswer
{
public int Number { get; set; }
}
public class StringAnswer : IAnswer
{
public string Number { get; set; }
}
public class DecimalAnswer : IAnswer
{ ... }
public class MultipleChoiceAnswer : IAnswer
{ ... }
Here is a concrete Problem:
public class BinaryProblem : IProblem, IEquatable<BinaryProblem>
{
private int _number1;
private int _number2;
public int Number1
{
get { return _number1; }
set { _number1 = value; }
}
public int Number2
{
get { return _number2; }
set { _number2 = value; }
}
public BinaryProblem(int number1, int number2)
{
this.Number1 = number1;
this.Number2 = number2;
}
public bool IsCorrect(IAnswer answer)
{
IntegerAnswer integerAnswer = (IntegerAnswer)answer;
return integerAnswer.Number == _number1 + _number2;
}
public IAnswer CreateAnswer()
{
return new IntegerAnswer();
}
public override string ToString()
{
return _number1 + " + " + _number2;
}
public override bool Equals(object obj)
{
if (obj is BinaryProblem)
return this.Equals(obj);
else
return false;
}
public bool Equals(BinaryProblem other)
{
return this.Number1 == other.Number1 &&
this.Number2 == other.Number2;
}
}
And to run this:
// Binary problem test
BinaryProblem binary = new BinaryProblem(4, 5);
IntegerAnswer answer = (IntegerAnswer)binary.CreateAnswer();
answer.Number = 9;
binary.IsCorrect(answer);
I realized it is necessary to store the correct answer. For example, if it's a problem where the stated question is: convert decimal to fraction.
My limitation here is that I need to know the result at the moment the problem is created. I'm convinced that the Answer doesn't belong to the problem, but also, the class needs to know the correct answer when it is created. Because 0.111 it's confusing, it can be 1/9 or 111/1000, so I prefer to store the correct answer in some place.
So, where should I modify the model?
I created a factory where one can create problems, which contains values of necessary properties and the correct answer. I'd like to know if the performance or OOP rules are correct, or if there are things to do to improve the factory.
I've modified the answers by a generic class.
This is the interface for my factories:
public interface IFactory<T> where T : IProblem
{
T CreateProblem();
}
My base class factory:
public abstract class Factory<T> : IFactory<T> where T : IProblem
{
protected const int DEFAULT_SIZE = 20;
protected const int MAX_SIZE = 100;
protected static Random rnd;
protected static LinkedListNode<T> actualNode;
protected static LinkedList<T> problems;
public virtual int TotalProblemsPossible { get; set; }
protected Factory(Levels level)
{
Initialize();
ConfigureLevels(level);
FirstTime();
}
public virtual void FirstTime()
{
if (rnd == null) rnd = new Random(MAX_SIZE);
if (problems == null)
{
problems = new LinkedList<T>();
Generate(problems);
}
actualNode = problems.First;
}
public virtual T CreateProblem()
{
if (actualNode.Next == null)
{
Generate(problems);
}
actualNode = actualNode.Next;
return actualNode.Value;
}
private void Generate(LinkedList<T> problems)
{
for (int i = 0; i < DEFAULT_SIZE; i++)
{
T newProblem;
int bucles = 0;
do
{
if (bucles == 50) throw new InvalidOperationException();
newProblem = Generate();
bucles++;
} while (problems.Contains(newProblem));
problems.AddLast(newProblem);
}
}
protected virtual void Initialize()
{
}
protected abstract T Generate();
protected abstract void ConfigureLevels(Levels level);
}
And a particular factory. At this factory case, I create a class called Bound which contains limits for a number, and gets some numbers randomly to create the problem.
public class BinaryProblemFactory : Factory<BinaryProblem>
{
private Bound<int> Bound { get; set; }
public BinaryProblemFactory(Levels level)
: base(level)
{
}
protected override void Initialize()
{
Bound = new Bound<int>();
base.Initialize();
}
protected override void ConfigureLevels(Levels level)
{
switch (level)
{
case Levels.Easy:
this.Bound.Min = 10;
this.Bound.Max = 100;
break;
case Levels.Normal:
this.Bound.Min = 50;
this.Bound.Max = 200;
break;
case Levels.Hard:
this.Bound.Min = 100;
this.Bound.Max = 10000;
break;
}
}
protected override BinaryProblem Generate()
{
BinaryProblem problem;
int number1 = rnd.Next(Bound.Min, Bound.Max);
int number2 = rnd.Next(Bound.Min, Bound.Max);
Answer<int> correctValue = new Answer<int>(number1 + number2);
problem = new BinaryProblem(number1, number2, correctValue);
return problem;
}
}
The idea is to do something similar with each problem type I want to add to the program. What do you think?
For testing:
BinaryProblemFactory factory = new BinaryProblemFactory(Levels.Normal);
List<BinaryProblem> problemList = new List<BinaryProblem>();
for (int i = 0; i < 50; i++)
{
BinaryProblem binary2 = (BinaryProblem)factory.CreateProblem();
problemList.Add(binary2);
}
bool Equals(object)
method instead of (or in addition to) providing you own typed Equals method. Also, you should override theint GetHashCode()
method. This will ensure that your object's instances are treated correctly when they are compared by things like the standard .NET collection classes. \$\endgroup\$