Which design pattern suitable to fetch same type of data from multiple sources, club them into a single unit and applying multiple filters

Viewed 286

I have two products, Product A and Product B. Product A has a list of Campaigns created using M database calls and Product B also has a list of campaigns created by separate N database calls.

Important Point to be noted - Some calls are common between M and N.

Now for Product A we call the list of M Database calls and combine them into a single list and vice versa for Product B.

Now we want to apply a list of X Filters on Product A and a list of Y Filters on Product B in order to get filtered list of Product A campaigns or Product B campaigns depending on the client's call for a particular Product.

What do you suggest, how should we approach it for the design of the system? Any suggestions or link or reference to guide me in the right direction would be greatly appreciated.

2 Answers

Can we Use Factory Method here? we can decide the Product which we want to create on runtime and also the filters which we want to apply to the product on runtime. this way if we want to add new products or new filters we can easily add them without making changes to the existing products or filter

https://refactoring.guru/design-patterns/factory-method

I think composition is the key word here. You could have a CampaignsProvider interface that's implemented by multiple 'sources' like API1CampaignsProvider, API2CampaignsProvider, InMemoryCacheCampaignsProvider, etc.

interface CampaignsProvider {
  func campaignsForProduct(product: Product) -> [Campaign]
}

Then you could have a class that composes all the providers like so:

class CampaignsProviderComposer: CampaignsProvider {
   let providers: [CampaignsProvider]
   init(providers: [CampaignsProvider]) {
      self.providers = providers
   }

   func campaignsForProduct(_ product: Product) -> [Campaign] {
       var allCampaings: [Campaign] = []
       providers.forEach { p in
           allCampaigns.appendAll(p.campaignsForProduct(product))
       }
   }
}

Then just compose with all different sources

var productA = Product(name: "A")
let campaignsProviderA = CampaignsProviderComposer(providers: [
   Api1CampaignsProvider(),
   Api2CampaignsProvider()
])
productA.campaigns = campaignsProvider.campaignsForProduct(productA)

var productB = Product(name: "B")
let campaignsProviderB = CampaignsProviderComposer(providers: [
   Api3CampaignsProvider(),
   Api4CampaignsProvider()
])
productB.campaigns = campaignsProvider.campaignsForProduct(productB)

As for filtering, a similar approach could be taken, having a CampaignsFilter interface, and have different implementations with different dependencies for different products

Related