How would you describe the Filter pattern in C ? (Question For - Junior Level Developer)

Question

How would you describe the Filter pattern in C ? (Question For – Junior Level Developer)

Brief Answer

Brief Answer: Filter Pattern in C#

The Filter (or Criteria) pattern is a behavioral design pattern that lets you define a set of criteria and apply them to a collection of objects to select a matching subset. Its primary strength lies in decoupling the object selection logic from the objects themselves.

How it Works:

  • Criteria Interface (e.g., ICriteria<T>): Defines a common method (like MeetCriteria) that all filters must implement. This enables polymorphism, treating different filters uniformly.
  • Concrete Criteria Classes: Implement the interface, encapsulating specific filtering rules (e.g., CategoryCriteria for products).
  • Filter Application: A mechanism iterates through the collection, applying the chosen filter(s).

Key Benefits (Good to Convey):

  • Decoupling & Flexibility: Separates “what to filter” from “how to filter,” allowing you to add new criteria without modifying core object classes.
  • Extensibility & Maintainability: New filters are easily added by creating new concrete criteria classes, adhering to the Open/Closed Principle (open for extension, closed for modification). This makes code easier to test and maintain.
  • Real-World Example: Filtering a list of products in an e-commerce application by category, price, or brand. Different filters can be combined or used independently without complex if-else chains.

In C#, this often involves using interfaces and generics (ICriteria<T>) with List<T> collections.

Super Brief Answer

Super Brief Answer: Filter Pattern in C#

The Filter pattern is a behavioral pattern used to select a subset of objects from a collection based on defined criteria. It decouples the filtering logic from the objects.

It achieves this by using a common ICriteria interface for specific filter implementations. This promotes flexibility and extensibility, allowing new filters to be added easily (Open/Closed Principle).

A common example is filtering products in an e-commerce system by category or price.

Detailed Answer

The Filter design pattern (also known as the Criteria pattern) is a behavioral design pattern that allows you to define a set of criteria (filters) and apply them to a collection of objects to select a subset that matches those criteria. Its core strength lies in promoting loose coupling by separating the object selection logic from the objects themselves, making your code more flexible and maintainable.

Key Concepts & Related Terms

Behavioral Patterns, Data Filtering, Criteria-Based Selection, Object Decoupling, Polymorphism, Open/Closed Principle.

Core Principles of the Filter Pattern

The Filter pattern achieves its goals through a few key components and principles:

  1. Criteria Interface

    This interface declares a common method that each concrete filter must implement (e.g., MeetCriteria). This ensures all filters have a consistent way of checking if an object meets their specific criteria. The interface acts as a contract, enabling polymorphism, which means you can treat different filter types uniformly, simplifying the code that applies the filters.

  2. Concrete Criteria Classes

    These classes implement the criteria interface and contain the actual filtering logic. For instance, a CategoryCriteria class would implement the interface, and its MeetCriteria method would check if a product’s category matches the desired value. Each concrete criteria class encapsulates a specific filtering rule.

  3. Filter Application Mechanism

    This part of the pattern handles the process of iterating through the collection of objects and applying the chosen filter(s). It decouples the filtering process from the objects being filtered and the filter criteria themselves. This could be as simple as a loop that calls the filter’s method for each object in the collection.

  4. Enhanced Flexibility and Extensibility

    Because of the decoupling provided by the interface, you can introduce new filters simply by creating a new class that implements the criteria interface. No changes are needed to the core objects, the collection, or the filtering application logic. This makes the codebase more maintainable and adaptable to changing requirements. It’s easier to test individual filters, and adding new filtering options doesn’t risk breaking existing functionality. It’s a practical example of the Open/Closed Principle — open for extension, closed for modification.

Interview Preparation Tips

When discussing the Filter pattern in an interview, consider these points:

  • 1. Emphasize Decoupling

    Highlight that decoupling is a key advantage. Explain how the Filter pattern allows you to add new filtering criteria without modifying the core object classes or the collection processing logic. Use a relatable example, like filtering Product objects in an e-commerce system by various criteria. Each criterion is encapsulated in its own class, keeping the Product class clean.

  • 2. Provide a Real-World Example

    An example like filtering products in an e-commerce application (by price range, brand, category, etc.) is highly effective. Mention how different filters can be combined (e.g., “Electronics AND Price < $500”) or used independently. Explain how this flexibility is achieved without creating a tangled mess of if-else statements.

  • 3. Highlight Maintainability and Extensibility

    Explain that adding a new filter (e.g., a “Size” filter) is straightforward: simply create a new SizeCriteria class implementing the common interface. No changes are required elsewhere in the system. This significantly improves maintainability and extensibility, making individual filters easier to test and reducing the risk of breaking existing functionality when new features are added. Connect this directly to the Open/Closed Principle.

C# Code Example

Here’s a simplified C# example demonstrating the core components of the Filter pattern:


// Example C# structure for Filter Pattern

// 1. Criteria Interface
public interface ICriteria<T>
{
    List<T> MeetCriteria(List<T> items);
}

// 2. Concrete Criteria Classes
public class Product
{
    public string Name { get; set; }
    public string Category { get; set; }
    public decimal Price { get; set; }
}

public class CategoryCriteria : ICriteria<Product>
{
    private string _category;

    public CategoryCriteria(string category)
    {
        _category = category;
    }

    public List<Product> MeetCriteria(List<Product> items)
    {
        List<Product> filteredItems = new List<Product>();
        foreach (var item in items)
        {
            if (item.Category.Equals(_category, StringComparison.OrdinalIgnoreCase))
            {
                filteredItems.Add(item);
            }
        }
        return filteredItems;
    }
}

// 3. Filter Application (Example Usage)
public class ProductFilterer
{
    public List<Product> Filter(List<Product> products, ICriteria<Product> criteria)
    {
        return criteria.MeetCriteria(products);
    }

    // Example of combining criteria (e.g., using And/Or patterns for composite filters)
    // For brevity, composite filters like AndCriteria or OrCriteria are not shown here.
}

// How to use the Filter Pattern:
/*
List allProducts = new List
{
    new Product { Name = "Laptop", Category = "Electronics", Price = 1200m },
    new Product { Name = "Smartphone", Category = "Electronics", Price = 800m },
    new Product { Name = "Desk Chair", Category = "Furniture", Price = 150m },
    new Product { Name = "Headphones", Category = "Electronics", Price = 100m }
};

ICriteria electronicsCriteria = new CategoryCriteria("Electronics");
ProductFilterer filterer = new ProductFilterer();
List electronics = filterer.Filter(allProducts, electronicsCriteria);

Console.WriteLine("Electronics Products:");
foreach (var product in electronics)
{
    Console.WriteLine($"- {product.Name} ({product.Category}, ${product.Price})");
}
*/