0

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();
    }
}
9
  • Looks sensible to me. Does this design allow to inject a "mock" db context object, for testing the factory or the controller without using a real database?
    – Doc Brown
    Sep 10, 2019 at 18:21
  • That's what I've been wondering too. If the controller didn't inject the DbContext into the factory, how can I get the ASP.NET DI Container to inject it for me? Sep 10, 2019 at 18:30
  • 1
    Honestly, if you don't know what 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.
    – Doc Brown
    Sep 10, 2019 at 18:34
  • Yeah MyDbContext should be replaceable. I could just use the EF Core InMemory database provider for testing Sep 10, 2019 at 18:38
  • I don't know if making the factory dependent on the context is a good idea though Sep 10, 2019 at 18:39

1 Answer 1

0

Yes its a correct approach.

Essentially you are instantiating an object from a db where the object could be one of several child classes.

A factory is a common way of achieving this.

But is it a good idea to make the factory dependent on this DbContext

Yes. I would always abstract the database into a repository. However, repositories are supposed to return business objects, so in this case the repository and factory would be the same thing and of course a repository needs DB access.

2
  • " However, repositories are supposed to return business objects, so in this case the repository and factory would be the same thing" Just because two services both return the same type does not mean that they are the same thing. The repository is concerned with how to instantiate a given entity of a given type, but a factory can (as would be the case for OP) be tasked with deciding which concrete type to return. That is not the reponsibility of a repository. Essentially, you'll have many repo methods (one per concrete type), and a single factory method that chooses which repo method to use
    – Flater
    Feb 2, 2021 at 15:22
  • I feel like you are ignoring the "in this case" bit. Its pretty common to have a repo return different sub classes based on type column in the db, maybe reading the extra info out of extra tables, in this case the factory and repository blend into a single class.
    – Ewan
    Feb 2, 2021 at 16:43

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.