For a ASP.NET Core application, I'm using a library which performs calculations using objects that have a similar interface but their constructors use different inputs. The inputs are market prices and volatilities.
public class Base
{
public virtual double Method1();
public virtual double Method2();
}
public class BaseOne : Base
{
public override double Method1();
public override double Method2();
}
public class BaseTwo : Base
{
public override double Method1();
public override double Method2();
}
public class ConcreteOneA : BaseOne
{
public ConcreteOneA(double F, double V, double r, double K, ...);
public override double Method1() { // code }
public override double Method2() { // code }
}
public class ConcreteOneB : BaseOne
{
public ConcreteOneA(double F, double V, double r, double K, ...);
public override double Method1() { // code }
public override double Method2() { // code }
}
public class ConcreteTwoA : BaseTwo
{
public ConcreteOneA(double F1, double F2, double V, double r, double K, ...);
public override double Method1() { // code }
public override double Method2() { // code }
}
To create the ConcreteOne and ConcreteTwo classes, I have to fetch the F, F1, F2, and V inputs from a SQL Server database. I have a EF Core DbContext entity which is injected into a ASP.NET Core controller.
Every time, I want to perform calculations, my code was littered with DbContext queries and filters. Also I wanted to be able to use a single controller action to compute values for Method1 and Method2, since these methods are similar to all the Concrete classes, and it provided for a convenient API interface for the users. So I created a factory class:
public class BaseFactory
{
private MyContext _context;
public BaseFactory(MyDbContext context)
{
_context = context;
}
public Base FromCode(MyDbEntity obj)
{
// use the context object to fetch F and V, and also F1 and F2 if the obj type is 3
//...
// compute the other inputs for the concrete constructors which can be obtained directly from the MyDbEntity obj
// ...
switch (obj.Code)
{
case "1":
case "4":
return new ConcreteOneA(F, V, ....rest of the parameters computed from obj...
case "5":
return new ConcreteOneB(F,V, ....rest of the parameters computed from obj...);
case "3":
return new ConcreteTwoA(F1, F2, V, ......rest computed from obj.....);
}
}
}
Is this the right approach? The F is the price and V is the volatility which might need to come from a different data source in the future, so I could need to create another factory method for that specific source. But is it a good idea to make the factory dependent on this DbContext? My controller passes the injected DbContext into the factory when the controller is created:
[ApiController]
public class MyController
{
public MyDbContext _context;
private BaseFactory factory;
public MyController(MyDbContext context)
{
_context = context;
factory = new BaseFactory(_context);
}
[HttpGet('/route1')]
public ActionResult<double> MyMethodCompute(string code, double m, double s, double p)
{
// use _context to get MyDbEntity obj...
return factory.FromCode(obj).Method1();
}
}
MyDbContext
is and if it can be replaced by a mock, how shall we? In case it cannot be replaced, encapsulate it inside of some kind of repository class which abstracts the database away.