admin管理员组

文章数量:1302406

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:

  • Consumer A relies heavily on one particular field.
  • Consumer B has constraints related to the same field as Consumer A plus an other one.
  • Consumer C ignores most fields but considers another aspect important.
  • Consumer D rejects certain requests outright based on a condition.

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:

  1. Growing complexity : The RequestData class keeps expanding.
  2. Unused data : Most consumers only require a subset of the fields, making it inefficient.

==> 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.

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:

  • Consumer A relies heavily on one particular field.
  • Consumer B has constraints related to the same field as Consumer A plus an other one.
  • Consumer C ignores most fields but considers another aspect important.
  • Consumer D rejects certain requests outright based on a condition.

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:

  1. Growing complexity : The RequestData class keeps expanding.
  2. Unused data : Most consumers only require a subset of the fields, making it inefficient.

==> 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.

Share Improve this question asked Feb 10 at 19:43 TotoToto 7,71919 gold badges51 silver badges72 bronze badges 8
  • "Unused data : Most consumers only require a subset of the fields, making it inefficient." - can you please elaborate, currently it is not very clear where the inefficiency comes from. How the consumers get the data? How many times the data is fetched? – Guru Stron Commented Feb 10 at 19:53
  • IMHO don't. Each consumer should define their own parameter data type. You could add a generic parameter; IRequestProcessor<T>{ double ComputeResult(T request); } but even that smells. – Jeremy Lakeman Commented Feb 11 at 0:36
  • The inefficiency is coming from that when a consumer need a new information, I update the RequestData with a need property. As result : 1/ every consumer now sees this property that is useless for them 2/ this leads to confusion 3/ there is potential unwanted side effect 4/ what if a data needs to be hidden to others consumer ? 5/ what if a consumer need to change an int property into double ? – Toto Commented Feb 12 at 1:03
  • Why do you want a single RequestData class? What is the problem to define a request data class per request processor? – Peter Csala Commented Feb 17 at 15:08
  • @PeterCsala, ideally I would like to have the same request sent to all processor. Having something like : void HandleIncomingRequest(Request request){ var minPrice = this.processor.Min(p=>p.ComputeResult(request));)} – Toto Commented Feb 17 at 19:16
 |  Show 3 more comments

1 Answer 1

Reset to default 0

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;

        // ...
    }
}

本文标签: cHow to avoid expanding a Request class when adding new consumersStack Overflow