Well, yes and no, it depends.
In general there are most certainly cases for it, where appropriate.
In your case though, probably not, and a lot of your issue comes down to more fundamental design problems. So just by reading your snippet it appears the possibilities are that an IEmployees
is:
- A set of all employees in a system (for example, all of the employees that work on a project or for a company), or
- An arbitrary list of employees (includes 1 but also e.g. search results, etc., the semantic equivalent of a
List<Employee>
, or
- A construct that has a list of employees associated with it (for example, a project, or an organization).
But you say:
it is actually an employee filter class. It will be inherited by other filter classes and will implement any one of the overloaded methods in the interface.
So your first minor problem is the interface name itself. IEmployees
leaves a lot up in the air, but if you name it something more self-documenting and descriptive, e.g. IEmployeeFilter
, then things start to come together a little more obviously.
So now you have a "filter", and it appears you are trying to have multiple separate filter strategies:
- By department
- By employee name
- Possibly others
These are separate filters, and you state your interface defines a filter, and therefore these are more appropriately organized as two separate subclasses.
So first of all the interface should be what is common to all filters. How the filtering is done is not the common aspect. The filtering itself is. So consider:
interface IEmployeeFilter {
public List<String> getEmployees (List<String> employees);
}
Now you have a filter that makes sense, a single common method, and everything else falls into place, e.g.:
class EmployeeNameFilter implements IEmployeeFilter {
private String name;
public EmployeeNameFilter (String name) {
this.name = name;
}
@Override
public List<String> getEmployees (List<String> employees) {
return employees filtered appropriately
}
}
And:
class EmployeeDepartmentFilter implements IEmployeeFilter {
private List<String> departments;
public EmployeeDepartmentFilter (List<String> departments) {
departments = new ArrayList<String>(departments);
}
@Override
public List<String> getEmployees (List<String> employees) {
return employees filtered appropriately
}
}
Etc. Then when you're ready to use one the interface is always the same:
List<String> employees = ...;
IEmployeeFilter filter = new EmployeeNameFilter("bob"); // or...
// IEmployeeFilter filter = new EmployeeDepartmentFilter(...);
List<String> results = filter.getEmployees(employees); // <- interface always the same
Point is, interfaces exist as a tool to make a job easier. When you run into a situation where you have a bunch of classes implementing that interface but they all implement different parts of it, you're starting to defeat the purpose of an interface, and it's a good hint that there's a fundamental change that needs to be made in your design.
That is, a more general rule of thumb can be: If your interface is making your job harder, or making your code more complicated, you've done something wrong. Otherwise, you've done something right.
Hope that made sense.