Qual é a diferença entre uma interface e uma classe, e por que devo usar uma interface quando posso implementar os métodos diretamente na classe?

117

Estou ciente de que esta é uma pergunta muito básica, mas um entrevistador me perguntou de uma forma muito ardilosa e eu estava desamparado :(

Conheço apenas a definição material ou teórica para uma interface e também a implementei em muitos projetos nos quais trabalhei. Mas eu realmente não entendo por que e como isso é útil.

Eu também não entendo nada de interface. ou seja, por exemplo, usamos

conn.Dispose();em finalmente bloquear. Mas não vejo que a classe está implementando ou herdando a classe IDisposableinterface ( SqlConnection), quero dizer. Estou me perguntando como posso simplesmente chamar o nome do método. Também na mesma coisa, não estou entendendo como o método Dispose funciona porque, precisamos implementar o corpo da função com nossa própria implementação para todos os métodos de interface. Então, como as interfaces são aceitas ou nomeadas como contratos? Essas perguntas continuaram rolando em minha mente até agora e, francamente, nunca vi nenhum fio condutor que explicasse minhas perguntas de uma forma que eu pudesse entender.

MSDN, como de costume, parece muito assustador e nenhuma linha é clara ( pessoal, desculpem-se por estarem em desenvolvimento de alto nível, eu sinto fortemente que qualquer código ou artigo deve alcançar a mente de qualquer pessoa que o veja, portanto, como muitos outros dizem, MSDN não é útil ).

O entrevistador disse:

Ele tem 5 métodos e está feliz em implementá-los na classe diretamente, mas se você tiver que ir para a classe ou interface Abstract, qual você escolherá e por quê? Eu respondi a ele todas as coisas que li em vários blogs, dizendo vantagens e desvantagens da classe abstrata e da interface, mas ele não está convencido, ele está tentando entender "Por que a interface" em geral. "Por que classe abstrata" em geral, mesmo se eu puder implementar os mesmos métodos apenas uma vez e não irei alterá-los.

Não vejo onde na net, poderia conseguir um artigo que me explicasse claramente sobre interfaces e seu funcionamento. Sou um daqueles muitos programadores que ainda não entendem de interfaces (conheço a teoria e os métodos que usei), mas não estou satisfeito de ter entendido claramente.

Aprendiz
fonte
4
As interfaces são algo que também luto para entender. Boa pergunta.
Brian
4
programar para um contrato abstrato em vez de uma implementação concreta ... Resumindo, significa que você pode substituir qualquer objeto que implemente uma interface quando uma interface for necessária.
Mitch Wheat
7
SqlConnectionherda o System.ComponentModel.Componentque implementa IDisposable.
Lee
2
@MitchWheat - Não é para ser um exemplo, a questão é como SqlConnectionimplementa IDisposable.
Lee
Oh Lee, isso me fez entender, obrigado. Mas ainda não vejo como ou onde a funcionalidade do método "Dispose" é definida.
Aprendiz

Respostas:

92

As interfaces são excelentes quando você deseja criar algo como:

using System;

namespace MyInterfaceExample
{
    public interface IMyLogInterface
    {
        //I want to have a specific method that I'll use in MyLogClass
        void WriteLog();       
    }

    public class MyClass : IMyLogInterface
    {

        public void WriteLog()
        {
            Console.Write("MyClass was Logged");
        }
    }

    public class MyOtherClass : IMyLogInterface
    {

        public void WriteLog()
        {
            Console.Write("MyOtherClass was Logged");
            Console.Write("And I Logged it different, than MyClass");
        }
    }

    public class MyLogClass
    {
        //I created a WriteLog method where I can pass as a parameter any object that implements IMyLogInterface.
        public static void WriteLog(IMyLogInterface myLogObject)
        {
            myLogObject.WriteLog(); //So I can use WriteLog here.
        }
    }

    public class MyMainClass
    {
        public void DoSomething()
        {
            MyClass aClass = new MyClass();
            MyOtherClass otherClass = new MyOtherClass();

            MyLogClass.WriteLog(aClass);//MyClass can log, and have his own implementation
            MyLogClass.WriteLog(otherClass); //As MyOtherClass also have his own implementation on how to log.
        }
    }
}

No meu exemplo, eu poderia ser um desenvolvedor que escreve MyLogClass, e os outros desenvolvedores, poderiam criar suas classes e, quando desejassem registrar, implementariam a interface IMyLogInterface. É como eles estavam me perguntando o que eles precisam implementar para usar o WriteLog()método em MyLogClass. A resposta que encontrarão na interface.

Guilherme de Jesus Santos
fonte
3
Ei, parece um ingrediente muito bom para eu entender, eu realmente agradeço, muito obrigado :) :)
Aluno
14
Minha pergunta é se você está instanciando MyClasse MyOtherClasspor que simplesmente não chamar aClass.WriteLog()por que adicionar essa etapa extra. A implementação de WriteLog()permaneceria diferente para cada uma das classes, mas você já tem o objeto, então por que passá-lo para uma classe manipuladora?
Zach M.
Hm pode ser que, se você colocar seu exemplo de registro no nugget, seria mais simples para outros usarem seu registrador, sem saber os detalhes .. mas por outro lado, ainda não é uma classe universal, (e eu poderia escrever um interface com log e níveis de alerta) interfaces ainda estão apenas dentro do seu escopo. então além de você para quem está se beneficiando com isso?
user3800527
2
@ZachM. Se eu estiver certo, a resposta significa que ele não irá instanciar as classes, mas outros desenvolvedores irão instanciar as classes e passá-las como parâmetro para o MyLogClass WriteLogmétodo. Portanto, seu método pode lidar com qualquer objeto que implemente IMyLogInterface. Aqui está outra postagem interessante.
shaijut de
1
Minha pergunta é por que Interface ??? O cenário acima também pode ser alcançado por uma classe abstrata com todos os métodos abstratos.
Abhijit Ojha
52

Um motivo pelo qual uso interfaces é porque aumentam a flexibilidade do código. Digamos que temos um método que recebe um objeto do tipo de classe Conta como parâmetro, como:

public void DoSomething(Account account) {
  // Do awesome stuff here.
}

O problema com isso é que o parâmetro do método é fixado para a implementação de uma conta. Isso é ótimo se você nunca precisaria de outro tipo de conta. Veja este exemplo, que em vez disso usa uma interface de conta como parâmetro.

public void DoSomething(IAccount account) {
  // Do awesome stuff here.
}

Esta solução não é fixa para uma implementação, o que significa que posso passar um SuperSavingsAccount ou ExclusiveAccount (ambos implementando a interface IAccount) e obter um comportamento diferente para cada conta implementada.

user2211290
fonte
45

Interfaces são contratos que os implementadores devem seguir. Classes abstratas permitem contratos mais implementações compartilhadas - algo que as interfaces não podem ter. As classes podem implementar e herdar várias interfaces. As classes podem estender apenas uma única classe abstrata.

Por que interface

  • Você não tem implementação de código padrão ou compartilhado
  • Você deseja compartilhar contratos de dados (serviços da web, SOA)
  • Você tem implementações diferentes para cada implementador de interface ( IDbCommandtem SqlCommande OracleCommandque implementa a interface de maneiras específicas )
  • Você deseja oferecer suporte a herança múltipla .

Por que abstrato?

SliverNinja - MSFT
fonte
2
@Silver Eu li a maior parte do que você digitou em blogs, mas estou tentando entender na prática. Eu fiz serviços WCF, interfaces expostas (mas era apenas um único aplicativo autônomo sem upstream ou downstream). Portanto, não consegui entender direito, embora tenha projetado e implementado interfaces muito bem. Minha pergunta é, praticamente, você apenas compartilha os nomes de métodos que o contrato significa, certo? COMO ISSO É ÚTIL :( Eu sei que só obriga a implementar todos os métodos, mas de outra forma? Em sua postagem acima na interface, o segundo ponto diz compartilhar, significa que você pode dar um exemplo prático em tempo real disso
Aprendiz
1
Para um exemplo prático sobre interfaces e SOA, compartilhamos nossas interfaces WCF ( DataContracts) em um .NET Assembly ( por exemplo, Contracts.Shared.dll ) para que os consumidores do cliente .NET possam interoperarChannelFactory facilmente usando ( evitando gerar código por meio de Adicionar Referência de Serviço, etc. ) ou usando Adicionar referência de serviço com tipos compartilhados
SliverNinja - MSFT
Se eu declarar apenas métodos abstratos dentro de um calss abstrato, a classe abstrata atuará como interface, então por que precisamos de interface?
Abhijit Ojha
25

insira a descrição da imagem aqui

Portanto, neste exemplo, o PowerSocket não sabe mais nada sobre os outros objetos. Todos os objetos dependem do Power fornecido pelo PowerSocket, portanto, eles implementam o IPowerPlug e, ao fazer isso, podem se conectar a ele.

As interfaces são úteis porque fornecem contratos que os objetos podem usar para trabalhar juntos sem a necessidade de saber mais nada um sobre o outro.

Brijesh Rana
fonte
Isso faz sentido, mas ainda estou lutando para entender, você simplesmente não poderia criar uma classe base para PowerSocket e todas as outras coisas herdá-la, se necessário. Tecnicamente, os Power Sockets não têm ideia sobre as outras classes.
altaaf.hussein
Acho que porque a herança múltipla não é permitida em C #
Hugh Seagraves
22

Em uma palavra - por causa do polimorfismo !

Se você "Programa para uma interface, não uma implementação", pode injetar diferentes objetos que compartilham a mesma interface (tipo) no método como um argumento. Desta forma, o código do seu método não está acoplado a nenhuma implementação de outra classe, o que significa que ele está sempre aberto para trabalhar com objetos recém-criados da mesma interface. (Princípio de abertura / fechamento)

  • Dê uma olhada em injeção de dependência e definitivamente leia Design Patterns - Elements of Reusable Object-Oriented Software de GOF.
Gabriel C. Troia
fonte
4

C # não tem digitação de pato - só porque você sabe que um determinado método é implementado em um conjunto de classes concretas, não significa que você pode tratá-los todos da mesma forma em relação à chamada desse método. Implementar uma interface permite que você trate todas as classes que a implementam como o mesmo tipo de coisa, em relação ao que essa interface define.

Erix
fonte
3
Você pode obter uma espécie de ducktyping em .net4 com o tipo dinâmico.
Tony Hopkinson
4

Eu acredito que muito sangue já foi derramado ao fazer essas perguntas, e muitos tentam resolver esses problemas explicando termos de robô que nenhum ser humano normal pode entender.

Então, primeiro. para saber por que interface e por que abstrata, você precisa aprender para que servem. Eu pessoalmente aprendi esses dois ao aplicar a Classe de Fábrica. você encontra um bom tutor neste link

Agora vamos nos aprofundar no link que já dei.

Você tem a classe de veículo que pode mudar de acordo com a necessidade do usuário (como adicionar caminhão , tanque , avião , etc.

public class clsBike:IChoice
{
   #region IChoice Members
    public string Buy()
    {
       return ("You choose Bike");
    }
    #endregion
}

e

public class clsCar:IChoice
{
   #region IChoice Members
    public string Buy()
    {
       return ("You choose Car");
    }
    #endregion
}

e ambos têm o Contrato IChoice que simplesmente diz que Minha aula deve ter o método Comprar

public interface IChoice
{
    string Buy();
}

Agora, você vê, essa interface apenas impõe o método, Buy()mas permite que a classe herdada decida o que fazer ao implementá-lo. Essa é a limitação da Interface, usando puramente interface, você pode acabar repetindo alguma tarefa que podemos implementar automaticamente usando abstact. Em nosso exemplo, digamos, a compra de cada veículo tem um desconto.

public abstract class Choice
{
    public abstract string Discount { get; }
    public abstract string Type { get; }
    public string Buy()
    {
       return "You buy" + Type + " with " + Discount;
}
public class clsBike: Choice
{
    public abstract string Discount { get { return "10% Discount Off"; } }
    public abstract string Type { get { return "Bike"; } }
}

public class clsCar:Choice
{
    public abstract string Discount { get { return " $15K Less"; } }
    public abstract string Type { get { return "Car"; } }
}

Agora, usando a classe de fábrica, você pode conseguir a mesma coisa, mas usando o abstrato, você deixa a classe base executar o Buy()método.

Em resumo: os contratos de interface permitem que a classe herdada faça a implementação, enquanto os contratos da classe abstrata podem inicializar a implementação (que pode ser substituída pela classe Inherit)

dr.Crow
fonte
2

Com uma interface, você pode fazer o seguinte:

1) Crie interfaces segregadas que oferecem cortes diferentes de sua implementação, permitindo uma interface mais coesa.

2) Permitir vários métodos com o mesmo nome entre as interfaces, porque hey, você não tem nenhuma implementação conflitante, apenas uma assinatura.

3) Você pode criar versões e ativar sua interface independentemente de sua implementação, garantindo que um contrato seja cumprido.

4) Seu código pode depender de abstração em vez de concretização, permitindo injeção de dependência inteligente, incluindo injeção de simulação de teste etc.

Tenho certeza de que há muitos outros motivos, estes são apenas alguns.

Uma classe abstrata permite que você tenha uma base parcialmente concreta para trabalhar; isso não é o mesmo que uma interface, mas tem suas próprias qualidades, como a capacidade de criar uma implementação parcial usando o padrão de método de template.

Jeff Watkins
fonte
Você negligenciou a coisa mais importante: implementar uma interface torna sua classe utilizável por qualquer código que necessite de uma implementação dessa interface, sem que o código em questão tenha que saber nada sobre sua classe.
supercat de
2

Como uma amostra real de @ user2211290 resposta:

Ambos Arraye Listter uma interface IList. Abaixo temos um string[]e um List<string>e verifique os dois com um método usando IList :

string[] col1 = { "zero", "one", "two", "three", "four"};
List<string> col2 = new List<string>{ "zero", "one", "two", "three"};

//a methode that manipulates both of our collections with IList
static void CheckForDigit(IList collection, string digit)
{
    Console.Write(collection.Contains(digit));
    Console.Write("----");
    Console.WriteLine(collection.ToString()); //writes the type of collection
}

static void Main()
{
    CheckForDigit(col1, "one");   //True----System.String[]
    CheckForDigit(col2, "one");   //True----System.Collections.Generic.List`1[System.String]



//Another test:

    CheckForDigit(col1, "four");   //True----System.String[]
    CheckForDigit(col2, "four");   //false----System.Collections.Generic.List`1[System.String]
}
Farzin Kanzi
fonte
1

Você só pode herdar de uma classe abstrata. Você pode herdar de várias interfaces. Isso determina o que uso na maioria dos casos.

A vantagem da classe abstrata é que você pode ter uma implementação básica. Porém, no caso de IDisposable, uma implementação padrão é inútil, uma vez que a classe base não sabe como limpar as coisas corretamente. Assim, uma interface seria mais adequada.

Jeow Li Huan
fonte
1

Tanto a classe abstrata quanto a interface são contratos.

A ideia de um contrato é especificar algum comportamento. Se você diz que implementou, você concordou com o contrato.

A escolha da interface abstrata é.

Qualquer descendente não abstrato da classe abstrata implementará o contrato.

versus

Qualquer classe que implemente a interface implementará o contrato.

Portanto, você usa abstrato quando deseja especificar algum comportamento que todos os descendentes devem implementar e evitar a definição de uma interface separada, mas agora tudo que atende a esse contrato efetivamente agregado deve ser um descendente.

Tony Hopkinson
fonte
1

As interfaces são para fazer uma abstração (um arquétipo) da abstração (as classes) da realidade (os objetos).

As interfaces são para especificar os termos do contrato sem fornecer implementação fornecida pelas classes.

As interfaces são especificações:

  • Interfaces são artefatos de tempo de design para especificar o comportamento imóvel do conceito, pois é sozinho e estático.

  • As classes são artefatos de tempo de implementação para especificar a estrutura móvel da realidade conforme ela interage e se move.

O que é uma interface?

Quando você observa um gato, pode dizer que é um animal que tem quatro patas, uma cabeça, um tronco, um rabo e cabelo. Você pode ver que ele pode andar, correr, comer e miar. E assim por diante.

Você acabou de definir uma interface com suas propriedades e suas operações. Como tal, você não definiu nenhum modus operandi, mas apenas características e capacidades sem saber como as coisas funcionam: você definiu habilidades e distinções.

Como tal, ainda não é realmente uma classe, embora na UML a chamemos de classe em um diagrama de classes, porque podemos definir membros privados e protegidos para começar a ter uma visão profunda do artefato. Não se confunda aqui porque em UML uma interface é um pouco diferente de uma interface em C #: é como um ponto de acesso parcial ao átomo de abstração. Como tal, dissemos que uma classe pode implementar várias interfaces. Como tal, é a mesma coisa, mas não, porque as interfaces em C # são usadas para abstrair a abstração e limitar essa abstração como um ponto de acesso. São dois usos diferentes. Assim, uma classe em UML representa uma interface de acoplamento completo para uma classe de programação, enquanto uma interface UML representa uma interface de desacoplamento de uma seção de uma classe de programação. De fato, o diagrama de classes em UML não cuida da implementação e todos os seus artefatos estão no nível da interface de programação. Enquanto mapeamos classes UML para classes de programação, é uma transposição de abstração abstrata em abstração concreta. Há uma sutileza que explica a dicotomia entre o campo do design e o campo da programação. Portanto, uma classe em UML é uma classe de programação do ponto de vista de uma interface de programação enquanto considera as coisas ocultas internas.

As interfaces também permitem simular herança múltipla quando não disponível de uma maneira estranha. Por exemplo, a classe cat implementará a interface cat que deriva da interface animal. Esta classe cat também implementará essas interfaces: andar, correr, comer e fazer um som. Isso compensa a ausência de herança múltipla no nível da classe, mas a cada vez você precisa reimplementar tudo e não pode fatorar a realidade, na melhor das hipóteses, como a própria realidade faz.

Para entender isso, podemos nos referir à codificação Pascal Object, onde você define em uma unidade a interface e as seções de implementação. Na interface você define os tipos e na implementação você implementa o tipo:

unit UnitName;

interface

type
  TheClass = class
  public
    procedure TheMethod;
  end;

implementation

class procedure TheClass.TheMethod;
begin
end;

Aqui, a seção de interface corresponde ao design da classe UML, enquanto os tipos de interfaces são, portanto, outras coisas.

Portanto, em nosso negócio, temos uma palavra, interface , para nomear duas coisas distintas, mas semelhantes, e isso é uma fonte de confusão.

Também em C #, por exemplo, as interfaces de programação permitem compensar a ausência do verdadeiro polimorfismo genérico em tipos abertos sem realmente atingir o objetivo porque você perdeu a habilidade de tipagem forte.

Afinal, as interfaces são necessárias para permitir que sistemas incompatíveis se comuniquem sem se preocupar com a implementação e o gerenciamento de objetos na memória como introduzidos no Modelo de Objeto Comum (Distribuído).

O que é uma aula?

Depois de definir uma redução da realidade de um ponto de vista externo, você pode descrevê-la de uma perspectiva interna: esta é a aula onde você define o processamento de dados e o gerenciamento de mensagens para permitir que a realidade que você encapsulou ganhe vida e interaja graças para objetos usando instâncias.

Portanto, na UML você percebe uma imersão fractal nas rodas da máquina e descreve os estados, as interações e assim por diante para ser capaz de implementar a abstração do fragmento da realidade que deseja manipular.

Como tal, uma classe abstrata é de alguma forma equivalente a uma interface do ponto de vista do compilador.

Mais Informações

Protocolo (programação orientada a objetos)

C # - Interfaces

C # - Classes

Olivier Rogier
fonte
1

Deixe-me falar sobre torradeiras voadoras.

torradeira voadora

Existem, é claro, muitas situações em que você pode construir um sistema de software funcional sem declarar ou implementar nenhuma interface: qualquer projeto de software orientado a objetos pode ser realizado usando nada além de classes.

Então, novamente, qualquer sistema de software também pode ser implementado em Assembly Language, ou melhor ainda, em Machine Code. A razão pela qual usamos mecanismos de abstração é porque eles tendem a tornar as coisas mais fáceis. As interfaces são um mecanismo de abstração.

Então, acontece que existem certos designs orientados a objetos não triviais que são muito mais fáceis de implementar se você usar interfaces, que as interfaces tornam-se praticamente necessárias nesses casos.

Esses designs não triviais têm a ver com herança múltipla, que, em sua forma "verdadeira", é quando uma classe herda não apenas de uma classe base, mas de duas ou mais classes base. Essa forma verdadeira não é possível em C #, mas antes de linguagens como C # e Java surgirem, a linguagem que governava era C ++, que oferece suporte total à herança múltipla verdadeira. Infelizmente, a verdadeira herança múltipla acabou não sendo uma ideia muito boa, porque complica imensamente o design da linguagem e também dá origem a vários problemas, por exemplo, o famoso "Problema do Diamante". (Veja "Qual é o problema exato com herança múltipla?" Resposta de J Francis )

Portanto, se alguém quisesse construir uma classe de "torradeira voadora", herdaria de alguma classe "torradeira" existente e também de alguma classe "voadora" existente. O tipo de problema que eles provavelmente enfrentariam era que a fonte de alimentação da classe da torradeira provavelmente seria uma tomada de parede, enquanto a fonte de alimentação da classe das máquinas voadoras provavelmente seria comida de pombo, e a nova classe resultante seria de alguma forma tem ambos, ou não ficaria claro qual teria. (O problema do diamante.)

Os criadores de linguagens como C # e Java decidiram não permitir a verdadeira herança múltipla, a fim de manter a linguagem simples e evitar armadilhas como o Problema do Diamante. No entanto, alguma forma de herança múltipla ainda é necessária (ou pelo menos muito desejável), portanto, nessas linguagens eles introduziram interfaces como um meio de suportar uma forma menor de herança múltipla, evitando os problemas e a complexidade da verdadeira herança múltipla.

Nessa forma menor de herança múltipla, você não tem permissão para ter uma classe que herda de mais de uma classe base, mas pode pelo menos herdar de uma ou mais interfaces. Então, se você quiser construir uma torradeira voadora, você não pode herdar de alguma classe de torradeira existente e de alguma classe de voadora existente, mas o que você pode fazer é herdar de uma classe de torradeira existente e também expor uma interface de voadora que você mesmo implementa, possivelmente usando qualquer meio que você já herdou da torradeira.

Portanto, a menos que você sinta a necessidade de criar uma classe que agregue dois conjuntos diferentes e não relacionados de funcionalidade, você não precisará de nenhuma forma de herança múltipla, portanto, não precisará declarar ou implementar nenhuma interface.

Mike Nakis
fonte
0

As interfaces permitem que o designer da classe torne os métodos disponíveis muito claros para o usuário final. Eles também são parte integrante do polimorfismo.

poy
fonte
Bem dito na sua primeira declaração. Mas não entendi sua segunda afirmação. Você poderia elaborar com um exemplo em tempo real, por favor?
Aluno de
0

Não publicarei a definição de uma interface em relação a uma classe abstrata porque acho que você conhece muito bem a teoria e suponho que você conheça os princípios SOLID, então vamos ser práticos.

Como você sabe, as interfaces não podem ter nenhum código, então a desvantagem é bastante simples de entender.

se você precisa inicializar a propriedade de sua classe fornecendo um construtor ou deseja fornecer parte da implementação, uma classe abstrata seria um bom ajuste contra uma interface que não permitiria que você fizesse isso.

Portanto, em geral você deve preferir classes abstratas às interfaces quando precisar fornecer um construtor ou qualquer código para o cliente que irá herdar / estender sua classe

Massimiliano Peluso
fonte
-2

As classes abstratas são criadas para entidades relacionadas, onde as interfaces podem ser usadas para entidades não relacionadas.

Por exemplo, se eu tenho duas entidades que dizem Animal e Human, então eu irei para Interface, onde como se eu tivesse que ir em detalhes, diga Tigre, Leão e quero me relacionar com Animal, então irei escolher a classe Animal Abstrato.

ficará como abaixo

   Interface             
   ____|____
  |        |
Animal   Human



  Animal (Abstract class)
   __|___
  |      |
Tiger   Lion
Manoj
fonte