Interface ou classe abstrata: qual usar?

327

Por favor, explique quando devo usar um PHP interfacee quando devo usar um abstract class?

Como posso mudar minha entrada abstract classpara uma interface?

Darryl Hein
fonte

Respostas:

458

Use uma interface quando desejar forçar os desenvolvedores que trabalham em seu sistema (inclusive você) a implementar um número definido de métodos nas classes que criarão.

Use uma classe abstrata quando desejar forçar os desenvolvedores que trabalham em seu sistema (inclusive você) a implementar um número definido de métodos e desejar fornecer alguns métodos básicos que os ajudarão a desenvolver suas classes filho.

Outro aspecto a ter em mente é que as classes de clientes podem estender apenas uma classe abstrata, enquanto podem implementar várias interfaces. Portanto, se você estiver definindo seus contratos de comportamento em classes abstratas, isso significa que cada classe filho poderá estar em conformidade apenas com um único contrato. Às vezes, isso é uma coisa boa, quando você deseja forçar seus programadores de usuários por um caminho específico. Outras vezes seria ruim. Imagine se as interfaces Countable e Iterator do PHP fossem classes abstratas em vez de interfaces.

Uma abordagem comum quando você não tem certeza de qual caminho seguir (como mencionado no cletus abaixo ) é criar uma interface e fazer com que sua classe abstrata implemente essa interface.

Alan Storm
fonte
12
Eu estava tentando o dia inteiro entender os usos abstracte as interfaceaulas, sua postagem deixou tudo claro. Muito obrigado Alan
afarazit 21/11
4
Outra vantagem das classes abstratas é a capacidade de definir métodos abstratos protegidos . Nem sempre é útil, mas pode ser útil em algumas arquiteturas.
Netcoder
Assim, em muitos casos, devemos usar classe abstrata por causa da flexibilidade - que é a minha conclusão :)
ymakux
3
@ volocuga: não necessariamente, como Alan apontou, apenas um único resumo pode ser estendido. Pessoalmente, não gosto do resumo que implementa uma ideia de interface, porque contribui para a ofuscação do código e é menos direta, IMO.
Prefixo
171

As diferenças entre an Abstract Classe an Interface:

Classes abstratas

Uma classe abstrata pode fornecer algumas funcionalidades e deixar o resto para a classe derivada .

  • A classe derivada pode ou não substituir as funções concretas definidas na classe base.

  • Uma classe filha estendida de uma classe abstrata deve estar logicamente relacionada.

Interface

Uma interface não pode conter nenhuma funcionalidade . Ele contém apenas definições dos métodos.

  • A classe derivada DEVE fornecer código para todos os métodos definidos na interface .

  • Classes completamente diferentes e não relacionadas podem ser agrupadas logicamente usando uma interface.

kn3l
fonte
1
Você pode fornecer um exemplo da vida real para demonstrá-lo?
RN Kushwaha
1
Qual é a diferença entre abstract class X implements Ye class X implements Y?
Webinan 9/07/2015
3
@Webinan Ao abstract class X implements Ydeclarar que a funcionalidade em massa de X deve ser implementada em uma classe derivada e que a classe abstrata e derivada deve conter funções definidas em Y, enquanto class X implements Yapenas implica que a classe X deve conter funções definidas em Y. Se sua interface Y não se destina a ser implementado por nenhuma outra classe além de XI, na verdade, pularia a definição de Y como uma interface e implementaria apenas as funções em Y como função abstrata pública / protegida / privada para garantir que elas sejam implementadas na classe derivada.
Calle Bergström
1
Interfaces não pode unicamente conter definição dos métodos, eles também podem conter constantes
Thielicious
Gostei da sua comparação. Então, queria adicionar algo. As interfaces podem ter constantes de classe prontas para uso, enquanto a classe abstrata não pode.
Noman Ibrahim
128

Por que usar classes abstratas? O seguinte é um exemplo simples. Vamos dizer que temos o seguinte código:

<?php 

class Fruit {
    private $color;

    public function eat() {
        // chew
    }

    public function setColor($c) {
        $this->color = $c;
    }
}

class Apple extends Fruit {
    public function eat() {
        // chew until core
    }
}

class Orange extends Fruit {
    public function eat() {
        // peeling
        // chew
    }
}

Agora eu te dou uma maçã e você a come. Como é o sabor? Tem gosto de maçã.

<?php 
$apple = new Apple();
$apple->eat();

// Now I give you a fruit.
$fruit = new Fruit();
$fruit->eat();

Como é esse sabor? Bem, não faz muito sentido, então você não deve ser capaz de fazer isso. Isso é feito tornando a classe Fruit abstrata, bem como o método de comer dentro dela.

<?php 
abstract class Fruit {
    private $color;

    abstract public function eat(){}

    public function setColor($c) {
        $this->color = $c;
    }
}
?>

Uma classe abstrata é como uma interface, mas você pode definir métodos em uma classe abstrata, enquanto em uma interface todos são abstratos. As classes abstratas podem ter métodos vazios e de trabalho / concreto. Nas interfaces, as funções definidas lá não podem ter um corpo. Nas aulas abstratas, eles podem.

Um exemplo do mundo real:

<?php 
abstract class person {

    public $LastName;
    public $FirstName;
    public $BirthDate;

    abstract protected function write_info();
}

final class employee extends person{

    public $EmployeeNumber;
    public $DateHired;

    public function write_info(){
        //sql codes here
        echo "Writing ". $this->LastName . "'s info to emloyee dbase table <br>";   
    }
}

final class student extends person{

    public $StudentNumber;
    public $CourseName;

    public function write_info(){
        //sql codes here
        echo "Writing ". $this->LastName . "'s info to student dbase table <br>";
    }
}

///----------
$personA = new employee;
$personB = new student;

$personA->FirstName="Joe";
$personA->LastName="Sbody";

$personB->FirstName="Ben";
$personB->LastName="Dover";

$personA->write_info();
// Writing Sbody's info to emloyee dbase table
$personB->write_info();
// Writing Dover's info to student dbase table 
Vineesh Kalarickal
fonte
2
Olá, esta resposta provavelmente recebeu votos negativos devido à forma como é formatada. Seria bom se não fosse um grande bloco de código (quatro espaços transformam algo em um bloco de código, desenterre o texto para tirá-lo do bloco) e, se este foi copiado e colado de algum lugar (parece que sim) seria educado creditá-los.
Camilo Martin
9
Eu te amo pelo exemplo de fruta, cara! Desde que comecei a php aprendizado, essa exmaples me deixa claro muito obrigado
Raheel
23
+1 What does that taste like? Well, it doesn't make much sense, so you shouldn't be able to do that.Agora eu sei abstrato!
Webinan 9/07
O que a finalpalavra - chave faz? Ótimo post, obrigado.
Gus
1
@VineeshKalarickal O que não entendo no exemplo Person é a diferença entre: 1) usar a classe abstrata Person (como no exemplo); 2) escrevendo Person como uma classe padrão e fazendo Employee e Student substituir o método write_info ().
Ferex
66

A melhor prática é usar uma interface para especificar o contrato e uma classe abstrata como apenas uma implementação do mesmo. Essa classe abstrata pode preencher grande parte do clichê para que você possa criar uma implementação, substituindo apenas o que precisa ou deseja, sem forçar o uso de uma implementação específica.

cleto
fonte
37

Apenas para colocar isso na mistura, mas como Cletus mencionou o uso de uma interface em conjunto com uma classe abstrata, eu frequentemente uso a interface para esclarecer meu pensamento de design.

Por exemplo:

<?php
class parser implements parserDecoratorPattern {
    //...
}

Dessa forma, qualquer pessoa que esteja lendo meu código (e quem sabe o que é um Padrão Decorador) saberá imediatamente a) como eu construo meu analisador eb) ser capaz de ver quais métodos são usados ​​para implementar o padrão decorador.

Além disso, e eu posso estar fora da base aqui, não sendo um programador Java / C ++ / etc, mas os tipos de dados podem entrar em jogo aqui. Seus objetos são de um tipo e, quando você os distribui, é importante programaticamente. Mover seus itens contratáveis ​​para a interface apenas determina os tipos que os métodos retornam, mas não o tipo base da classe que os implementa.

É tarde e não consigo pensar em um exemplo melhor de psudo-código, mas aqui vai:

<?php
interface TelevisionControls {};
class Remote implements TelevisionControls {};
class Spouse implements TelevisionControls {};
Spouse spouse = new Spouse();
Remote remote = new Remote();
isSameType = (bool)(remote == spouse)
Austen Hoogen
fonte
1
Que exemplo incrível! ;)
Joel Murphy
@ matt2000 Não é sexista e agora também trabalha para casamentos do mesmo sexo. Ótima edição. :)
Austen Hoogen
4
Este é um exemplo incrível! No entanto, eu não acho que você pode instanciar uma classe abstrata, mas sim uma classe que se estende de uma classe abstrata
Arielle Nguyen
2
não mataria para fazer com que o código sudo parecesse pelo menos a linguagem em questão. alguém deve colocar alguns dólares lá.
Lutei com um urso uma vez.
2
Embora o exemplo seja engraçado, não podemos instanciar uma classe abstrata diretamente, faça alterações no exemplo para que as pessoas não considerem o uso válido no PHP.
saji89
16

A principal diferença é que uma classe abstrata pode conter implementação padrão, enquanto uma interface não.

Uma interface é um contrato de comportamento sem nenhuma implementação.

Mitch Wheat
fonte
16

Além disso, gostaria de acrescentar aqui que apenas porque qualquer outra linguagem OO tem algum tipo de interface e abstração também não significa que elas tenham o mesmo significado e propósito que no PHP. O uso de abstração / interfaces é um pouco diferente, enquanto as interfaces no PHP realmente não têm uma função real. Eles são usados ​​apenas por razões semânticas e relacionadas ao esquema. O objetivo é ter um projeto o mais flexível possível, expansível e seguro para futuras extensões, independentemente de o desenvolvedor ter posteriormente um plano de uso totalmente diferente ou não.

Se o seu inglês não é nativo, você pode pesquisar o que realmente são Abstração e Interfaces. E procure sinônimos também.

E isso pode ajudá-lo como uma metáfora:

INTERFACE

Digamos que você faça um novo tipo de bolo com morangos e criou uma receita descrevendo os ingredientes e as etapas. Só você sabe por que está gostando tão bem e seus convidados gostam. Então você decide publicar sua receita para que outras pessoas também possam experimentar esse bolo.

O ponto aqui é

- acertar
- tomar cuidado
- evitar coisas que podem dar errado (como morangos demais ou algo assim)
- facilitar as pessoas que experimentam
- dizer quanto tempo é o que fazer (como agitar )
- para dizer quais coisas você PODE fazer, mas NÃO PRECISA

Exatamente ISTO é o que descreve as interfaces. É um guia, um conjunto de instruções que observam o conteúdo da receita. É como se você criasse um projeto em PHP e desejasse fornecer o código no GitHub ou com seus companheiros ou qualquer outra coisa. Uma interface é o que as pessoas podem fazer e o que você não deve. Regras que o mantêm - se você desobedecer a uma, toda a construção será quebrada.


ABSTRAÇÃO

Para continuar com essa metáfora aqui ... imagine, você é o convidado dessa vez comendo aquele bolo. Então você está tentando esse bolo usando a receita agora. Mas você deseja adicionar novos ingredientes ou alterar / pular as etapas descritas na receita. Então, o que vem a seguir? Planeje uma versão diferente desse bolo. Desta vez com bagas pretas e não bagas de palha e mais creme de baunilha ... gostoso.

Isto é o que você poderia considerar uma extensão do bolo original. Você basicamente faz uma abstração criando uma nova receita porque é um lil diferente. Tem alguns novos passos e outros ingredientes. No entanto, a versão black berry tem algumas partes que você assumiu do original - essas são as etapas básicas que todo tipo de bolo deve ter. Como ingredientes como o leite - é o que toda classe derivada tem.

Agora você deseja trocar ingredientes e etapas e estas DEVEM ser definidas na nova versão desse bolo. Estes são métodos abstratos que precisam ser definidos para o novo bolo, porque deve haver uma fruta no bolo, mas quais? Então você pega as bagas pretas dessa vez. Feito.

Pronto, você estendeu o bolo, seguiu a interface e abstraiu as etapas e os ingredientes.

Thielicious
fonte
1
Esta tem sido minha comparação favorita de qualquer coisa relacionada ao PHP. Realmente fazia sentido. Obrigado!
cbloss793
13

Para adicionar algumas das já excelentes respostas:

  • As classes abstratas permitem fornecer algum grau de implementação; as interfaces são modelos puros. Uma interface pode apenas definir funcionalidade , nunca pode implementá-la.

  • Qualquer classe que implemente a interface se compromete a implementar todos os métodos que define ou deve ser declarada abstrata.

  • As interfaces podem ajudar a gerenciar o fato de que, como Java, o PHP não suporta herança múltipla. Uma classe PHP pode estender apenas um pai único. No entanto, você pode fazer uma promessa de classe para implementar quantas interfaces desejar.

  • tipo: para cada interface implementada, a classe assume o tipo correspondente. Como qualquer classe pode implementar uma interface (ou mais interfaces), as interfaces efetivamente associam tipos que, de outra forma, não são relacionados.

  • uma classe pode estender uma superclasse e implementar qualquer número de interfaces:

    class SubClass extends ParentClass implements Interface1, Interface2 {
        // ...
    }

Por favor, explique quando devo usar uma interface e quando devo usar a classe abstrata?

Use uma interface quando precisar fornecer apenas um modelo sem implementação do que nunca e deseja garantir que qualquer classe que implemente essa interface tenha os mesmos métodos que qualquer outra classe que a implemente (pelo menos).

Use uma classe abstrata quando desejar criar uma base para outros objetos (uma classe parcialmente construída). A classe que estende sua classe abstrata usará algumas propriedades ou métodos definidos / implementados:

<?php
// interface
class X implements Y { } // this is saying that "X" agrees to speak language "Y" with your code.

// abstract class
class X extends Y { } // this is saying that "X" is going to complete the partial class "Y".
?>

Como posso mudar minha classe abstrata para uma interface?

Aqui está um caso / exemplo simplificado. Retire todos os detalhes da implementação. Por exemplo, altere sua classe abstrata de:

abstract class ClassToBuildUpon {
    public function doSomething() {
          echo 'Did something.';
    }
}

para:

interface ClassToBuildUpon {
    public function doSomething();
}
bg17aw
fonte
12

Do ponto de vista filosófico:

  • Uma classe abstrata representa um relacionamento "é um". Digamos que eu tenha frutas, bem, eu teria uma classe abstrata Fruit que compartilhe responsabilidades e comportamentos comuns.

  • Uma interface representa um relacionamento "deve fazer". Uma interface, na minha opinião (que é a opinião de um desenvolvedor júnior), deve ser nomeada por uma ação ou algo próximo a uma ação (Desculpe, não consigo encontrar a palavra, eu não sou um falante nativo de inglês) digamos IEatable. Você sabe que pode ser comido, mas não sabe o que come.

Do ponto de vista da codificação:

  • Se seus objetos tiverem código duplicado, é uma indicação de que eles têm comportamento comum, o que significa que você pode precisar de uma classe abstrata para reutilizar o código, o que não pode ser feito com uma interface.

  • Outra diferença é que um objeto pode implementar quantas interfaces você precisar, mas você só pode ter uma classe abstrata por causa do "problema do diamante" (confira aqui para saber o porquê! Http://en.wikipedia.org/wiki/ Herança_ múltipla # The_diamond_problem )

Provavelmente esqueço alguns pontos, mas espero que possa esclarecer as coisas.

PS: O "é um" / "deve fazer" é trazido pela resposta de Vivek Vermani, eu não quis roubar a resposta dele, apenas para reutilizar os termos porque eu gostava deles!

IEatBagels
fonte
2
A palavra que você está procurando é comestível, acredito.
Travis Weston
1
Na verdade, eu acredito que é um "verbo", um "fazer palavra"
Grizly
7

As diferenças técnicas entre uma classe abstrata e uma interface já estão listadas nas outras respostas com precisão. Quero adicionar uma explicação para escolher entre uma classe e uma interface enquanto escrevia o código em prol da programação orientada a objetos.

Uma classe deve representar uma entidade, enquanto uma interface deve representar o comportamento.

Vamos dar um exemplo. Um monitor de computador é uma entidade e deve ser representado como uma classe.

class Monitor{
    private int monitorNo;
}

Ele foi projetado para fornecer uma interface de exibição para você, portanto a funcionalidade deve ser definida por uma interface.

interface Display{
    void display();
}

Há muitas outras coisas a considerar, como explicado nas outras respostas, mas essa é a coisa mais básica que a maioria das pessoas ignora durante a codificação.

Anurag Sharma
fonte
2
PHP does not definir tipos de retorno eo OP marcado esta pergunta comPHP
Purefan
1

Só queria adicionar um exemplo de quando você pode precisar usar os dois. Atualmente, estou escrevendo um manipulador de arquivos vinculado a um modelo de banco de dados em uma solução ERP de uso geral.

  • Eu tenho várias classes abstratas que lidam com o padrão crud e também algumas funcionalidades especiais, como conversão e streaming para diferentes categorias de arquivos.
  • A interface de acesso a arquivos define um conjunto comum de métodos necessários para obter, armazenar e excluir um arquivo.

Dessa forma, tenho vários modelos para arquivos diferentes e um conjunto comum de métodos de interface com clara distinção. A interface fornece a analogia correta para os métodos de acesso, e não o que teria sido com uma classe abstrata de base.

Mais adiante, quando farei adaptadores para diferentes serviços de armazenamento de arquivos, essa implementação permitirá que a interface seja usada em outros lugares em contextos totalmente diferentes.

Umair Ahmed
fonte