java what Existe mais em uma interface do que ter os métodos corretos




what interface in java (12)

O único propósito das interfaces é garantir que a classe que implementa uma interface tenha os métodos corretos, conforme descrito por uma interface? Ou existe algum outro uso de interfaces?

Estou atualizando a resposta com novos recursos da interface, que foram introduzidos com a versão do java 8 .

Da página de documentação do oracle no resumo da interface :

Uma declaração de interface pode conter

  1. assinaturas de método
  2. métodos padrão
  3. métodos estáticos
  4. definições constantes.

Os únicos métodos que possuem implementações são os métodos padrão e estático.

Usos da interface :

  1. Para definir um contrato
  2. Para vincular classes não relacionadas com tem uma capacidade (por exemplo, classes implementando interface Serializable pode ou não ter qualquer relação entre eles, exceto a implementação dessa interface
  3. Para fornecer implementação intercambiável, por exemplo, padrão de estratégia
  4. Os métodos padrão permitem adicionar novas funcionalidades às interfaces de suas bibliotecas e garantir compatibilidade binária com código escrito para versões mais antigas dessas interfaces
  5. Organize métodos auxiliares em suas bibliotecas com métodos estáticos (é possível manter métodos estáticos específicos para uma interface na mesma interface em vez de em uma classe separada)

Algumas questões SE relacionadas com relação à diferença entre classe abstrata e interface e casos de uso com exemplos de trabalho:

Qual é a diferença entre uma interface e uma classe abstrata?

Como devo ter explicado a diferença entre uma interface e uma classe abstrata?

Dê uma olhada na página de documentation para entender os novos recursos adicionados no java 8: métodos padrão e métodos estáticos .

https://code.i-harness.com

Então, digamos que eu tenha essa interface:

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

E eu tenho uma classe que implementa isso:

public class Rectangle implements IBox
{
   private int size;
   //Methods here
}

Se eu quisesse usar a interface IBox, na verdade não posso criar uma instância dela, da seguinte forma:

public static void main(String args[])
{
    Ibox myBox=new Ibox();
}

certo? Então eu realmente tenho que fazer isso:

public static void main(String args[])
{
    Rectangle myBox=new Rectangle();
}

Se isso for verdade, então o único propósito das interfaces é garantir que a classe que implementa uma interface tenha os métodos corretos como descritos por uma interface? Ou existe algum outro uso de interfaces?


Aqui está o meu entendimento da vantagem da interface. Corrija-me se eu estiver enganado. Imagine que estamos desenvolvendo o sistema operacional e outra equipe está desenvolvendo os drivers para alguns dispositivos. Por isso, desenvolvemos uma interface StorageDevice. Temos duas implementações (FDD e HDD) fornecidas por outros desenvolvedores.

Então nós temos uma classe OperatingSystem que pode chamar métodos de interface como saveData apenas passando uma instância de classe implementada a interface StorageDevice.

A vantagem aqui é que não nos importamos com a implementação da interface. A outra equipe fará o trabalho implementando a interface StorageDevice.

package mypack;

interface StorageDevice {
    void saveData (String data);
}


class FDD implements StorageDevice {
    public void saveData (String data) {
        System.out.println("Save to floppy drive! Data: "+data);
    }
}

class HDD implements StorageDevice {
    public void saveData (String data) {
        System.out.println("Save to hard disk drive! Data: "+data);
    }
}

class OperatingSystem {
    public String name;
    StorageDevice[] devices;
    public OperatingSystem(String name, StorageDevice[] devices) {

        this.name = name;
        this.devices = devices.clone();

        System.out.println("Running OS " + this.name);
        System.out.println("List with storage devices available:");
        for (StorageDevice s: devices) {
            System.out.println(s);
        }

    }

    public void saveSomeDataToStorageDevice (StorageDevice storage, String data) {
        storage.saveData(data);
    }
}

public class Main {

    public static void main(String[] args) {

        StorageDevice fdd0 = new FDD();
        StorageDevice hdd0 = new HDD();     
        StorageDevice[] devs = {fdd0, hdd0};        
        OperatingSystem os = new OperatingSystem("Linux", devs);
        os.saveSomeDataToStorageDevice(fdd0, "blah, blah, blah...");    
    }
}

Eu acho que você entende tudo o que as Interfaces fazem, mas você ainda não está imaginando as situações nas quais uma Interface é útil.

Se você estiver instanciando, usando e liberando um objeto dentro de um escopo restrito (por exemplo, dentro de uma chamada de método), uma interface realmente não adiciona nada. Como você observou, a classe concreta é conhecida.

Onde Interfaces são úteis é quando um objeto precisa ser criado em um lugar e retornado a um chamador que pode não se importar com os detalhes da implementação. Vamos mudar o seu exemplo do IBox para um Shape. Agora podemos ter implementações de Shape como Rectangle, Circle, Triangle, etc. As implementações dos métodos getArea () e getSize () serão completamente diferentes para cada classe concreta.

Agora você pode usar uma fábrica com uma variedade de métodos createShape (params) que retornarão uma Shape apropriada dependendo dos parâmetros transmitidos. Obviamente, a fábrica saberá que tipo de Shape está sendo criado, mas o chamador não terá para se preocupar se é um círculo, um quadrado ou assim por diante.

Agora, imagine que você tenha uma variedade de operações que você precisa realizar em suas formas. Talvez você precise classificá-los por área, definir todos eles para um novo tamanho e, em seguida, exibi-los em uma interface do usuário. As formas são todas criadas pela fábrica e depois podem ser passadas para as classes Classificador, Sizer e Display com muita facilidade. Se você precisar adicionar uma classe hexagonal em algum momento no futuro, não será necessário alterar nada além da fábrica. Sem a interface, adicionar outra forma se torna um processo muito confuso.


Interfaces onde uma fetature adicionada ao java para permitir herança múltipla. Os desenvolvedores de Java embora / perceberam que ter herança múltipla era um recurso "perigoso", por isso surgiu a ideia de uma interface.

herança múltipla é perigosa porque você pode ter uma classe como a seguinte:


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
}

Qual seria o método que deveria ser chamado quando usamos


   FunckyFigure.GetArea(); 

Todos os problemas são resolvidos com interfaces, porque você sabe que pode estender as interfaces e que eles não terão métodos de classe ... claro que o compilador é legal e diz se você não implementou um método, mas eu gosto de pensar que é um efeito colateral de uma ideia mais interessante.


Interfaces são uma maneira de tornar seu código mais flexível. O que você faz é isto:

Ibox myBox=new Rectangle();

Então, mais tarde, se você decidir usar um tipo diferente de caixa (talvez haja outra biblioteca, com um tipo de caixa melhor), mude seu código para:

Ibox myBox=new OtherKindOfBox();

Depois de se acostumar com isso, você descobrirá que é uma ótima maneira (realmente essencial) de trabalhar.

Outra razão é, por exemplo, se você deseja criar uma lista de caixas e executar alguma operação em cada uma delas, mas deseja que a lista contenha diferentes tipos de caixas. Em cada caixa você poderia fazer:

myBox.close()

(supondo que o IBox tenha um método close ()) mesmo que a classe real do myBox mude dependendo de qual caixa você está na iteração.


Não se esqueça que em uma data posterior você pode pegar uma classe existente e implementá- IBox , e ela ficará disponível para todo o seu código.

Isso se torna um pouco mais claro se as interfaces forem nomeadas como -able . por exemplo

public interface Saveable {
....

public interface Printable {
....

etc. (Os esquemas de nomeação nem sempre funcionam, por exemplo, não sei se o Boxable é apropriado aqui)


O propósito das interfaces é abstração ou desacoplamento da implementação.

Se você introduzir uma abstração em seu programa, não se importará com as possíveis implementações. Você está interessado no que pode e não como , e usa uma interface para expressar isso em Java.


O propósito das interfaces é o polimorfismo , também conhecido como substituição de tipos . Por exemplo, dado o seguinte método:

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

Ao chamar o método de scale , você pode fornecer qualquer valor que seja de um tipo que implemente a interface do IBox . Em outras palavras, se o Rectangle e o Square implementarem o IBox , você poderá fornecer um Rectangle ou um Square sempre que um IBox for esperado.


PORQUE INTERFACE ??????

Começa com um cachorro. Em particular, um pug .

O pug tem vários comportamentos:

public class Pug { 
private String name;
public Pug(String n) { name = n; } 
public String getName() { return name; }  
public String bark() { return  "Arf!"; } 
public boolean hasCurlyTail() { return true; } }

E você tem um Labrador, que também tem um conjunto de comportamentos.

public class Lab { 
private String name; 
public Lab(String n) { name = n; } 
public String getName() { return name; } 
public String bark() { return "Woof!"; } 
public boolean hasCurlyTail() { return false; } }

Nós podemos fazer alguns pugs e laboratórios:

Pug pug = new Pug("Spot"); 
Lab lab = new Lab("Fido");

E podemos invocar seus comportamentos:

pug.bark() -> "Arf!" 
lab.bark() -> "Woof!" 
pug.hasCurlyTail() -> true 
lab.hasCurlyTail() -> false 
pug.getName() -> "Spot"

Vamos dizer que eu corro um canil e eu preciso acompanhar todos os cães que estou abrigando. Eu preciso armazenar meus pugs e labradores em matrizes separadas :

public class Kennel { 
Pug[] pugs = new Pug[10]; 
Lab[] labs = new Lab[10];  
public void addPug(Pug p) { ... } 
public void addLab(Lab l) { ... } 
public void printDogs() { // Display names of all the dogs } }

Mas isso claramente não é o ideal. Se eu quiser abrigar alguns poodles também, eu tenho que mudar minha definição de canil para adicionar uma variedade de Poodles. Na verdade, preciso de um array separado para cada tipo de cachorro.

Perspicácia: tanto os pugs como os labradores (e poodles) são tipos de cães e têm o mesmo conjunto de comportamentos. Ou seja, podemos dizer (para os propósitos deste exemplo) que todos os cães podem latir, ter um nome e podem ou não ter uma cauda encaracolada. Podemos usar uma interface para definir o que todos os cães podem fazer, mas deixar para os tipos específicos de cães para implementar esses comportamentos específicos. A interface diz "aqui estão as coisas que todos os cães podem fazer", mas não diz como cada comportamento é feito.

public interface Dog 
{
public String bark(); 
public String getName(); 
public boolean hasCurlyTail(); }

Então eu altero ligeiramente as classes Pug e Lab para implementar os comportamentos Dog. Podemos dizer que um Pug é um cachorro e um laboratório é um cachorro.

public class Pug implements Dog {
// the rest is the same as before } 

public class Lab implements Dog { 
// the rest is the same as before 
}

Ainda posso instanciar Pugs e Labs como anteriormente, mas agora também tenho uma nova maneira de fazer isso:

Dog d1 = new Pug("Spot"); 
Dog d2 = new Lab("Fido");

Isso diz que d1 não é apenas um cachorro, é especificamente um pug. E d2 também é um cachorro, especificamente um laboratório. Podemos invocar os comportamentos e eles funcionam como antes:

d1.bark() -> "Arf!" 
d2.bark() -> "Woof!" 
d1.hasCurlyTail() -> true 
d2.hasCurlyTail() -> false 
d1.getName() -> "Spot"

Aqui é onde todo o trabalho extra compensa. A turma do Kennel se torna muito mais simples. Eu preciso apenas de um array e de um método addDog. Ambos irão trabalhar com qualquer objeto que seja um cachorro; isto é, objetos que implementam a interface Dog.

public class Kennel {
Dog[] dogs = new Dog[20]; 
public void addDog(Dog d) { ... } 
public void printDogs() {
// Display names of all the dogs } }

Veja como usá-lo:

Kennel k = new Kennel(); 
Dog d1 = new Pug("Spot"); 
Dog d2 = new Lab("Fido"); 
k.addDog(d1); 
k.addDog(d2); 
k.printDogs();

A última declaração seria exibida: Spot Fido

Uma interface permite que você especifique um conjunto de comportamentos que todas as classes que implementam a interface compartilharão em comum. Consequentemente, podemos definir variáveis ​​e coleções (como arrays) que não precisam saber de antemão que tipo de objeto específico elas conterão, apenas que elas conterão objetos que implementam a interface.


Se você tiver o CardboardBox e o HtmlBox (ambos implementam o IBox), você pode passar ambos para qualquer método que aceite um IBox. Embora sejam muito diferentes e não sejam completamente intercambiáveis, os métodos que não se importam com "abrir" ou "redimensionar" ainda podem usar suas classes (talvez porque se importem com quantos pixels são necessários para exibir algo em uma tela).


Um dos muitos usos que tenho lido é onde é difícil sem usar interfaces de herança múltipla em Java:

class Animal
{
void walk() { } 
....
.... //other methods and finally
void chew() { } //concentrate on this
} 

Agora, imagine um caso em que:

class Reptile extends Animal 
{ 
//reptile specific code here
} //not a problem here

mas,

class Bird extends Animal
{
...... //other Bird specific code
} //now Birds cannot chew so this would a problem in the sense Bird classes can also call chew() method which is unwanted

Melhor design seria:

class Animal
{
void walk() { } 
....
.... //other methods 
} 

Animal não tem o método chew () e, em vez disso, é colocado em uma interface como:

interface Chewable {
void chew();
}

e ter a classe Reptile implementando isso e não os Birds (já que os Birds não podem mastigar):

class Reptile extends Animal implements Chewable { } 

e incase de pássaros simplesmente:

class Bird extends Animal { }

você poderia fazer

Ibox myBox = new Rectangle();

Dessa forma você está usando este objeto como Ibox e você não se importa que seja realmente Rectangle .







interface