Enhance Your Design Skills by Understanding Interfaces
Episode 6: Functional Programming and Interfaces
(Last updated: 2024.2.6)
Linux concept image
This article takes about 5 minutes to read!
(If the images appear small, try viewing in landscape mode)
"Interfaces in Functional Programming"
In the previous article, we learned about interfaces in object-oriented programming. This time, let’s explore the role of interfaces in functional programming, which differs in its approach.
[Table of Contents]
Interfaces in Functional Programming
Practical Use Cases
Summary
1. Interfaces in Functional Programming
Functional programming is a programming paradigm that models computation as the evaluation of mathematical functions, avoiding mutable variables and state changes. In this approach, functions are first-class citizens — they can be assigned to variables, passed as arguments to other functions, or returned from functions. Interfaces play a vital role even in this paradigm, though their usage differs from that in object-oriented programming (OOP).
■ Higher-Order Functions and Abstraction
Functional languages use higher-order functions (functions that accept or return other functions) to increase abstraction. Interfaces are often used to define the type of functions passed into these higher-order functions. This clarifies the methods and properties expected of those functions and defines their behavior as a form of contract.
■ Immutability and Pure Functions
Functional programming emphasizes immutability and pure functions (functions without side effects). Through interfaces, input and output types can be defined to enforce purity — ensuring that a function always returns the same output for the same input and does not alter global state.
■ Example of a Functional Interface
Java’s java.util.function package provides a range of functional interfaces supporting functional programming. For example, the Function interface represents a function that takes a T (e.g., String) as input and returns an R (e.g., Integer). In the example below, the Function interface is used to define a function that returns the length of a string. Functional interfaces like this help define function behavior clearly, enhancing code reusability and abstraction.
Functional Interface in Java
Using interfaces in functional programming reinforces abstraction, reusability, and purity. Combined with concepts like higher-order functions, immutability, and pure functions, they allow for the creation of more declarative, comprehensible, and reliable programs. Functional interfaces enable developers to write code at a more abstract level, improving modularity and testability. Furthermore, concepts like immutability and pure functions minimize side effects and contribute to thread safety and concurrency. (For reference, the function length in the example returns 12 because “Hello, World” consists of 12 characters.)
2. Practical Use Cases
Interfaces are applied across many domains in software development to enhance extensibility, maintainability, and testability. Here are three practical use cases: API design, plugin architecture, and dependency injection.
■ API Design
Interfaces play a central role in public API design. By defining API contracts through interfaces, developers can change the API implementation while keeping the usage code unchanged. This allows independent evolution of different system components.
The example below defines a simple API for payment processing. Different payment providers can implement this interface, allowing the application to process payments without being tied to a specific provider.
Interface for Payment Processing (Java)
■ Plugin Architecture
Interfaces are also used to build plugin architectures. An application can load plugins that implement a specific interface and integrate their functionality at runtime.
In the example below, all plugins implementing the IPlugin interface can be loaded, and their Execute method can be called when specific events occur. This enables dynamic extension of application features.
Plugin Interface Example (Java)
■ Dependency Injection
Dependency injection is a technique for managing dependencies between application components. Interfaces define how components interact during this process.
In the example below, the CustomerService class depends on the CustomerRepository interface. The actual repository implementation is provided at runtime through dependency injection. This makes it easy to swap out implementations and greatly improves testability. Since CustomerService does not need to know the details of a specific CustomerRepository, it communicates through the interface. This is especially useful in writing unit and integration tests, where mock objects or stubs can simulate repository behavior without relying on real data sources.
Interface in Dependency Injection (Java)
Moreover, dependency injection increases application flexibility and makes reconfiguration or feature extensions easier. For instance, to support a new type of data storage, all that’s needed is to create a new implementation of CustomerRepository and change the application’s settings to inject it. This allows the system to meet new requirements without modifying existing code.
Using dependency injection keeps components loosely coupled and improves code reusability. Independent components are easier to test and reuse, and software maintainability is enhanced, making it easier to add new features or update existing ones efficiently.
3. Summary
In this article, we explored the concept of interfaces in functional programming and introduced three practical use cases: API design, plugin architecture, and dependency injection. These use cases are commonly seen in real-world applications and are worth studying further. Among them, dependency injection is particularly important in modern software development, improving testability, code flexibility, and reusability. It helps developers maintain a cleaner and more manageable codebase while enabling their applications to grow and evolve. Due to its usefulness, this pattern is widely used across frameworks in languages like C#, Node.js, and PHP. It’s definitely a skill worth mastering.
▼ References
"Chouzetsu Software Design Introduction — Understanding OOP Through PHP", Gijutsu-Hyoron Publishing, Hisateru Tanaka
Implementing Plugin Features in C#, One Step Ahead
Summary of Dependency Injection Patterns, Zenn