Search code examples
javaimplements

Is there a necessity or a convention of designing some specific class that invokes the methods in our interface


When we create an interface is it enough just to create the interface? or do we have to design another specific class which invokes the methods of the interface?

Correction on behalf of the previous edition of this question

As pointed in the questions below, when we are designing an interface it is possible to design it with default methods. So in that case we don't need to have some specific class designed to invoke the unimplemented methods of that interface. Because the user can use the interface to invoke those default methods.

So now my question is, when our interface doesn't have any default methods implemented and only have unimplemented methods, do we need to design some specific class/classes that invoke those unimplemented methods, In order to work with that interface/classes that implements our interface?


Solution

  • Interface is primarily intended to declare a contract of what can be done with the objects that will ever implement this interface.

    So when you create an interface you essentially define a capability, a feature of the system by means of declaring a contract.

    Now after you do that, you can decide whether to implement this interface immediately, and in many cases you implement it immediately if this case is an internal part of the system that you're working on now, or in other words the system is "closed" in this particular feature. In this case there can be one single implementation, or many implementations.

    An example for this is if you design some feature, that requires polymorphic behavior. Lets say, you design a "word"-like system (text processor) and you're required to save the document in different formats, so you'll probably end up with something like:

    public interface DocumentSaveHandler {
       void save(Document doc);
    }
    
    public class PdfSaveHandler {
     void save(Document doc) { 
       // save the document in the pdf format
     }
    }
    
    public class TextSaveHandler {
     void save(Document doc) { 
       // save the document in the textual format
     }
    }
    

    Alternatively you can declare the contract that will be implemented later (by you, your co-workers, your future customers if you work on some kind of API, or even auto-generated in build time or during the run-time (auto-generated proxies) )

    For example, take all the functional interfaces that were added in Java 8. These usually play well together with streams (again a feature of Java 8) but the designers of streams opted for providing the interface and they didn't know who and how exactly they will be used. So in this case its a part of the API (open system at this point).

    Another example, let's say you design a library and you specify in the documentation: "In Order to use my library the user must implement the interface XYZ" (and therefor supply an actual implementation of the capabilities provided by the inteface XYZ. In this case again, you define a contract that you by yourself cannot implement because you don't know enough details, hence you supply only the interface without an implementation, but the future users can certainly implement your interface.

    Update

    Due to the OP's comment to my answer:

    You should always try to program to interfaces and not to the implementations. In the example you've raised in the comment, There should be a class that takes a DocumentSaveHandler and not a concrete implementation.

    In runtime the concrete implementation will be passed there but for compilation concrete implementation won't be required.

    Here is an example:

    
    public class Word {
    
       private Map<String, DocumentSaveHandler> handlers; // note its the interface, not an implementation - map of supported types to the actual handler
    
    
       public onSaveButtonPressed(String selectedDocType) {
          Document doc = getDocumentToSave();
          DocumentSaveHandler handler  =  handlers.get(selectedDocType);
          handler.save(doc);
       } 
    }
    
    

    Notice, I've never used a concrete implementation. I've assumed that it will be supplied by the code that will initialize the whole Word text processor. So this code will compile even if there are no real implementations of the DocumentSaveHandler

    This example is slightly complicated, but even in easier cases, where you don't have a map, you still work with interface and not with a real implementation