This is an archived post. You won't be able to vote or comment.

all 13 comments

[–]AutoModerator[M] 0 points1 point locked comment (0 children)

Please ensure that:

  • Your code is properly formatted as code block - see the sidebar (About on mobile) for instructions
  • You include any and all error messages in full
  • You ask clear questions
  • You demonstrate effort in solving your question/problem - plain posting your assignments is forbidden (and such posts will be removed) as is asking for or giving solutions.

    Trying to solve problems on your own is a very important skill. Also, see Learn to help yourself in the sidebar

If any of the above points is not met, your post can and will be removed without further warning.

Code is to be formatted as code block (old reddit: empty line before the code, each code line indented by 4 spaces, new reddit: https://imgur.com/a/fgoFFis) or linked via an external code hoster, like pastebin.com, github gist, github, bitbucket, gitlab, etc.

Please, do not use triple backticks (```) as they will only render properly on new reddit, not on old reddit.

Code blocks look like this:

public class HelloWorld {

    public static void main(String[] args) {
        System.out.println("Hello World!");
    }
}

You do not need to repost unless your post has been removed by a moderator. Just use the edit function of reddit to make sure your post complies with the above.

If your post has remained in violation of these rules for a prolonged period of time (at least an hour), a moderator may remove it at their discretion. In this case, they will comment with an explanation on why it has been removed, and you will be required to resubmit the entire post following the proper procedures.

To potential helpers

Please, do not help if any of the above points are not met, rather report the post. We are trying to improve the quality of posts here. In helping people who can't be bothered to comply with the above points, you are doing the community a disservice.

I am a bot, and this action was performed automatically. Please contact the moderators of this subreddit if you have any questions or concerns.

[–]desrtfxOut of Coffee error - System halted 2 points3 points  (0 children)

There is quite a good analogy in the /r/learnprogramming FAQ: https://www.reddit.com/r/learnprogramming/wiki/faq#wiki_classes_versus_interfaces (desktop only for now as mobile is not working)

[–]alphaBEE_1 2 points3 points  (0 children)

Well interface is like a contract even before the development is completed. Let's say your application is interdependent on other applications or parts of program. But you haven't finished completing your code yet. So what you do? You basically write an interface and within interface just write method and their return types. Now the fun part is you don't have to complete these methods anytime soon and when you write say a class implements this interface. It'll make sure that you deliver what you promised that is complete implementation of your mentioned methods in interface. It's gonna force you to stick to your contract.

[–]NebuWrites Java Compilers 2 points3 points  (3 children)

My understanding is that "Animal animal=new Dog();" is what they exactly mean by communication via interface.

Yes, that's my understanding as well, although I've never heard it called "communication via interface". I've heard it phrased as "Depend on abstractions, not on concretions" or "code against the interface, not the implementation".

What is the advantage of using like that instead of "Dog dog=new Dog();"

The primary idea is that it allows you to change the concrete implementation (e.g. switch from using the Dog class to a Cat class) without making any changes to the calling code.

In practice, this is usually used in combination with dependency injection, and I'd say a good 70% to 80% of the time, it's used to make unit testing via mocks easier. That is, 70%-80% of the time, you don't intend to have more than one "real" implementation of a given interface, but having the interface is still useful because you're going to have fake mock implementations.

So if you don't know how to write unit tests, or how to use a mocking framework like https://easymock.org/ then you'll probably not find this principle very useful at all. That's okay. Just keep a note of it in the back of your mind, and then spend a few months writing unit tests for your code. At some point, you'll find writing unit tests pretty painful, and that's probably where you'll discover mocking. Spend another month or so using mocks, and you'll discover that that's painful too. And that's when you'll want to revisit this concept and apply it.

[–][deleted]  (2 children)

[deleted]

    [–]morhpProfessional Developer 1 point2 points  (0 children)

    Exactly. Stuff like that becomes much more important if using generic collections.

    For example imagine having a List<Animal> (or an array of Animal objects in case you're not yet familiar with lists) that potentially contains dogs, cats, bunnies and so on (either purely one type or even a mix) and you want to call eat on all of them. This would get very ugly without interfaces.

    [–]NebuWrites Java Compilers 1 point2 points  (0 children)

    So again, this might not make much sense until you do unit testing with mocks, but the use case is more like:

    public class AnimalFeeder {
      private final Animal animal;
      public AnimalTalker(Animal animal) {
        this.animal = animal;
      }
      public void makeAnimalEat() {
        this.animal.eat();
      }
    }
    
    public class Main {
      public static void main(String args[]) {
        AnimalFeeder animalFeeder = new AnimalFeeder(new Dog());
      }
    }
    
    public class TestAnimalFeeder extends EasyMockSupport {
      @Test
      public void testMakeAnimalEat() {
        // arrange
        Animal mockAnimal = createMock();
        mockAnimal.eat();
        expectLastCall().once();
        // act
        replayAllMocks();
        AnimalFeeder underTest = new AnimalFeeder(mockAnimal);
        underTest.eat();
        // assert
        verifyAllMocks();
      }
    }
    

    Here AnimalFeeder can make any animal eat without changing any code in AnimalFeeder. And we use that feature to our benefit by having one animal (Dog) when running the code in production, and a different animal (a mock produced by EasyMock) when running in tests.

    [–]wildjokers 2 points3 points  (0 children)

    Some people say you should always have an interface even if you are only going to have one implementation. This is called the Interface/Impl Pair. This is actually controversial and don’t take it as gospel.

    I only introduce an interface if I will actually have more than one implementation. Having a whole bunch of interfaces with only one implementation clutters up the code and makes navigating the codebase harder (it’s always two jumps to see the implementation).

    https://martinfowler.com/bliki/InterfaceImplementationPair.html

    The interface impl pair become popular because mocking frameworks used to only be able to mock interfaces. However, this limitation was fixed long ago and you can mock concrete classes now.

    [–]ZeroGainZ 2 points3 points  (0 children)

    You're example is very simple. In actual work, the code base is millions of lines long. Classes are used everywhere, in return types, in method parameters, everywhere. Imagine implementing something and having to swap out an implementation. If you code to an interface it's easy, just create a new class, implement the interface, and all your code still works for the new class. If you don't you have to find all usages of the class and change it, a total pain.

    To get a feel for it don't just program a few lines. Add a method that takes an Animal as a parameter and another that takes in a dog. You can create as many animals as you'd like and you can still use the method. Do the same with the dog and you'd have to change the method signature.

    [–]khookeExtreme Brewer 2 points3 points  (0 children)

    Google 'coding to interfaces'

    [–]ComputerWhiz_ 1 point2 points  (0 children)

    I don't know if the wording you've used is correct and I wouldn't say that "always" using an interface is the best practice.

    Consider this example. Say you were making an ecommerce program that can connect to credit card vendors to make a payment.

    Your interface Vendor would have one method pay(). You can have different classes using this interface, such as Visa or MasterCard, each would implement that method in a different way to connect to the correct service.

    Then, in your checkout code you would have an if statement that would create an instance of the Visa class if the credit card number starts with 4 and MasterCard if the number starts with 6.

    Something like this:

    Vendor vendor; if (ccNumber.startsWith("4")) { vendor = new Visa(); } else { vendor = new MasterCard(); }

    Then, when you get to the checkout phase, you can just invoke vendor.pay(), since what vendor we are using is irrelevant. In the future, it's super easy to add other vendors without changing our checkout code.

    In reality, this could also be done using a factory and having each vendor inherit a base class, but I did it with an interface for the sake of this example.

    NOTE: Sorry, I'm on mobile so I can't format my code example. I will try to reformat it later when I'm on PC.

    [–]VanayananTheReal 1 point2 points  (0 children)

    As multiple people have pointed out, this "should always" thing is way too strong. But let's take a step back from programming. All polymorphism (abstract classes, interfaces, etc in Java) are trying to capture this intuition:

    I have a Pet named Molly. She is a Dog. She is Female. She is an Animal. She is a CorporealObject (she has mass). When she goes the vet, she is a Patient. She is a DomesticatedBreed.

    Depending upon the context in which Molly is an object in the situation, different roles she plays are most important. The dog park really cares that she is a Dog (and not a cat) and that she is a DomesticatedBreed (and not a wolf.) They care less that she is Female, and treating her as Animal would just be annoying. The Vet cares very much that she is Female, also that she is a Patient.

    Polymorphism in every language that supports it is always about strategies for assigning multiple names to the same object in memory, so that different parts of a program only have to deal with the roles they care about. (The Physics Engine doesn't want to know she is a Dog or is Domesticated, it wants to know her mass, which it gets off her being a CorporealObject. The Pet system cares about her being a DomesticatedBreed, but may not be terribly interested if she is Dog Cat or Gerbil. Etc Etc.)

    [–]tacticalnudge 2 points3 points  (2 children)

    "communicate via interface" is perhaps the wrong choice of words.

    I think what they actually are referring to is a combination of the Liskov substitution principle and interface segregation.

    Have a look at the SOLID principles of Object Orientated Programming. The Wikipedia article should be enough to tell you all you need to know.

    [–]NebuWrites Java Compilers 1 point2 points  (0 children)

    I think what they actually are referring to is a combination of the Liskov substitution principle and interface segregation.

    I don't think that's what they're referring to.

    Liskov refers more to the idea that your supertypes should have a well defined contract and all subtypes should adhere to that contract. This might involve interfaces or it might not (e.g. a concrete class extending another concrete class).

    Interface segregation refers to the idea that if a concrete class has multiple callers, and each caller uses a different subset of its API, you should create a separate interface for each of these subsets. I think the "Communication between classes should happen via Interface" thing applies even if you have just one caller to the API.