I have implemented a sort of Strategy Pattern for implementing a business rule but having trouble with figuring out how to implement it following dependency Injection:
What I have done is I have calculated priority based on
- Business types (Petroleum, Software Company, Insurance etc..)
- Revenues (1 million, 2 million, 3 million etc..)
- and Company Size (Large, Medium, Small)
I need to store this Priority in a database.
Code:
public class Request
{
public int Revenue;
public int CompanySizeId;
public int BusinessTypeId;
}
public interface IRankProvider
{
int RankCount { get; }
int RankIndexOf(Request request);
}
public interface IPriorityProvider
{
int PriorityOf(Request request);
}
public class PriorityProvider : IPriorityProvider
{
IRankProvider[] rankProviders;
public PriorityProvider(params IRankProvider[] rankProviders)
{
this.rankProviders = rankProviders;
}
public int PriorityOf(Request request)
{
int priority = 0;
foreach (var rp in rankProviders)
priority = priority * rp.RankCount + rp.RankIndexOf(request);
return priority + 1;
}
}
public class CompanySize
{
public int Id;
public string Size;
public int Rank;
}
public class CompanySizeRankProvider : IRankProvider
{
Dictionary<int, int> indexById;
public CompanySizeRankProvider(IEnumerable<CompanySize> source)
{
indexById = source
.OrderBy(e => e.Rank)
.Select((item, index) => new { item, index })
.ToDictionary(e => e.item.Id, e => e.index);
}
public int RankCount { get { return indexById.Count; } }
public int RankIndexOf(Request request)
{
int index;
if (indexById.TryGetValue(request.CompanySizeId, out index)) return index;
throw new KeyNotFoundException();
}
}
public class BusinessType
{
public int Id;
public string Title;
public int Rank;
}
public class BusinessTypeRankProvider : IRankProvider
{
Dictionary<int, int> indexById;
public BusinessTypeRankProvider(IEnumerable<BusinessType> source)
{
indexById = source
.OrderBy(e => e.Rank)
.Select((item, index) => new { item, index })
.ToDictionary(e => e.item.Id, e => e.index);
}
public int RankCount { get { return indexById.Count; } }
public int RankIndexOf(Request request)
{
int index;
if (indexById.TryGetValue(request.BusinessTypeId, out index)) return index;
throw new KeyNotFoundException();
}
}
public class Revenue
{
public int Id;
public int LowerLimit;
}
public class RevenueRankProvider : IRankProvider
{
int[] lowerLimits;
public RevenueRankProvider(IEnumerable<Revenue> source)
{
lowerLimits = source
.OrderByDescending(e => e.LowerLimit)
.Select(e => e.LowerLimit)
.ToArray();
}
public int RankCount { get { return lowerLimits.Length + 1; } }
public int RankIndexOf(Request request)
{
int index = 0;
while (index < lowerLimits.Length && request.Revenue < lowerLimits[index])
index++;
return index;
}
}
My Controller:
[Route("api/[controller]")]
[ApiController]
public class PeopleController : ControllerBase
{
IPeopleProvider provider;
IPriorityProvider _priorityProvider;
public PeopleController(IPeopleProvider provider, IPriorityProvider priorityProvider)
{
this.provider = provider;
this._priorityProvider = priorityProvider;
}
public Person Post()
{
// coming from database
var businessTypes = new BusinessType[]
{
new BusinessType { Id = 1, Title = "A", Rank = 1 },
new BusinessType { Id = 2, Title = "B", Rank = 2 },
new BusinessType { Id = 3, Title = "C", Rank = 3 },
new BusinessType { Id = 4, Title = "D", Rank = 4 },
new BusinessType { Id = 5, Title = "E", Rank = 5 },
};
// coming from database
var companySizes = new CompanySize[]
{
new CompanySize { Id = 1, Size = "Large", Rank = 1 },
new CompanySize { Id = 2, Size = "Medium", Rank = 2 },
new CompanySize { Id = 3, Size = "Small", Rank = 3 },
new CompanySize { Id = 4, Size = "Micro", Rank = 4 },
};
// coming from database
var revenues = new Revenue[]
{
new Revenue { Id = 1, LowerLimit = 500000001 },
new Revenue { Id = 2, LowerLimit = 250000001 },
new Revenue { Id = 3, LowerLimit = 100000001 },
new Revenue { Id = 4, LowerLimit = 10000001 },
};
// I want to avoid new here
_priorityProvider = new PriorityProvider(
new RevenueRankProvider(revenues),
new CompanySizeRankProvider(companySizes),
new BusinessTypeRankProvider(businessTypes)
);
var req = new Request
{
Revenue = 12345,
CompanySizeId = 1,
BusinessTypeId = 1,
};
var priority = _priorityProvider.PriorityOf(req);
//save priority to Database
}
What I am trying to avoid is this inside my controller method:
_priorityProvider = new PriorityProvider(
new RevenueRankProvider(revenues),
new CompanySizeRankProvider(companySizes),
new BusinessTypeRankProvider(businessTypes)
);
So my question is, how do I make this work to follow the whole Dependency Injection process and avoid creating a new instance in the controller?