Home > Enterprise >  Filtering list violates open–closed principle
Filtering list violates open–closed principle

Time:05-17

I wrote a method that filters list by parameters, it works pretty good. But I'm worried about violation of "open–closed principle".

Open–closed principle states that "software entities (classes, modules, functions, etc.) should be open for extension, but closed for modification"

Currently if I want to add one more filter I need to modificate Params class and Filter method.

I want to ask how to refactor these entities to be extendible? or maybe it's dumb question and I don't need to refactor here anything? I'll appreciate any thoughts of this.

Filtering method:

public IEnumerable<Meeting> Filter(Params params)
{
    IEnumerable<Meeting> selectedMeetings =  new List<Meeting>(_dataContext.Meetings);

    if (request.Description is not null)
        selectedMeetings = selectedMeetings.GetByDescription(request.Description);

    if (request.Name is not null)
        selectedMeetings = selectedMeetings.GetByResponsiblePerson(request.Name);

    if (request.Category is not null)
        selectedMeetings = selectedMeetings.GetByCategory(request.Category);

    if (request.Type is not null)
        selectedMeetings = selectedMeetings.GetByType(request.Type);

    if (request.StartDate is not null)
        selectedMeetings = selectedMeetings.GetByStartDate(request.StartDate);

    if (request.EndDate is not null)
        selectedMeetings = selectedMeetings.GetByEndDate(request.EndDate);
           
    if (request.AttendeeCount is not null)
        selectedMeetings = selectedMeetings.GetByAttendeesCount(request.AttendeeCount);

    return selectedMeetings;
}

Params class:

 public class Params
    {
        public string? Description { get; set; }
        public string? Name { get; set; }
        public string? Category { get; set; }
        public string? Type { get; set; }
        public string? StartDate { get; set; }
        public string? EndDate { get; set; }
        public string? AttendeeCount { get; set; }
    }

CodePudding user response:

If you want the filtering logic to be extensible, you could create a base class for filter criteria:

public abstract class FilterCriteria 
{
  IEnumerable<Meetings> Filter(IEnumerable<Meetings> meetings, string input);
}

For each criteria, you'd create a class that derives from FilterCriteria, e.g.:

public class DescriptionFilterCriteria : FilterCriteria
{
  public override IEnumerable<Meetings> Filter(IEnumerable<Meetings> meetings, string input)
  {
    return meetings.GetByDescription(input);
  }
}

Your Filter method would receive a list of filters instead of a Params instance and loop over it:

public List<Meetings> Filter(IEnumerable<FilterCriteria> criteria)
{
    IEnumerable<Meetings> selectedMeetings = new List<Meetings>(_dataContext.Meetings);

    foreach (var crit in criteria)
      selectedMeetings = crit.Filter(selectedMeetings, input);

    return selectedMeetings;
}

If you need to create another filter criteria, you derive a new class from FilterCriteria; you do not have to change Params and the global Filter method anymore.

  • Related