Reputation: 7719
I have a system where multiple consumers (e.g., pricing calculators) process requests based on specific constraints. Each consumer has different requirements, meaning they only need a subset of the available data. For example:
Eg:
public interface IRequestProcessor
{
double ComputeResult(RequestData request);
}
class ConsumerA : IRequestProcessor
{
public double ComputeResult(RequestData request)
=> 10 * request.SomeValue + request.BaseCost;
}
class ConsumerB : IRequestProcessor
{
public double ComputeResult(RequestData request)
=> (request.SomeCondition ? 10 : 0) * request.SomeValue + request.BaseCost;
}
class ConsumerC : IRequestProcessor
{
public double ComputeResult(RequestData request)
=> request.HasDetail ? 1.5 * request.BaseCost : request.BaseCost;
}
class ConsumerD : IRequestProcessor
{
public double ComputeResult(RequestData request)
=> request.DueDate < DateTime.Now.AddMonths(6)
? -1
: request.HasDetail ? 1.5 * request.BaseCost : request.BaseCost;
}
And the RequestData
class:
class RequestData
{
public double BaseCost { get; } // Used by all Consumers
public double SomeValue { get; } // Used by Consumer A & B
public bool SomeCondition { get; } // Used by Consumer B
public bool HasDetail { get; } // Used by Consumer C & D
public DateTime DueDate { get; } // Used by Consumer D
}
Each time that I add a new consumer, I need to modify RequestData
to introduce new fields. This leads to:
RequestData
class keeps expanding.==> How can I modelize this system so that it fill a better design ?
Although my current implementation is in C#, I welcome any general design pattern or architectural approach to solve this issue.
Upvotes: 0
Views: 56
Reputation: 6801
I like Jeremey Lakeman's suggestion of generics.
You could also try consumer-specific derivatives:
abstract class RequestData {
public double BaseCost { get; } // Used by all Consumers
}
class ConsumerARequestData : RequestData{
public double SomeValue { get; } // Used by Consumer A & B
}
class ConsumerBRequestData : ConsumerARequest {
public bool SomeCondition { get; } // Used by Consumer B
}
class ConsumerCRequestData : RequestData {
public bool HasDetail { get; } // Used by Consumer C & D
}
class ConsumerDRequestData : ConsumerCRequestData {
public DateTime DueDate { get; } // Used by Consumer D
}
However, the cost of this approach is that you have to cast to the specific type in each implementation:
class ConsumerD : IRequestProcessor
{
public double ComputeResult(RequestData request) {
var requestData = (ConsumerDRequestData) request;
// ...
}
}
Upvotes: 0