Exploring the Factory Method Design Pattern — Searching Algorithms

Nitish Singh
5 min readNov 6, 2023

--

In software development, it’s important to have Searching algorithms that are efficient and optimized for performance. There are different types of Searching algorithms, such as linear and binary search, and the choice between them depends on the nature and organization of the data being searched. To ensure that the code is clean and organized, we can follow the Single Responsibility Principle (SRP), which means that each class should have only one responsibility. In the case of Searching algorithms, this means creating separate classes for each type of search.

To make it easier to create instances of these algorithms, we can use a factory pattern. This pattern provides a structured and extensible approach to creating objects, allowing for flexibility in the future. An enumeration is useful in this context, as it allows us to define a set of named constants, which can be used to represent the different types of search algorithms.

By combining these principles, we can create a comprehensive and adaptable framework for search algorithms that balances efficiency and elegance. This approach not only enhances modularity but also lays the groundwork for seamlessly extending the system to accommodate new search strategies in the future.

Linear Search

Linear search, also known as the sequential search algorithm, is the most basic searching algorithm. With linear search, the entire list is traversed and each element is compared with the item whose location is being sought. If a match is found, the location of the item is returned; otherwise, the algorithm returns NULL.

This method is commonly used to search for an element within an unsorted list. The worst-case time complexity of linear search is O(n).

Time Complexity of Linear Search:

Time Complexity of Linear Search:

  • Best Case: O(1)
  • Average Case: O(n)
  • Worst Case: O(n)

Binary Search

Binary search is an efficient search technique that operates on sorted lists. It follows the divide and conquer approach by dividing the list into two halves and comparing the item with the middle element of the list. If a match is found, the location of the middle element is returned. Otherwise, the search continues in either of the halves, based on the result produced through the match. It’s important to ensure that the list is sorted before using binary search to search for an element.

The time complexity of Binary Search is as follows:

  • Best Case: O(1) — Occurs when the element being searched is found in the first comparison, i.e., when the first middle element itself is the element to be searched.
  • Average Case: O(logn) — Represents the average time complexity of Binary search.
  • Worst Case: O(logn) — Occurs when we have to keep reducing the search space until it has only one element.

The space complexity of Binary Search is O(1), indicating that the amount of memory used by the algorithm is constant and does not depend on the size of the input.

Factory Pattern and Enumeration for Search Algorithms

Enumeration for Search Algorithms:
Enums, or enumerations, are commonly employed when a variable is expected to select one value from a predefined set of possible values. Their use enhances abstraction, allowing developers to concentrate on the values themselves rather than the storage mechanism. Additionally, enums are beneficial for code documentation and readability.

In this scenario, we have two potential search algorithms, so let’s define enums for them.

Abstract Base Class for Search Algorithms:
An abstract class serve as representations of general concepts from which more specific classes can be derived. It is not possible to create an object of an abstract class type, but pointers and references to abstract class types can be utilized. To create an abstract class, we declare at least one pure virtual member function using the pure specifier (= 0) syntax. Classes derived from the abstract class must implement the pure virtual function, or they, too, will be abstract classes.

Pure virtual functions in abstract classes cannot have an implementation in the abstract class itself. They must be implemented in the derived classes. When using pure virtual functions, you can only call them using the fully qualified syntax.

Let’s defines a common interface for search algorithms, ensuring a unified structure for our factory pattern:

Factory Pattern Implementation

Creating the SearchAlgorithmFactory:
The `SearchAlgorithmFactory` class utilizes the enumeration to create instances of the appropriate search algorithms, adhering to the principles of the factory pattern:

Utilizing the Search Algorithms with Factory Pattern

Now, let’s revisit the orchestration of these search algorithms based on the nature of the data within a `main` function:

Advantages and Considerations

Advantages of Factory Pattern and Enumeration:

1. Modularity: Each search algorithm resides in its own class, fostering a modular design that is easy to understand, maintain, and extend.

2. SRP Compliance: Adhering to the Single Responsibility Principle ensures that each class has a specific responsibility, preventing changes to one algorithm from affecting another.

3. Encapsulation: Internal details of each search algorithm are encapsulated within its class, shielding the complexity and facilitating clean interactions.

4. Readability: The code becomes more readable and self-explanatory, enhancing collaboration and comprehension among developers.

Considerations and Usage Scenarios:

1. Data Nature: Opt for the appropriate search algorithm based on the nature of the data, considering factors such as sorting and efficiency.

2. Performance Trade-offs: Understand the performance characteristics of each search algorithm and choose accordingly based on the size and characteristics of the dataset.

3. Extensibility: The modular structure allows for the seamless addition of new search algorithms in the future, promoting codebase extensibility.

4. Testing: Each search class can be tested independently, ensuring the robustness of individual algorithms.

Conclusion

In conclusion, creating separate classes for search algorithms using a factory pattern and enumeration results in a codebase that is easy to understand, test, and extend. This approach ensures that each algorithm has only one responsibility, making the code clean and organized. With this modular approach, developers can choose between different types of search algorithms, such as LinearSearch and BinarySearch, depending on the type of data being searched. This brings efficiency and modularity to the codebase, resulting in a balance of simplicity and sophistication.

More Read

Please read the full implementation of the factory design pattern for the search algorithm using the provided link.

This implementation is allowed for easy addition of interpolation search method. Please follow the link for complete implementation.

To Understand the difference between Abstract Classes and Interfaces in C++, please follow the link.

Factory Method Pattern: Case conversion in C++, please us ethe following link.

--

--

Nitish Singh
Nitish Singh

Written by Nitish Singh

Passionate about empowering devs with practical tips, using modern C++ as the tool, and up-to-date knowledge. Join me on Medium for engaging articles.

No responses yet