Quando devo usar uma interface e quando devo usar uma classe base?
Deve sempre ser uma interface se eu não quiser realmente definir uma implementação base dos métodos?
Se eu tiver uma aula de cachorro e gato. Por que eu iria querer implementar o IPet em vez do PetBase? Eu posso entender ter interfaces para ISheds ou IBarks (IMakesNoise?), Porque elas podem ser colocadas em um animal de estimação, mas não sei qual usar para um animal de estimação genérico.
I tend to prefer using the interface technique over the base type technique because the base type technique doesn’t allow the developer to choose the base type that works best in a particular situation.
. Não consigo entender o significado do trecho. Podemos criar alguns tipos de base e criar um tipo derivado para qualquer um deles, para que um desenvolvedor possa escolher um tipo de base. Alguém poderia explicar, por favor, o que estou perdendo? Eu acredito que isso pode fazer parte dessa pergunta. Ou devo postar outro sobre o trecho específico?Respostas:
Vamos dar o seu exemplo de uma classe Dog e Cat e ilustrar usando C #:
Tanto um cachorro quanto um gato são animais, especificamente mamíferos quadrúpedes (os animais são muito gerais). Vamos supor que você tenha uma classe abstrata Mammal, para os dois:
Essa classe base provavelmente terá métodos padrão, como:
Todos eles são comportamentos que têm mais ou menos a mesma implementação entre as duas espécies. Para definir isso, você terá:
Agora vamos supor que existem outros mamíferos, os quais geralmente veremos em um zoológico:
Isso ainda será válido porque no centro da funcionalidade
Feed()
eMate()
ainda será o mesmo.No entanto, girafas, rinocerontes e hipopótamos não são exatamente animais dos quais você pode criar animais de estimação. É aí que uma interface será útil:
A implementação do contrato acima não será a mesma entre um gato e um cachorro; colocar suas implementações em uma classe abstrata para herdar será uma má idéia.
Suas definições de cachorro e gato agora devem ter a seguinte aparência:
Teoricamente, você pode substituí-los de uma classe base mais alta, mas essencialmente uma interface permite adicionar apenas o que você precisa em uma classe sem a necessidade de herança.
Conseqüentemente, como você geralmente pode herdar apenas de uma classe abstrata (na maioria das linguagens OO de tipo estatístico, que é ... as exceções incluem C ++), mas pode implementar várias interfaces, isso permite que você construa objetos estritamente conforme necessário .
fonte
Bem, Josh Bloch disse a si mesmo no Effective Java 2d :
Preferir interfaces sobre classes abstratas
Alguns pontos principais:
Por outro lado, as interfaces são muito difíceis de evoluir. Se você adicionar um método a uma interface, ele interromperá todas as suas implementações.
PS .: Compre o livro. É muito mais detalhado.
fonte
Interfaces e classes base representam duas formas diferentes de relacionamentos.
A herança (classes base) representa um relacionamento "é-a". Por exemplo, um cachorro ou um gato "é um" animal de estimação. Esse relacionamento sempre representa o objetivo (único) da classe (em conjunto com o "princípio de responsabilidade única" ).
As interfaces , por outro lado, representam recursos adicionais de uma classe. Eu chamaria isso de um relacionamento "é", como em "
Foo
é descartável", daí aIDisposable
interface em C #.fonte
Estilo moderno é definir IPet e PetBase.
A vantagem da interface é que outro código pode usá-lo sem qualquer vínculo com outro código executável. Completamente "limpo". Também as interfaces podem ser misturadas.
Mas as classes base são úteis para implementações simples e utilitários comuns. Portanto, forneça também uma classe base abstrata para economizar tempo e código.
fonte
Interfaces
Classes base
fonte
Em geral, você deve favorecer interfaces sobre classes abstratas. Um motivo para usar uma classe abstrata é se você tiver uma implementação comum entre classes concretas. Obviamente, você ainda deve declarar uma interface (IPet) e ter uma classe abstrata (PetBase) implementando essa interface. Usando interfaces pequenas e distintas, você pode usar múltiplos para melhorar ainda mais a flexibilidade. As interfaces permitem a quantidade máxima de flexibilidade e portabilidade de tipos através dos limites. Ao passar referências entre fronteiras, sempre passe a interface e não o tipo concreto. Isso permite que o terminal receptor determine a implementação concreta e fornece flexibilidade máxima. Isso é absolutamente verdade ao programar de forma TDD / BDD.
O Gangue dos Quatro declarou em seu livro "Como a herança expõe uma subclasse aos detalhes da implementação de seus pais, é comum dizer que 'a herança quebra o encapsulamento". Eu acredito que isto seja verdade.
fonte
Isso é bastante específico do .NET, mas o manual de diretrizes de design da estrutura argumenta que, em geral, as classes oferecem mais flexibilidade em uma estrutura em evolução. Depois que uma interface é enviada, você não pode alterá-la sem quebrar o código que usou essa interface. Com uma classe, no entanto, você pode modificá-la e não quebrar o código vinculado a ela. Desde que você faça as modificações corretas, o que inclui adicionar novas funcionalidades, você poderá estender e evoluir seu código.
Krzysztof Cwalina diz na página 81:
Dito isto, certamente há um lugar para interfaces. Como diretriz geral, sempre forneça uma implementação abstrata de classe base de uma interface, como se fosse um exemplo de uma maneira de implementar a interface. Na melhor das hipóteses, essa classe base economizará muito trabalho.
fonte
Juan,
Eu gosto de pensar em interfaces como uma maneira de caracterizar uma classe. Uma classe específica de raça de cães, por exemplo, um YorkshireTerrier, pode ser descendente da classe de cães pais, mas também implementa IFurry, IStubby e IYippieDog. Portanto, a classe define o que é a classe, mas a interface nos diz coisas sobre ela.
A vantagem disso é que me permite, por exemplo, reunir todos os IYippieDog e jogá-los na minha coleção Ocean. Portanto, agora posso alcançar um conjunto específico de objetos e encontrar objetos que atendam aos critérios que estou examinando sem inspecionar a classe muito de perto.
Acho que as interfaces realmente devem definir um subconjunto do comportamento público de uma classe. Se ele define todo o comportamento público de todas as classes que implementam, geralmente não precisa existir. Eles não me dizem nada de útil.
Esse pensamento, porém, contraria a idéia de que toda classe deve ter uma interface e você deve codificar para a interface. Tudo bem, mas você acaba com muitas interfaces individuais para as classes e isso torna as coisas confusas. Entendo que a idéia é que realmente não custa nada para fazer e agora você pode trocar e devolver as coisas com facilidade. No entanto, acho que raramente faço isso. Na maioria das vezes, estou apenas modificando a classe existente e tenho exatamente os mesmos problemas que sempre tive se a interface pública dessa classe precisar ser alterada, exceto que agora tenho que alterá-la em dois lugares.
Então, se você pensa como eu, diria que gato e cachorro são IPettable. É uma caracterização que combina com os dois.
A outra parte disso é que eles devem ter a mesma classe base? A questão é se eles precisam ser tratados de maneira ampla como a mesma coisa. Certamente, ambos são animais, mas isso se encaixa em como vamos usá-los juntos.
Digamos que eu queira reunir todas as classes de animais e colocá-las no meu contêiner de arca.
Ou eles precisam ser mamíferos? Talvez precisemos de algum tipo de fábrica de ordenha para animais?
Eles ainda precisam estar ligados? É suficiente apenas saber que ambos são IPettable?
Muitas vezes sinto o desejo de derivar toda uma hierarquia de classe quando realmente preciso apenas de uma classe. Faço isso antecipadamente um dia, talvez precise e geralmente nunca preciso. Mesmo quando o faço, geralmente acho que tenho que fazer muito para corrigi-lo. Isso porque a primeira classe que estou criando não é o Cão, não tenho tanta sorte, é o Ornitorrinco. Agora toda a minha hierarquia de classes é baseada no caso bizarro e tenho muito código desperdiçado.
Você também pode descobrir em algum momento que nem todos os gatos são IPettable (como aquele sem pêlos). Agora você pode mover essa interface para todas as classes derivadas que se encaixam. Você descobrirá que uma mudança muito menor é que, de repente, os gatos não são mais derivados do PettableBase.
fonte
Aqui está a definição básica e simples da interface e da classe base:
Felicidades
fonte
Eu recomendo usar composição em vez de herança sempre que possível. Use interfaces, mas use objetos membros para implementação básica. Dessa forma, você pode definir uma fábrica que construa seus objetos para se comportarem de uma certa maneira. Se você quiser alterar o comportamento, crie um novo método de fábrica (ou fábrica abstrata) que crie diferentes tipos de subobjetos.
Em alguns casos, você pode achar que seus objetos principais não precisam de interfaces, se todo o comportamento mutável estiver definido nos objetos auxiliares.
Portanto, em vez de IPet ou PetBase, você pode acabar com um Pet com um parâmetro IFurBehavior. O parâmetro IFurBehavior é definido pelo método CreateDog () do PetFactory. É esse parâmetro que é chamado para o método shed ().
Se você fizer isso, verá que seu código é muito mais flexível e a maioria dos seus objetos simples lida com comportamentos básicos do sistema.
Eu recomendo esse padrão mesmo em idiomas de herança múltipla.
fonte
É bem explicado neste artigo do Java World .
Pessoalmente, costumo usar interfaces para definir interfaces - isto é, partes do design do sistema que especificam como algo deve ser acessado.
Não é incomum que eu tenha uma classe implementando uma ou mais interfaces.
Classes abstratas que uso como base para outra coisa.
A seguir, um extrato do artigo mencionado acima, artigo JavaWorld.com, autor Tony Sintes, 20/04/01
Alguns dizem que você deve definir todas as classes em termos de interfaces, mas acho que a recomendação parece um pouco extremada. Uso interfaces quando vejo que algo no meu design muda frequentemente.
fonte
Lembre-se também de não se deixar levar pelo OO ( consulte o blog ) e sempre modele objetos com base no comportamento necessário, se você estava projetando um aplicativo em que o único comportamento necessário era um nome genérico e uma espécie para um animal, você só precisaria uma classe Animal com uma propriedade para o nome, em vez de milhões de classes para todos os animais possíveis no mundo.
fonte
Eu tenho uma regra geral
Funcionalidade: provável que seja diferente em todas as partes: Interface.
Dados e funcionalidade, partes serão basicamente os mesmos, partes diferentes: classe abstrata.
Dados e funcionalidade, realmente funcionando, se estendidos apenas com pequenas alterações: classe comum (concreta)
Dados e funcionalidade, sem alterações planejadas: classe comum (concreta) com modificador final.
Dados e talvez funcionalidade: somente leitura: membros da enumeração.
Isso é muito difícil e pronto e não é estritamente definido, mas existe um espectro de interfaces em que tudo deve ser alterado para enumerações em que tudo é corrigido um pouco como um arquivo somente leitura.
fonte
As interfaces devem ser pequenas. Muito pequeno. Se você realmente está dividindo seus objetos, suas interfaces provavelmente conterão apenas alguns métodos e propriedades muito específicos.
Classes abstratas são atalhos. Existem coisas que todos os derivados do PetBase compartilham que você pode codificar uma vez e terminar? Se sim, é hora de uma aula abstrata.
Classes abstratas também são limitantes. Embora eles ofereçam um ótimo atalho para a produção de objetos filho, qualquer objeto específico pode implementar apenas uma classe abstrata. Muitas vezes, acho isso uma limitação das classes Abstratas, e é por isso que uso muitas interfaces.
Classes abstratas podem conter várias interfaces. Sua classe abstrata do PetBase pode implementar IPet (animais de estimação têm proprietários) e IDigestion (animais de estimação comem, ou pelo menos deveriam). No entanto, o PetBase provavelmente não implementará o IMammal, pois nem todos os animais de estimação são mamíferos e nem todos os mamíferos são animais de estimação. Você pode adicionar um MammalPetBase que estende o PetBase e adicionar IMammal. O FishBase pode ter o PetBase e adicionar o IFish. O IFish teria ISwim e IUnderwaterBreather como interfaces.
Sim, meu exemplo é muito complicado para o exemplo simples, mas isso faz parte da grande parte de como interfaces e classes abstratas funcionam juntas.
fonte
Fonte : http://jasonroell.com/2014/12/09/interfaces-vs-abstract-classes-what-should-you-use/
C # é uma linguagem maravilhosa que amadureceu e evoluiu nos últimos 14 anos. Isso é ótimo para nós, desenvolvedores, porque uma linguagem madura nos fornece uma infinidade de recursos de linguagem que estão à nossa disposição.
No entanto, com muito poder se torna muita responsabilidade. Alguns desses recursos podem ser mal utilizados ou, às vezes, é difícil entender por que você escolheria usar um recurso em detrimento de outro. Ao longo dos anos, um recurso com o qual eu tenho visto muitos desenvolvedores se debater é quando optar por usar uma interface ou usar uma classe abstrata. Ambos têm vantagens e desvantagens e a hora e o local corretos para usar cada um. Mas como nós decidimos ???
Ambos fornecem a reutilização de funcionalidades comuns entre tipos. A diferença mais óbvia imediatamente é que as interfaces não fornecem implementação para sua funcionalidade, enquanto as classes abstratas permitem implementar algum comportamento "básico" ou "padrão" e, em seguida, têm a capacidade de "substituir" esse comportamento padrão pelos tipos derivados de classes, se necessário .
Tudo está bem e fornece uma ótima reutilização de código e segue o princípio de desenvolvimento de software DRY (Não se repita). As aulas abstratas são ótimas para usar quando você tem um relacionamento "é um".
Por exemplo: Um golden retriever "é um" tipo de cachorro. Então é um poodle. Ambos podem latir, como todos os cães. No entanto, você pode indicar que o parque de poodle é significativamente diferente do latido de cachorro "padrão". Portanto, pode fazer sentido implementar algo da seguinte maneira:
Como você pode ver, essa seria uma ótima maneira de manter seu código DRY e permitir que a implementação da classe base seja chamada quando qualquer um dos tipos puder confiar apenas no Bark padrão em vez de uma implementação de caso especial. As classes como GoldenRetriever, Boxer, Lab poderiam herdar o Bark "padrão" (classe de baixo) sem nenhum custo, apenas porque implementam a classe abstrata Dog.
Mas tenho certeza que você já sabia disso.
Você está aqui porque deseja entender por que pode escolher uma interface em vez de uma classe abstrata ou vice-versa. Bem, um motivo pelo qual você pode escolher uma interface em vez de uma classe abstrata é quando você não possui ou deseja impedir uma implementação padrão. Isso geralmente ocorre porque os tipos que estão implementando a interface não relacionados em um relacionamento "é um". Na verdade, eles não precisam estar relacionados, exceto pelo fato de que cada tipo "é capaz" ou tem "a capacidade" de fazer algo ou ter algo.
Agora, o que diabos isso significa? Bem, por exemplo: um humano não é um pato ... e um pato não é um humano. Muito obvio. No entanto, tanto um pato quanto um humano têm "a capacidade" de nadar (já que o humano passou nas aulas de natação na 1ª série :)). Além disso, como um pato não é humano ou vice-versa, isso não é um relacionamento "é um", mas sim um relacionamento "capaz" e podemos usar uma interface para ilustrar isso:
O uso de interfaces como o código acima permitirá que você passe um objeto para um método que "é capaz" de fazer alguma coisa. O código não se importa com o que faz ... Tudo o que sabe é que ele pode chamar o método Swim nesse objeto e esse objeto saberá qual comportamento é executado no tempo de execução com base em seu tipo.
Mais uma vez, isso ajuda seu código a ficar SECO para que você não precise escrever vários métodos que estão chamando o objeto para executar a mesma função principal (ShowHowHumanSwims (humano), ShowHowDuckSwims (duck), etc.)
O uso de uma interface aqui permite que os métodos de chamada não precisem se preocupar com que tipo é qual ou como o comportamento é implementado. Apenas sabe que, dada a interface, cada objeto precisará ter implementado o método Swim, para que seja seguro chamá-lo em seu próprio código e permitir que o comportamento do método Swim seja tratado dentro de sua própria classe.
Resumo:
Portanto, minha regra principal é usar uma classe abstrata quando você deseja implementar uma funcionalidade "padrão" para uma hierarquia de classes ou / e as classes ou tipos com os quais você está trabalhando compartilham um relacionamento "é um" (por exemplo, poodle "é um ”Tipo de cachorro).
Por outro lado, use uma interface quando você não tem um relacionamento "é um", mas tem tipos que compartilham "a capacidade" de fazer algo ou ter algo (por exemplo, Duck "não é" um ser humano. No entanto, Duck e Human compartilham “A capacidade” de nadar).
Outra diferença a ser observada entre as classes abstratas e as interfaces é que uma classe pode implementar uma a várias interfaces, mas uma classe só pode herdar de UMA classe abstrata (ou qualquer outra classe). Sim, você pode aninhar classes e ter uma hierarquia de herança (que muitos programas fazem e deveriam ter), mas não é possível herdar duas classes em uma definição de classe derivada (essa regra se aplica ao C #. Em outros idiomas, você pode fazer isso, geralmente apenas por falta de interfaces nessas linguagens).
Lembre-se também ao usar interfaces para aderir ao Princípio de Segregação de Interface (ISP). O ISP declara que nenhum cliente deve ser forçado a depender dos métodos que não usa. Por esse motivo, as interfaces devem se concentrar em tarefas específicas e geralmente são muito pequenas (por exemplo, IDisposable, IComparable).
Outra dica é se você estiver desenvolvendo pequenos e concisos bits de funcionalidade, use interfaces. Se você estiver projetando grandes unidades funcionais, use uma classe abstrata.
Espero que isso esclareça as coisas para algumas pessoas!
Além disso, se você puder pensar em exemplos melhores ou quiser apontar algo, faça-o nos comentários abaixo!
fonte
O caso das Classes base sobre interfaces foi explicado bem nas Diretrizes de codificação do submain .NET:
fonte
Uma diferença importante é que você pode herdar apenas uma classe base, mas pode implementar muitas interfaces. Portanto, você só deseja usar uma classe base se tiver certeza absoluta de que não precisará herdar também uma classe base diferente. Além disso, se você achar que sua interface está ficando grande, comece a dividi-la em algumas partes lógicas que definem a funcionalidade independente, já que não há regra de que sua classe não possa implementar todas (ou você pode definir uma configuração diferente). interface que apenas herda todos eles para agrupá-los).
fonte
Quando comecei a aprender sobre programação orientada a objetos, cometi o erro fácil e provavelmente comum de usar a herança para compartilhar comportamentos comuns - mesmo quando esse comportamento não era essencial à natureza do objeto.
Para desenvolver ainda mais um exemplo muito usado nessa questão em particular, há muitas coisas que podem ser usadas - namoradas, carros, cobertores felpudos ... - então eu poderia ter uma classe Petable que forneceu esse comportamento comum e várias classes herdadas a partir dele.
No entanto, ser petável não faz parte da natureza de nenhum desses objetos. Existem conceitos muito mais importantes que são essenciais à sua natureza - a namorada é uma pessoa, o carro é um veículo terrestre, o gato é um mamífero ...
Os comportamentos devem ser atribuídos primeiro às interfaces (incluindo a interface padrão da classe) e promovidos a uma classe base apenas se forem (a) comuns a um grande grupo de classes que são subconjuntos de uma classe maior - no mesmo sentido que "gato" e "pessoa" são subconjuntos de "mamífero".
O problema é que, depois de entender o design orientado a objetos suficientemente melhor do que eu entendi no início, você normalmente faz isso automaticamente, sem sequer pensar nisso. Portanto, a pura verdade da afirmação "codificar para uma interface, não para uma classe abstrata" torna-se tão óbvia que é difícil acreditar que alguém se daria ao trabalho de dizer isso - e começou a tentar ler outros significados.
Outra coisa que eu acrescentaria é que, se uma classe é puramente abstrata - sem membros ou métodos não abstratos e não herdados expostos a filhos, pais ou clientes -, por que é uma classe? Pode ser substituído, em alguns casos por uma interface e em outros casos por Null.
fonte
Preferir interfaces sobre classes abstratas
Justificativa, os principais pontos a serem considerados [dois já mencionados aqui] são:
Obviamente, o assunto já foi discutido detalhadamente em outros lugares [2,3].
[1] Ele adiciona mais código, é claro, mas se a brevidade é sua principal preocupação, você provavelmente deveria ter evitado o Java em primeiro lugar!
[2] Joshua Bloch, Java efetivo, itens 16-18.
[3] http://www.codeproject.com/KB/ar ...
fonte
Comentários anteriores sobre o uso de classes abstratas para implementação comum estão definitivamente em jogo. Um benefício que ainda não vi mencionado é que o uso de interfaces facilita muito a implementação de objetos simulados para fins de teste de unidade. Definir IPet e PetBase como Jason Cohen descreveu permite simular facilmente diferentes condições de dados, sem a sobrecarga de um banco de dados físico (até você decidir que é hora de testar a coisa real).
fonte
Não use uma classe base, a menos que você saiba o que significa e se aplica nesse caso. Se aplicável, use-o; caso contrário, use interfaces. Mas observe a resposta sobre pequenas interfaces.
A herança pública é usada em excesso no OOD e expressa muito mais do que a maioria dos desenvolvedores percebe ou está disposta a cumprir. Veja o princípio da substituibilidade de Liskov
Em suma, se A "é um" B, então A requer não mais que B e entrega não menos que B, para todo método exposto.
fonte
Outra opção a ter em mente é usar o relacionamento "tem-a", também conhecido como "é implementado em termos de" ou "composição". Às vezes, essa é uma maneira mais limpa e flexível de estruturar as coisas do que usar a herança "é-a".
Pode não fazer tanto sentido logicamente dizer que cachorro e gato "têm" um animal de estimação, mas evita várias armadilhas comuns de herança:
Sim, este exemplo mostra que há muita duplicação de código e falta de elegância para fazer as coisas dessa maneira. Mas também se deve considerar que isso ajuda a manter o cão e o gato separados da classe Pet (na medida em que o cão e o gato não têm acesso aos membros particulares do Pet) e deixa espaço para o cão e o gato herdarem de outra coisa. Possivelmente a classe Mammal.
A composição é preferível quando não é necessário acesso privado e você não precisa se referir a Cães e gatos usando referências / indicadores genéricos para animais de estimação. As interfaces fornecem esse recurso de referência genérico e podem ajudar a reduzir a verbosidade do seu código, mas também podem ofuscar as coisas quando estão mal organizadas. A herança é útil quando você precisa de acesso de membro privado e, ao usá-lo, está se comprometendo a acoplar altamente suas classes Cão e Gato à sua classe Pet, o que é um alto custo a pagar.
Entre herança, composição e interfaces, não existe uma maneira sempre certa e ajuda a considerar como as três opções podem ser usadas em harmonia. Dos três, a herança geralmente é a opção que deve ser usada com menos frequência.
fonte
Conceitualmente, uma interface é usada para definir formal e semi-formalmente um conjunto de métodos que um objeto fornecerá. Formalmente significa um conjunto de nomes e assinaturas de métodos e semi-formalmente significa documentação legível por humanos associada a esses métodos.
Interfaces são apenas descrições de uma API (afinal, API significa interface de programação de aplicativos ), não podem conter nenhuma implementação e não é possível usar ou executar uma interface. Eles apenas explicitam o contrato de como você deve interagir com um objeto.
As classes fornecem uma implementação e podem declarar que implementam zero, uma ou mais interfaces. Se uma classe deve ser herdada, a convenção é prefixar o nome da classe com "Base".
Há uma distinção entre uma classe base e uma classe base abstrata (ABC). ABCs combinam interface e implementação. Resumo fora da programação do computador significa "resumo", ou seja, "resumo == interface". A classe base abstrata pode descrever uma interface, bem como uma implementação vazia, parcial ou completa que deve ser herdada.
As opiniões sobre quando usar interfaces versus classes básicas abstratas versus apenas classes variam muito, com base no que você está desenvolvendo e em qual idioma você está desenvolvendo. As interfaces geralmente são associadas apenas a linguagens estaticamente tipadas como Java ou C #, mas linguagens dinamicamente tipadas também podem ter interfaces e classes base abstratas . Em Python, por exemplo, a distinção é esclarecida entre uma Classe, que declara que implementa uma interface , e um objeto, que é uma instância de uma classe , e é dito que fornece essa interface. Em uma linguagem dinâmica, é possível que dois objetos que são ambas instâncias da mesma classe possam declarar que fornecem interfaces completamente diferentes . No Python, isso só é possível para atributos de objeto, enquanto métodos são estado compartilhado entre todos os objetos de uma classe . No entanto, no Ruby, os objetos podem ter métodos por instância, portanto, é possível que a interface entre dois objetos do mesmo classe possa variar tanto quanto o programador desejar (no entanto, o Ruby não tem nenhuma maneira explícita de declarar interfaces).
Em linguagens dinâmicas, a interface para um objeto geralmente é assumida implicitamente, seja pela introspecção de um objeto e perguntando quais métodos ele fornece ( observe antes de pular ) ou, de preferência, simplesmente tentando usar a interface desejada em um objeto e capturando exceções se o objeto não fornece essa interface (é mais fácil pedir perdão do que permissão ). Isso pode levar a "falsos positivos", onde duas interfaces têm o mesmo nome de método, mas são semanticamente diferentes. No entanto, a desvantagem é que seu código é mais flexível, pois você não precisa especificar muito de antemão para antecipar todos os usos possíveis do seu código.
fonte
Depende de suas necessidades. Se o IPet for simples o suficiente, eu preferiria implementar isso. Caso contrário, se o PetBase implementar uma tonelada de funcionalidades que você não deseja duplicar, faça isso.
A desvantagem de implementar uma classe base é o requisito para
override
(ounew
) métodos existentes. Isso os torna métodos virtuais, o que significa que você deve ter cuidado com o uso da instância do objeto.Por fim, a herança única do .NET me mata. Um exemplo ingênuo: digamos que você está fazendo um controle de usuário e herda
UserControl
. Mas agora você está impedido de herdar tambémPetBase
. Isso obriga a reorganizar, como tornar umPetBase
membro da classe.fonte
Normalmente, eu também não implemento até precisar de um. Eu sou a favor das interfaces em detrimento das classes abstratas, porque isso oferece um pouco mais de flexibilidade. Se houver um comportamento comum em algumas das classes herdadas, eu subo e faço uma classe base abstrata. Não vejo a necessidade de ambos, já que eles essencialmente servem o mesmo objetivo, e ter ambos é um mau cheiro (imho) de código que a solução foi projetada em excesso.
fonte
Em relação ao C #, em alguns sentidos, interfaces e classes abstratas podem ser intercambiáveis. No entanto, as diferenças são: i) interfaces não podem implementar código; ii) por causa disso, as interfaces não podem chamar mais a pilha para a subclasse; e iii) somente a classe abstrata pode ser herdada em uma classe, enquanto várias interfaces podem ser implementadas em uma classe.
fonte
Por definição, a interface fornece uma camada para se comunicar com outro código. Todas as propriedades e métodos públicos de uma classe são, por padrão, implementando uma interface implícita. Também podemos definir uma interface como uma função, sempre que qualquer classe precisar desempenhar essa função, ela deve implementá-la, oferecendo-lhe diferentes formas de implementação, dependendo da classe que a implementa. Portanto, quando você fala sobre interface, você está falando sobre polimorfismo e quando você está falando sobre classe base, você está falando sobre herança. Dois conceitos de oops !!!
fonte
Descobri que um padrão de Interface> Resumo> Concreto funciona no seguinte caso de uso:
A classe abstrata define atributos compartilhados padrão das classes concretas, mas reforça a interface. Por exemplo:
Agora, como todos os mamíferos têm cabelos e mamilos (AFAIK, eu não sou zoólogo), podemos incluir isso na classe base abstrata
E então as classes concretas apenas definem que andam de pé.
Esse design é bom quando há muitas classes concretas e você não deseja manter o clichê apenas para programar em uma interface. Se novos métodos fossem adicionados à interface, isso quebraria todas as classes resultantes, portanto você ainda obterá as vantagens da abordagem da interface.
Nesse caso, o resumo poderia muito bem ser concreto; no entanto, a designação abstrata ajuda a enfatizar que esse padrão está sendo empregado.
fonte
Um herdeiro de uma classe base deve ter um relacionamento "é um". Interface representa Um relacionamento "implementa um". Portanto, use apenas uma classe base quando seus herdeiros manterem o relacionamento.
fonte
Use Interfaces para impor um contrato às famílias de classes não relacionadas. Por exemplo, você pode ter métodos de acesso comuns para classes que representam coleções, mas contém dados radicalmente diferentes, ou seja, uma classe pode representar um conjunto de resultados de uma consulta, enquanto a outra pode representar as imagens em uma galeria. Além disso, você pode implementar várias interfaces, permitindo combinar (e significar) os recursos da classe.
Use Herança quando as classes tiverem um relacionamento comum e, portanto, possuam uma assinatura estrutural e comportamental semelhante, ou seja, Carro, Moto, Caminhão e SUV são todos os tipos de veículos rodoviários que podem conter várias rodas, uma velocidade máxima
fonte