Is there more to an interface than having the correct methods

后端 未结 17 665
小鲜肉
小鲜肉 2020-11-22 13:37

So lets say I have this interface:

public interface IBox
{
   public void setSize(int size);
   public int getSize();
   public int getArea();
  //...and so          


        
相关标签:
17条回答
  • 2020-11-22 14:17

    Interfaces are a way to make your code more flexible. What you do is this:

    Ibox myBox=new Rectangle();
    

    Then, later, if you decide you want to use a different kind of box (maybe there's another library, with a better kind of box), you switch your code to:

    Ibox myBox=new OtherKindOfBox();
    

    Once you get used to it, you'll find it's a great (actually essential) way to work.

    Another reason is, for example, if you want to create a list of boxes and perform some operation on each one, but you want the list to contain different kinds of boxes. On each box you could do:

    myBox.close()
    

    (assuming IBox has a close() method) even though the actual class of myBox changes depending on which box you're at in the iteration.

    0 讨论(0)
  • 2020-11-22 14:17

    Interfaces where a fetature added to java to allow multiple inheritance. The developers of Java though/realized that having multiple inheritance was a "dangerous" feature, that is why the came up with the idea of an interface.

    multiple inheritance is dangerous because you might have a class like the following:

    
    class Box{
        public int getSize(){
           return 0;
        }
        public int getArea(){
           return 1;
        }
    
    }
    
    class Triangle{
        public int getSize(){
           return 1;
        }
        public int getArea(){
           return 0;
        }
    
    }
    
    class FunckyFigure extends Box, Triable{
       // we do not implement the methods we will used the inherited ones
    }
    
    

    Which would be the method that should be called when we use

    
       FunckyFigure.GetArea(); 
    
    

    All the problems are solved with interfaces, because you do know you can extend the interfaces and that they wont have classing methods... ofcourse the compiler is nice and tells you if you did not implemented a methods, but I like to think that is a side effect of a more interesting idea.

    0 讨论(0)
  • 2020-11-22 14:19

    Interfaces allow statically typed languages to support polymorphism. An Object Oriented purist would insist that a language should provide inheritance, encapsulation, modularity and polymorphism in order to be a fully-featured Object Oriented language. In dynamically-typed - or duck typed - languages (like Smalltalk,) polymorphism is trivial; however, in statically typed languages (like Java or C#,) polymorphism is far from trivial (in fact, on the surface it seems to be at odds with the notion of strong typing.)

    Let me demonstrate:

    In a dynamically-typed (or duck typed) language (like Smalltalk), all variables are references to objects (nothing less and nothing more.) So, in Smalltalk, I can do this:

    |anAnimal|    
    anAnimal := Pig new.
    anAnimal makeNoise.
    
    anAnimal := Cow new.
    anAnimal makeNoise.
    

    That code:

    1. Declares a local variable called anAnimal (note that we DO NOT specify the TYPE of the variable - all variables are references to an object, no more and no less.)
    2. Creates a new instance of the class named "Pig"
    3. Assigns that new instance of Pig to the variable anAnimal.
    4. Sends the message makeNoise to the pig.
    5. Repeats the whole thing using a cow, but assigning it to the same exact variable as the Pig.

    The same Java code would look something like this (making the assumption that Duck and Cow are subclasses of Animal:

    Animal anAnimal = new Pig();
    duck.makeNoise();
    
    anAnimal = new Cow();
    cow.makeNoise();
    

    That's all well and good, until we introduce class Vegetable. Vegetables have some of the same behavior as Animal, but not all. For example, both Animal and Vegetable might be able to grow, but clearly vegetables don't make noise and animals cannot be harvested.

    In Smalltalk, we can write this:

    |aFarmObject|
    aFarmObject := Cow new.
    aFarmObject grow.
    aFarmObject makeNoise.
    
    aFarmObject := Corn new.
    aFarmObject grow.
    aFarmObject harvest.
    

    This works perfectly well in Smalltalk because it is duck-typed (if it walks like a duck, and quacks like a duck - it is a duck.) In this case, when a message is sent to an object, a lookup is performed on the receiver's method list, and if a matching method is found, it is called. If not, some kind of NoSuchMethodError exception is thrown - but it's all done at runtime.

    But in Java, a statically typed language, what type can we assign to our variable? Corn needs to inherit from Vegetable, to support grow, but cannot inherit from Animal, because it does not make noise. Cow needs to inherit from Animal to support makeNoise, but cannot inherit from Vegetable because it should not implement harvest. It looks like we need multiple inheritance - the ability to inherit from more than one class. But that turns out to be a pretty difficult language feature because of all the edge cases that pop up (what happens when more than one parallel superclass implement the same method?, etc.)

    Along come interfaces...

    If we make Animal and Vegetable classes, with each implementing Growable, we can declare that our Cow is Animal and our Corn is Vegetable. We can also declare that both Animal and Vegetable are Growable. That lets us write this to grow everything:

    List<Growable> list = new ArrayList<Growable>();
    list.add(new Cow());
    list.add(new Corn());
    list.add(new Pig());
    
    for(Growable g : list) {
       g.grow();
    }
    

    And it lets us do this, to make animal noises:

    List<Animal> list = new ArrayList<Animal>();
    list.add(new Cow());
    list.add(new Pig());
    for(Animal a : list) {
      a.makeNoise();
    }
    

    The advantage to the duck-typed language is that you get really nice polymorphism: all a class has to do to provide behavior is provide the method. As long as everyone plays nice, and only sends messages that match defined methods, all is good. The downside is that the kind of error below isn't caught until runtime:

    |aFarmObject|
    aFarmObject := Corn new.
    aFarmObject makeNoise. // No compiler error - not checked until runtime.
    

    Statically-typed languages provide much better "programming by contract," because they will catch the two kinds of error below at compile-time:

    // Compiler error: Corn cannot be cast to Animal.
    Animal farmObject = new Corn();  
    farmObject makeNoise();
    

    --

    // Compiler error: Animal doesn't have the harvest message.
    Animal farmObject = new Cow();
    farmObject.harvest(); 
    

    So....to summarize:

    1. Interface implementation allows you to specify what kinds of things objects can do (interaction) and Class inheritance lets you specify how things should be done (implementation).

    2. Interfaces give us many of the benefits of "true" polymorphism, without sacrificing compiler type checking.

    0 讨论(0)
  • 2020-11-22 14:21

    Normally Interfaces define the interface you should use (as the name says it ;-) ). Sample

    
    public void foo(List l) {
       ... do something
    }
    

    Now your function foo accepts ArrayLists, LinkedLists, ... not only one type.

    The most important thing in Java is that you can implement multiple interfaces but you can only extend ONE class! Sample:

    
    class Test extends Foo implements Comparable, Serializable, Formattable {
    ...
    }
    
    is possible but
    
    class Test extends Foo, Bar, Buz {
    ...
    }
    
    is not!

    Your code above could also be: IBox myBox = new Rectangle();. The important thing is now, that myBox ONLY contains the methods/fields from IBox and not the (possibly existing) other methods from Rectangle.

    0 讨论(0)
  • 2020-11-22 14:23

    The purpose of interfaces is polymorphism, a.k.a. type substitution. For example, given the following method:

    public void scale(IBox b, int i) {
       b.setSize(b.getSize() * i);
    }
    

    When calling the scale method, you can provide any value that is of a type that implements the IBox interface. In other words, if Rectangle and Square both implement IBox, you can provide either a Rectangle or a Square wherever an IBox is expected.

    0 讨论(0)
  • 2020-11-22 14:23

    I think you understand everything Interfaces do, but you're not yet imagining the situations in which an Interface is useful.

    If you're instantiating, using and releasing an object all within a narrow scope (for example, within one method call), an Interface doesn't really add anything. Like you noted, the concrete class is known.

    Where Interfaces are useful is when an object needs to be created one place and returned to a caller that may not care about the implementation details. Let's change your IBox example to an Shape. Now we can have implementations of Shape such as Rectangle, Circle, Triangle, etc., The implementations of the getArea() and getSize() methods will be completely different for each concrete class.

    Now you can use a factory with a variety of createShape(params) methods which will return an appropriate Shape depending on the params passed in. Obviously, the factory will know about what type of Shape is being created, but the caller won't have to care about whether it's a circle, or a square, or so on.

    Now, imagine you have a variety of operations you have to perform on your shapes. Maybe you need to sort them by area, set them all to a new size, and then display them in a UI. The Shapes are all created by the factory and then can be passed to the Sorter, Sizer and Display classes very easily. If you need to add a hexagon class some time in the future, you don't have to change anything but the factory. Without the Interface, adding another shape becomes a very messy process.

    0 讨论(0)
提交回复
热议问题