Essa pode ser uma pergunta genérica de POO. Eu queria fazer uma comparação genérica entre uma interface e uma classe abstrata com base em seu uso.
Quando alguém iria querer usar uma interface e quando alguém iria querer usar uma classe abstrata ?
Essa pode ser uma pergunta genérica de POO. Eu queria fazer uma comparação genérica entre uma interface e uma classe abstrata com base em seu uso.
Quando alguém iria querer usar uma interface e quando alguém iria querer usar uma classe abstrata ?
Respostas:
Eu escrevi um artigo sobre isso:
Classes abstratas e interfaces
Resumindo:
Quando falamos sobre classes abstratas, estamos definindo características de um tipo de objeto; especificando o que é um objeto .
Quando falamos sobre uma interface e definimos os recursos que prometemos fornecer, estamos falando em estabelecer um contrato sobre o que o objeto pode fazer.
Interfaces do not express something like "a Doberman is a type of dog and every dog can walk" but more like "this thing can walk"
. Obrigado
Use abstract classes and inheritance if you can make the statement “A is a B”. Use interfaces if you can make the statement “A is capable of [doing] as”
Uma classe abstrata pode ter estado ou funcionalidade compartilhada. Uma interface é apenas uma promessa para fornecer o estado ou a funcionalidade. Uma boa classe abstrata reduzirá a quantidade de código que precisa ser reescrita porque sua funcionalidade ou estado pode ser compartilhado. A interface não possui informações definidas para serem compartilhadas
Pessoalmente, quase nunca tenho a necessidade de escrever aulas abstratas.
Na maioria das vezes eu vejo as classes abstratas sendo (mis) usadas, é porque o autor da classe abstrata está usando o padrão "Método de modelo".
O problema com o "método Template" é que ele quase sempre é reentrante - a classe "derivada" sabe não apenas sobre o método "abstrato" de sua classe base que está implementando, mas também sobre os métodos públicos da classe base , mesmo que na maioria das vezes não precise chamá-los.
Exemplo (simplificado demais):
abstract class QuickSorter
{
public void Sort(object[] items)
{
// implementation code that somewhere along the way calls:
bool less = compare(x,y);
// ... more implementation code
}
abstract bool compare(object lhs, object rhs);
}
Então, aqui, o autor desta classe escreveu um algoritmo genérico e pretende que as pessoas o usem "especializando-o", fornecendo seus próprios "ganchos" - nesse caso, um método "comparar".
Portanto, o uso pretendido é algo como isto:
class NameSorter : QuickSorter
{
public bool compare(object lhs, object rhs)
{
// etc.
}
}
O problema é que você juntou indevidamente dois conceitos:
No código acima, teoricamente, o autor do método "compare" pode reincidir novamente no método "Sort" da superclasse ... mesmo que na prática eles nunca desejem ou precisem fazer isso.
O preço pago por esse acoplamento desnecessário é que é difícil alterar a superclasse e, na maioria dos idiomas OO, é impossível alterá-lo em tempo de execução.
O método alternativo é usar o padrão de design "Estratégia":
interface IComparator
{
bool compare(object lhs, object rhs);
}
class QuickSorter
{
private readonly IComparator comparator;
public QuickSorter(IComparator comparator)
{
this.comparator = comparator;
}
public void Sort(object[] items)
{
// usual code but call comparator.Compare();
}
}
class NameComparator : IComparator
{
bool compare(object lhs, object rhs)
{
// same code as before;
}
}
Portanto, observe agora: tudo o que temos são interfaces e implementações concretas dessas interfaces. Na prática, você realmente não precisa de mais nada para fazer um projeto OO de alto nível.
Para "ocultar" o fato de termos implementado "classificação de nomes" usando uma classe "QuickSort" e um "NameComparator", ainda podemos escrever um método de fábrica em algum lugar:
ISorter CreateNameSorter()
{
return new QuickSorter(new NameComparator());
}
Sempre que houver uma classe abstrata, você poderá fazer isso ... mesmo quando houver um relacionamento reentrante natural entre a classe base e a classe derivada, geralmente vale a pena torná-las explícitas.
Um pensamento final: tudo o que fizemos acima é "compor" uma função "NameSorting" usando uma função "QuickSort" e uma função "NameComparison" ... em uma linguagem de programação funcional, esse estilo de programação se torna ainda mais natural, com menos código.
Se você está vendo java como linguagem OOP,
" interface não fornece implementação de método " não é mais válido com o lançamento do Java 8. Agora o java fornece implementação na interface para métodos padrão.
Em termos simples, eu gostaria de usar
interface: Para implementar um contrato por vários objetos não relacionados. Ele fornece a capacidade " TEM A ".
classe abstrata: Para implementar o mesmo ou diferente comportamento entre vários objetos relacionados. Estabelece uma relação" IS A ".
O site da Oracle fornece as principais diferenças entre interface
e abstract
classe.
Considere usar classes abstratas se:
Considere usar interfaces se:
Serializable
interface.Exemplo:
Classe abstrata ( IS A relação )
Leitor é uma classe abstrata.
BufferedReader é umReader
O FileReader é umReader
FileReader
e BufferedReader
são usados para fins comuns: leitura de dados e são relacionados por meio deReader
classe.
Interface ( capacidade HAS A )
Serializable é uma interface.
Suponha que você tenha duas classes em seu aplicativo, que estão implementando a Serializable
interface
Employee implements Serializable
Game implements Serializable
Aqui você não pode estabelecer nenhuma relação por meio da Serializable
interface entre Employee
e Game
, que é para fins diferentes. Ambos são capazes de serializar o estado e a comparação termina aí.
Dê uma olhada nessas postagens:
Como devo ter explicado a diferença entre uma interface e uma classe abstrata?
OK, tendo acabado de "grunhir" isso sozinho - aqui está nos termos dos leigos (fique à vontade para me corrigir se eu estiver errado) - eu sei que esse tópico é demais, mas alguém pode tropeçar nele um dia ...
As classes abstratas permitem criar um blueprint, além de CONSTRUIR (implementar) propriedades e métodos que você deseja que TODOS os seus descendentes possuam.
Uma interface, por outro lado, permite apenas declarar que você deseja que propriedades e / ou métodos com um determinado nome existam em todas as classes que a implementam - mas não especifica como você deve implementá-la. Além disso, uma classe pode implementar MUITAS interfaces, mas só pode estender UMA classe Abstrata. Uma interface é mais uma ferramenta de arquitetura de alto nível (que fica mais clara se você começar a entender os padrões de design) - um resumo tem um pé nos dois campos e também pode realizar parte do trabalho sujo.
Por que usar um sobre o outro? O primeiro permite uma definição mais concreta de descendentes - o segundo permite um maior polimorfismo . Este último ponto é importante para o usuário final / codificador, que pode utilizar essas informações para implementar o AP I (interface) em uma variedade de combinações / formas para atender às suas necessidades.
Eu acho que esse foi o momento da "lâmpada" para mim - pense nas interfaces menos da perspectiva do autor e mais da de qualquer codificador vindo mais tarde na cadeia que esteja adicionando implementação a um projeto ou estendendo uma API.
Meus dois centavos:
Uma interface basicamente define um contrato, ao qual qualquer classe de implementação deve aderir (implementar os membros da interface). Não contém nenhum código.
Por outro lado, uma classe abstrata pode conter código e pode haver alguns métodos marcados como abstratos que uma classe herdada deve implementar.
As raras situações em que usei classes abstratas são quando tenho algumas funcionalidades padrão nas quais a classe herdada pode não ser interessante em substituir, por exemplo, uma classe base abstrata, da qual algumas classes especializadas herdam.
Exemplo (muito rudimentar!): Considere uma classe base chamada Customer, que possui métodos abstratos como CalculatePayment()
, CalculateRewardPoints()
e alguns métodos não abstratos comoGetName()
, SavePaymentDetails()
.
Classes especializadas gostam RegularCustomer
e GoldCustomer
herdarão da Customer
classe base e implementarão sua própria lógica CalculatePayment()
e o CalculateRewardPoints()
método, mas reutilizarão a classeGetName()
e SavePaymentDetails()
métodos.
Você pode adicionar mais funcionalidades a uma classe abstrata (métodos não abstratos) sem afetar as classes filho que estavam usando uma versão mais antiga. Enquanto a adição de métodos a uma interface afetaria todas as classes que a implementam, uma vez que precisariam agora implementar os membros da interface recém-adicionados.
Uma classe abstrata com todos os membros abstratos seria semelhante a uma interface.
Quando fazer o que é uma coisa muito simples, se você tiver o conceito claro em sua mente.
Classes abstratas podem ser derivadas, enquanto as interfaces podem ser implementadas. Há alguma diferença entre os dois. Quando você deriva de uma classe Abstract, o relacionamento entre a classe derivada e a classe base é 'é um'. por exemplo, um cão é um animal, uma ovelha é um animal, o que significa que uma classe derivada está herdando algumas propriedades da classe base.
Enquanto na implementação de interfaces, o relacionamento é "pode ser". por exemplo, um cão pode ser um cão espião. Um cachorro pode ser um cachorro de circo. Um cão pode ser um cão de corrida. O que significa que você implementa certos métodos para adquirir algo.
Espero estar claro.
1. Se você estiver criando algo que fornece funcionalidade comum para classes não relacionadas, use uma interface.
2. Se você estiver criando algo para objetos que estão intimamente relacionados em uma hierarquia, use uma classe abstrata.
Escrevi um artigo sobre quando usar uma classe abstrata e quando usar uma interface. Existe muito mais diferença entre eles do que "um IS-A ... e um CAN-DO ...". Para mim, essas são respostas enlatadas. Menciono alguns motivos para usar um deles. Espero que ajude.
Eu acho que a maneira mais sucinta de colocar isso é a seguinte:
Propriedades compartilhadas => classe abstrata.
Funcionalidade compartilhada => interface.
E para dizer de forma menos sucinta ...
Exemplo de classe abstrata:
public abstract class BaseAnimal
{
public int NumberOfLegs { get; set; }
protected BaseAnimal(int numberOfLegs)
{
NumberOfLegs = numberOfLegs;
}
}
public class Dog : BaseAnimal
{
public Dog() : base(4) { }
}
public class Human : BaseAnimal
{
public Human() : base(2) { }
}
Como os animais têm uma propriedade compartilhada - número de pernas neste caso - faz sentido criar uma classe abstrata contendo essa propriedade compartilhada. Isso também nos permite escrever código comum que opera nessa propriedade. Por exemplo:
public static int CountAllLegs(List<BaseAnimal> animals)
{
int legCount = 0;
foreach (BaseAnimal animal in animals)
{
legCount += animal.NumberOfLegs;
}
return legCount;
}
Exemplo de interface:
public interface IMakeSound
{
void MakeSound();
}
public class Car : IMakeSound
{
public void MakeSound() => Console.WriteLine("Vroom!");
}
public class Vuvuzela : IMakeSound
{
public void MakeSound() => Console.WriteLine("VZZZZZZZZZZZZZ!");
}
Observe aqui que Vuvuzelas e Carros são coisas completamente diferentes, mas eles têm uma funcionalidade compartilhada: fazer um som. Assim, uma interface faz sentido aqui. Além disso, permitirá que os programadores agrupem coisas que emitem sons sob uma interface comum - IMakeSound
neste caso. Com esse design, você pode escrever o seguinte código:
List<IMakeSound> soundMakers = new List<ImakeSound>();
soundMakers.Add(new Car());
soundMakers.Add(new Vuvuzela());
soundMakers.Add(new Car());
soundMakers.Add(new Vuvuzela());
soundMakers.Add(new Vuvuzela());
foreach (IMakeSound soundMaker in soundMakers)
{
soundMaker.MakeSound();
}
Você pode dizer o que isso resultaria?
Por fim, você pode combinar os dois.
Exemplo combinado:
public interface IMakeSound
{
void MakeSound();
}
public abstract class BaseAnimal : IMakeSound
{
public int NumberOfLegs { get; set; }
protected BaseAnimal(int numberOfLegs)
{
NumberOfLegs = numberOfLegs;
}
public abstract void MakeSound();
}
public class Cat : BaseAnimal
{
public Cat() : base(4) { }
public override void MakeSound() => Console.WriteLine("Meow!");
}
public class Human : BaseAnimal
{
public Human() : base(2) { }
public override void MakeSound() => Console.WriteLine("Hello, world!");
}
Aqui, exigimos que todos BaseAnimal
façam um som, mas ainda não sabemos sua implementação. Nesse caso, podemos abstrair a implementação da interface e delegar sua implementação às suas subclasses.
Um último ponto, lembre-se de que, no exemplo da classe abstrata, fomos capazes de operar nas propriedades compartilhadas de objetos diferentes e no exemplo da interface, fomos capazes de invocar a funcionalidade compartilhada de objetos diferentes? Neste último exemplo, poderíamos fazer as duas coisas.
Quando preferir uma classe abstrata à interface?
Quando preferir uma interface à classe abstrata?
As classes podem herdar de apenas uma classe base; portanto, se você deseja usar classes abstratas para fornecer polimorfismo a um grupo de classes, todas elas devem herdar dessa classe. As classes abstratas também podem fornecer membros que já foram implementados. Portanto, você pode garantir uma certa quantidade de funcionalidade idêntica a uma classe abstrata, mas não com uma interface.
Aqui estão algumas recomendações para ajudá-lo a decidir se deve usar uma interface ou uma classe abstrata para fornecer polimorfismo para seus componentes.
Copiado de:
http://msdn.microsoft.com/en-us/library/scsyfw1d%28v=vs.71%29.aspx
Considere usar classes abstratas se alguma destas instruções se aplicar à sua situação:
Considere usar interfaces se alguma destas instruções se aplicar à sua situação:
As respostas variam entre os idiomas. Por exemplo, em Java, uma classe pode implementar (herdar de) várias interfaces, mas herdar apenas de uma classe abstrata. Portanto, as interfaces oferecem mais flexibilidade. Mas isso não é verdade em C ++.
Para mim, eu usaria interfaces em muitos casos. Mas eu prefiro aulas abstratas em alguns casos.
As classes em OO geralmente se referem à implementação. Uso classes abstratas quando quero forçar alguns detalhes de implementação para os filhos, caso contrário eu vou com interfaces.
Obviamente, as classes abstratas são úteis não apenas para forçar a implementação, mas também para compartilhar alguns detalhes específicos entre muitas classes relacionadas.
Use uma classe abstrata se desejar fornecer algumas implementações básicas.
em java, você pode herdar de uma classe (abstrata) para "fornecer" a funcionalidade e implementar várias interfaces para "garantir" a funcionalidade
Puramente com base na herança, você usaria um Resumo em que está definindo relacionamentos abstratos claramente descendentes (ou seja, animal-> gato) e / ou requer a herança de propriedades virtuais ou não públicas, especialmente o estado compartilhado (que a Interfaces não pode suportar )
Você deve tentar favorecer a composição (via injeção de dependência) sobre a herança, onde puder, e observe que as Interfaces sendo contratos suportam testes de unidade, separação de preocupações e (variação de idioma) herança múltipla de uma maneira que os Abstracts não podem.
Um local interessante em que as interfaces se saem melhor do que as classes abstratas é quando você precisa adicionar funcionalidade extra a um grupo de objetos (relacionados ou não). Se você não pode fornecer a eles uma classe abstrata base (por exemplo, eles são sealed
ou já têm um pai), você pode fornecer uma interface fictícia (vazia) e simplesmente escrever métodos de extensão para essa interface.
Pode ser uma decisão muito difícil de fazer ...
Um ponteiro que posso dar: Um objeto pode implementar muitas interfaces, enquanto um objeto pode herdar apenas uma classe base (em uma linguagem OO moderna como c #, eu sei que o C ++ tem herança múltipla - mas isso não é desaprovado?)
Uma classe abstrata pode ter implementações.
Uma interface não possui implementações, simplesmente define um tipo de contrato.
Também pode haver algumas diferenças dependentes do idioma: por exemplo, o C # não tem herança múltipla, mas várias interfaces podem ser implementadas em uma classe.
A regra básica do polegar é: Para "Substantivos", use a classe Abstract e para "Verbos", use a interface
Por exemplo: car
é uma classe abstrata e drive
, podemos torná-la uma interface.
drive
no carro - que é uma classe abstrata.