0

Is it right to overload method in Java interface like below. And then use the method required in your subclass? If not, is there a better way to do it, kindly suggest.

interface IEmployees{
    public List<String> getEmployees(List<String> employees, List<String> departments);
    public List<String> getEmployees(List<String> employees, String name);
} 

class EmployeesByDept implements IEmployees{
    public List<String> getEmployees(List<String> employees, List<String> departments){
        // select employees belonging to depts in list and return.
    }
    public List<String> getEmployees(List<String> employees, String name){
         throw new UnsupportedOperationException();
    } 
}

class EmployeesByName implements IEmployees{
    public List<String> getEmployees(List<String> employees, List<String> departments){
        throw new UnsupportedOperationException();
    }
    public List<String> getEmployees(List<String> employees, String name){
        // select employees with name in list and return.
    }
}
Meena Chaudhary
  • 9,909
  • 16
  • 60
  • 94
  • What do you mean by "is it right"? – Mena Sep 12 '16 at 14:11
  • If only one of the methods is allowed I'd split the interface into two. Besides that if the interface then only contains one method that is implemented by one class you might ask yourself whether that interface is needed or not. – Thomas Sep 12 '16 at 14:13
  • What is an `IEmployees` *supposed* to represent? The answer really depends on that. Is it: 1a) A list of all known employees, 1b) An arbitrary subset of all known employees, or 2) Some organization that has employees? – Jason C Sep 12 '16 at 14:13
  • @Mena from design point of view, an interface with overloaded methods. – Meena Chaudhary Sep 12 '16 at 14:13
  • Think about what that interface would be used for and what would shield the caller from having to know which method is currently supported. It might be better to just provide a method `getEmployees(List employees)` and add additional criteria to the implementation, e.g. via constructor. – Thomas Sep 12 '16 at 14:15
  • @JasonC 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. – Meena Chaudhary Sep 12 '16 at 14:15
  • @thomas i liked your suggestion about keeping only employees argument in method definition. The reason I want to use an interface even when each subclass will use only one method, so I can use polymorphism at runtime. – Meena Chaudhary Sep 12 '16 at 14:20
  • You might want to provide an example of how you'd want to use it. I have the strong feeling that there's a better solution for what you're trying to do in the end. You could try to use some sort of builder hierarchy and let those create the filter or just provide all values that potentially might be combined (like employe ids, departments, name etc.) - we're using the latter approach btw. As I already said, an important question would be: How would the caller decide which method to call/which method is actually implemented based on the interface alone? – Thomas Sep 12 '16 at 14:28
  • @Thomas in case I want my method to be statically used, I will have to set arguments not included in method individually coz now I won't be using a constructor. How about that..? – Meena Chaudhary Sep 12 '16 at 14:29
  • @MeenaChaudhary If you want to provide `static` methods then the discussion of interfaces and polymorphic capabilities is moot. There is no concept of a [static interface method](http://stackoverflow.com/questions/512877/why-cant-i-define-a-static-method-in-a-java-interface). Java 8 adds them but they're not equivalent to what you're describing. – Jason C Sep 12 '16 at 14:33
  • 1
    I'm not sure I understand what you're trying to do. Please add the description as well as some example (might be pseudo code of how you'd like it to use) to your question. What we (or at least I) would need probably doesn't fit into a comment (size and formatting). – Thomas Sep 12 '16 at 14:34
  • I have to concur with Thomas here; your question appeared clear at first but your comments have been muddling it. You should probably go back and edit your question to be more representative of your situation. – Jason C Sep 12 '16 at 14:38
  • This is probably a good candidate for [code Review](http://codereview.stackexchange.com/) – MrBrushy Sep 12 '16 at 15:52

3 Answers3

2

in my opinion overloading an interface this way is not a good idea, as this produces unnecessary/useless code at the implementing class.

I would therefore recommend to write 2 or 3 different interfaces like so

interface IEmployees {
}

interface IEmployeesByDept extends IEmployees {
    public List<String> getEmployees(List<String> employees, List<String> departments);
}

interface IEmployeesByName extends IEmployees {
    public List<String> getEmployees(List<String> employees, String name);
}

This Way you can cleanly implement the interface that matches your case.

DMuenstermann
  • 31
  • 1
  • 3
  • This is another good strategy, if it's appropriate for the application (e.g. derived filters can be divided into the general categories "by name" and "by department" with more than one implementation per category), +1 and also welcome to the site! – Jason C Sep 12 '16 at 14:33
  • 1
    One might argue that an empty `IEmployees` might not be needed here (what would you do with that?) and the names of the specific interfaces indicate there might be only one implementation anyways so even those interface might not be needed but should be the implementations themselves (assuming there aren't multiple implementations of the specific interfaces). – Thomas Sep 12 '16 at 14:37
0

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:

  1. A set of all employees in a system (for example, all of the employees that work on a project or for a company), or
  2. An arbitrary list of employees (includes 1 but also e.g. search results, etc., the semantic equivalent of a List<Employee>, or
  3. 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.

Jason C
  • 38,729
  • 14
  • 126
  • 182
  • Yet another option is an interface that defines just a pass/fail criteria for a single employee, e.g. `interface Filter { public boolean isAcceptable (String employee); }`, and elsewhere you can have a method to apply it by looping through a list and creating a result list, e.g. `public List filterEmployees (List employees, Filter filter) { ... }`. – Jason C Sep 12 '16 at 14:42
0

Your use-case does not warrant the use of an Interface at all

An Interface represents a contract. You defined the contract as being able to fulfill two requirements. If you know you won't be able to provide both parts of the contract, do not use an interface at all.

Additionally, I strongly doubt you have alternative ways of getting these Employees Lists, another reason not to use interfaces.

Alternative solution

I am guessing your IEmployeesXXX classes have no state variable. This is a good indicator that the methods are utility methods which fetch and return a list of objects.

You should make it a classic Utility class, i.e. an abstract final class with static methods.

Here's an example using your own code, wich becomes much cleaner:

public abstract final class Employeesutility{
    public static List<String> getEmployees(List<String> employees, List<String> departments){
        // select employees belonging to depts in list and return.
    }
    public static List<String> getEmployees(List<String> employees, String name){
        // select employees with name in list and return.
    }
}

Notes going forward

I do not like Utility classes much, I would rather make an intermediate class with rich internal representation, and rich collections wich expose your proposed interface methods. But for your use case, this would probably mean duplicate the entire DB (guessing you have one), which would be stupid. Please consider it if ever you decide to create a true Employee class... which you will when your program becomes big enough.

MrBrushy
  • 680
  • 3
  • 17