oopdesign-patternsobject-oriented-analysissystem-designarchitectural-patterns

Should We use NullValueFilter in Intercept Design Pattern Implementation?


I have a List of campaigns that need to be processed via different kinds of filters for e.g., Platform Filter, Application Filter, CampaignRunning Filter to check if the current date should be between Start Date and End Date etc.

There are ideally 15 - 20 different filters, and I am managing them using Intercept Design Pattern.

before applying filters List could be empty, so should I use NullValueFilter in the filter chain?

after applying some filters list again can be empty, to check that also should I inject the same null or empty check strategy using the strategy design pattern?

I usually think more on designing perspective to manage such cases. I want to know if I am thinking in the right direction or maybe I am overengineering on that part.

Some pseudo code to illustrate the scenario -

Class NullValueFilter : IFilter {
  Execute(List<CampaignList> campaignList) {
    if(campaignList != null && campaignList.Count == 0) {
         return false;
    }
    return true;
  }
}

Class PlatformFilter : IFilter {
  Execute(List<CampaignList> campaignList) {
    if(campaignList != null && campaignList.Count == 0) {
         return false;
    }
    campaignList = campaignList.Where( x => x.Platform == 'Mobile');
    return true
  }
}

Class CampaignRunningFilter : IFilter {
  Execute(List<CampaignList> campaignList) {
    if(campaignList != null && campaignList.Count == 0) {
         return false;
    }
    // first Fetch campaign start date and end date 
    
    campaignList = campaignList.Where( x => x.startdate <= curr_date && x.enddate >= curr_date);
    return true
  }
}

I can think of two options here -

  1. create a filterbase class that can manage null and empty check for list.
  2. inject null value filter instance in each filter using constructor injection and call that null and empty check method.

Solution

  • For 15 up to 20 filters, I would simply not do any checks for the empty list, that makes things more complicated than necessary without any noteable benefit.

    Each filter behaves perfectly consistent when it passes an empty list just through, so I don't see any compelling reason why this premature optimization of "breaking the chain" is necessary. The most cleanest design is IMHO the one where we have thrown any unneccesary waste over board, so this is what I would start with.

    However, if you really notice measureable, relevant performance improvement by stopping the processing at the empty list, I would not let the filters test for this case. Instead, let the caller test it directly, instead of checking a boolean return code. I would recommend to make the Execute method return the filtered list, and do implement it along the lines of this snippet:

     List<Campaign> campaignList = ...;  // init this here
     foreach(IFilter filter in GetActiveFilters)
     {
          if(campaignList==null || campaignList.Count == 0)
              break;
          campaignList = filter.Execute(campaignList);
     }
    

    This way, there is only one place in the code where the empty-list test needs to be implemented, and you don't have to repeat this in the filters over and over again.