In this article, we will discuss the best practice of coding to an interface, not to an implementation, with an example. Always program to an interface, not an implementation; this leads to flexible code that can work with any new implementation of the interface. This principle is advised in many Java books, including "Effective Java" and "Head First Design Patterns".
Check out the Java Best Practices series at Java Best Practices.
Video
The code for the "Interface, not for implementation" best practice is well explained in the video tutorial below:
Code: Program for Interface, Not for Implementation
Let's create a Shape
interface with multiple implementations, such as Circle
, Rectangle
, and Square
.
interface Shape {
void draw();
}
class Circle implements Shape {
@Override
public void draw() {
System.out.println("Drawing circle ...");
}
}
class Rectangle implements Shape {
@Override
public void draw() {
System.out.println("Drawing rectangle ...");
}
}
class Square implements Shape {
@Override
public void draw() {
System.out.println("Drawing square ...");
}
}
Here, we use the interface as the reference type and method argument:
public class Test {
public static void main(String[] args) {
Shape shape = new Circle();
print(shape);
}
private static void print(Shape shape) {
shape.draw();
}
}
Output:
Drawing circle ...
With the "code for interface, not for implementation" technique, you can change the implementation anytime without changing the existing code. For example, we can change from Circle
to Square
:
Shape shape = new Square();
Code for Interface, Not for Implementation in Collections Framework
1. Always use interface type as a reference type.
Example:
// Better
List<String> list = new ArrayList<>();
// Avoid
ArrayList<String> list = new ArrayList<>();
// Better
Set<String> set = new HashSet<>();
// Avoid
HashSet<String> employees = new HashSet<>();
// Better
Map<String, String> map = new HashMap<>();
// Avoid
HashMap<String, String> map = new HashMap<>();
By declaring a collection using an interface type, the code is more flexible as you can change the concrete implementation easily when needed, for example:
List<String> list = new LinkedList<>();
When your code is designed to depend on the List
interface, you can swap among List’s implementations with ease without modifying the code that uses it.
2. Always use the interface type as a return type.
Example:
public Collection<Employee> listEmployees() {
List<Employee> employees = new ArrayList<>();
// add Employees to the list
return employees;
}
3. Always use Interface Types as a method argument.
Example:
public void foo(Set<Integer> numbers) {
}
The flexibility of using interface type for a collection is more visible in the case of the method’s parameters.
Conclusion
Coding to an interface, not an implementation, is a crucial best practice in Java that promotes flexibility and maintainability in your codebase. This approach ensures that your code can easily adapt to new implementations without significant changes.
Check out more Java best practices series at Java Best Practices.
Java Best Practices
- Java Standard Naming Conventions
- Java Exception Handling Best Practices
- Java Synchronization Best Practices
- String Best Practices in Java
- Java Collection Framework Best Practices
- Secure Coding Standards for Java Serialization
- JUnit Framework Best Practices
- Java Generics Best Practices
- Java Enums and Annotations Best Practices
Comments
Post a Comment
Leave Comment