Quando usar classes abstratas em vez de interfaces com métodos de extensão em C #?

69

"Classe abstrata" e "interface" são conceitos semelhantes, sendo a interface o mais abstrato dos dois. Um fator diferenciador é que classes abstratas fornecem implementações de métodos para classes derivadas quando necessário. Em C #, no entanto, esse fator de diferenciação foi reduzido pela introdução recente de métodos de extensão, que permitem a implementação de métodos de interface. Outro fator de diferenciação é que uma classe pode herdar apenas uma classe abstrata (ou seja, não há herança múltipla), mas pode implementar várias interfaces. Isso torna as interfaces menos restritivas e mais flexíveis. Então, em C #, quando deveríamos usar classes abstratas em vez de interfaces com métodos de extensão?

Um exemplo notável do modelo de método de interface + extensão é o LINQ, onde a funcionalidade de consulta é fornecida para qualquer tipo que implemente IEnumerable por meio de vários métodos de extensão.

    
por Gulshan 31.01.2011 / 10:17
fonte

7 respostas

61

Quando você precisar de uma parte da turma a ser implementada. O melhor exemplo que usei é o padrão método de modelo .

public abstract class SomethingDoer
{
    public void Do()
    {
        this.DoThis();
        this.DoThat();
    }

    protected abstract void DoThis();
    protected abstract void DoThat();
}

Assim, você pode definir as etapas que serão executadas quando Do () for chamado, sem conhecer as especificidades de como elas serão implementadas. Classes derivadas devem implementar os métodos abstratos, mas não o método Do ().

Os métodos de extensões não satisfazem necessariamente a parte "deve ser uma parte da classe" da equação. Além disso, iirc, os métodos de extensão não podem (parecer) ser algo além de público no escopo.

editar

A pergunta é mais interessante do que eu originalmente acreditava. Após um exame mais aprofundado, Jon Skeet respondeu a uma pergunta como esta em SO em favor de usando interfaces + métodos de extensão. Além disso, uma possível desvantagem está usando a reflexão em relação a uma hierarquia de objetos projetada dessa maneira .

Pessoalmente, estou tendo problemas para ver o benefício de alterar uma prática comum no momento, mas também vejo poucas ou nenhuma desvantagem em fazê-lo.

Deve-se notar que é possível programar desta maneira em muitos idiomas através de classes Utility. As extensões fornecem apenas o açúcar sintático para fazer com que os métodos pareçam pertencer à classe.

    
por 31.01.2011 / 11:15
fonte
24

É tudo sobre o que você quer modelar:

Classes abstratas funcionam por herança . Sendo apenas classes base especiais, elas modelam algumas relações é -a .

Por exemplo, um cachorro é um animal, por isso temos

class Dog : Animal { ... }

Como não faz sentido realmente criar um all-animal genérico (como seria?), nós fazemos isso Animal base class abstract - mas ainda é um classe base. E a classe Dog não faz sentido sem ser um Animal .

As

Interfaces , por outro lado, são uma história diferente. Eles não usam herança, mas fornecem polimorfismo (que pode ser implementado com herança também). Eles não modelam um relacionamento é-a , mas mais de um ele suporta .

Tome, por exemplo IComparable - um objeto que suporta a comparação com outro.

A funcionalidade de uma classe não depende das interfaces implementadas, a interface apenas fornece uma maneira genérica de acessar a funcionalidade. Poderíamos ainda Dispose de um Graphics ou um FileStream sem que eles implementassem IDisposable . A interface apenas relaciona os métodos juntos.

Em princípio, pode-se adicionar e remover interfaces como extensões sem alterar o comportamento de uma classe, apenas enriquecendo o acesso a ela. Você não pode tirar uma classe base, pois o objeto ficaria sem sentido!

    
por 31.01.2011 / 13:13
fonte
3

Acabei de perceber que não usei classes abstratas (pelo menos não criadas) em anos.

A classe abstrata é uma fera estranha entre interface e implementação. Há algo nas classes abstratas que formiga meu senso de aranha. Eu diria, não se deve "expor" a implementação por trás da interface de qualquer forma (ou fazer qualquer ligação).

Mesmo se houver necessidade de um comportamento comum entre as classes que implementam uma interface, eu usaria uma classe auxiliar independente, em vez de uma classe abstrata.

Eu iria para interfaces.

    
por 31.01.2011 / 11:06
fonte
2

IMHO, acho que há uma mistura de conceitos aqui.

As classes usam um certo tipo de herança, enquanto as interfaces usam um tipo diferente de herança.

Ambos os tipos de herança são importantes e úteis, e cada um tem seus prós e contras.

Vamos começar pelo começo.

A história com interfaces começa há muito tempo com o C ++. Em meados da década de 1980, quando o C ++ foi desenvolvido, a ideia de interfaces como um tipo diferente de tipo ainda não havia sido realizada (chegaria a tempo).

C ++ só tinha um tipo de herança, o tipo de herança usada por classes, chamada herança de implementação.

Para poder aplicar a recomendação do GoF Book: "Para programar para a interface, e não para a implementação", C ++ suportou classes abstratas e herança de múltiplas implementações para poder fazer quais interfaces em C # são capazes (e úteis! ) de fazer.

O C # introduz um novo tipo de tipo, interfaces e um novo tipo de herança, herança de interface, para oferecer pelo menos duas maneiras diferentes de suportar "Programar para a interface, e não para a implementação", com uma importante ressalva : C # suporta apenas herança múltipla com herança de interface (e não com herança de implementação).

Portanto, as razões arquiteturais por trás das interfaces em C # são a recomendação do GoF.

Espero que isso possa ajudar.

Atenciosamente, Gastón

    
por 03.09.2012 / 17:42
fonte
1

A aplicação de métodos de extensão a uma interface é útil para aplicar um comportamento comum entre classes que podem compartilhar apenas uma interface comum. Essas classes podem já existir e ser fechadas para extensões por outros meios.

Para novos designs, eu favoreceria o uso de métodos de extensão nas interfaces. Para uma hierarquia de tipos, os métodos de extensão fornecem um meio de estender o comportamento sem precisar abrir a hierarquia inteira para modificação.

No entanto, os métodos de extensão não conseguem acessar a implementação privada, portanto, no topo de uma hierarquia, se eu precisar encapsular a implementação privada por trás de uma interface pública, uma classe abstrata seria a única maneira.

    
por 31.01.2011 / 12:24
fonte
0

Eu acho que em C # herança múltipla não é suportada e é por isso que o conceito de interface é introduzido em C #.

No caso de classes abstratas, a herança múltipla também não é suportada. Portanto, é fácil decidir se usar classes ou interfaces abstratas.

    
por 20.12.2012 / 10:49
fonte
-1

Estou no processo de implementar uma classe abstrata no meu projeto, simplesmente porque C # não suporta operadores (conversões implícitas, no meu caso) em Interfaces.

    
por 30.05.2012 / 22:48
fonte