mercredi 28 septembre 2022

Design Pattern to use for customizable/extendable classes with constructors

Starting with the use case.
Let's consider the base for this questions is a big framework and implementations of business objects of some software.

This software hast to be customized quite regularly, so it would be preferred that most of the C# objects are extendable and logic can be overriden. Even "model data".

The goal would be to be able to write code, create objects with input parameters - that may create more objects etc - and you don't have to think about whether those objects have derived implementations in any way. The derived classes will be used automatically.
For ease of uses a typesafe way to create the objects would be preferred as well.

A quick example:

public class OrderModel
{
    public int Id { get; set; }
    public string Status { get; set; }
}
public class CustomOrderModel : OrderModel
{
    public string AdditionalData { get; set; }
}
public class StockFinder
{
    public Article Article { get; }

    public StockFinder(Article article)
    {
        Article = article;
    }

    public virtual double GetInternalStock() { /*...*/ }

    public virtual double GetFreeStock() { /*...*/ }
}
public class CustomStockFinder : StockFinder
{
    public bool UsePremiumAvailability { get; }

    public CustomStockFinder(Article article, bool usePremiumAvailability)
        : base(article)
    {
        UsePremiumAvailability = usePremiumAvailability;
    }

    protected CustomStockFinder(Article article) : this(article, false) { } // For compatibility (?)

    public override double GetFreeStock() { /*...*/ }
}

In both cases I wanna do stuff like this

var resp = Factory.Create<OrderModel>(); // Creates a CustomOrderModel internally

// Generic
var finderGeneric = Factory.Create<StockFinder>(someArticle);

// Typesafe?
var finderTypesafe1 = Factory.StockFinder.Create(someArticle); // GetFreeStock() uses the new implementation
var finderTypesafe2 = Factory.StockFinder.Create(someArticle, true); // Returns the custom class already

Automatically generating and compiling C# code on build is not a big issue and could be done.
Usage of Reflection to call constructors is okay, if need be.
It's less about how complicating some code generation logic, written code analyzers, internal factories, builders etc are, and more about how "easy" and understandable the framework solution will be on a daily basis, to write classes and create those objects.

I thought about tagging the relevant classes with Attributes and then generating a typesafe factory class automatically on build step. Not so sure about naming conflicts, or references that might be needed to compile, as the constructor parameters could be anything.
Also, custom classes could have different constructors, so they should be compatible at each place in default code where they might be constructed already, but still create the custom object. In the custom code then you should be able to use the full custom constructor.

I am currently considering several different cases and possibilities, and can't seem to find a good solution. Maybe I am missing some kind of design pattern, or am not able to look outside of my bubble.

What would be the best design pattern or coding be to implement use cases like this?

Aucun commentaire:

Enregistrer un commentaire