Existem três maneiras comuns, AFAIK, de implementar a reutilização quando se trata de OOP
- Herança: geralmente representar é um relacionamento (um pato é um pássaro)
- Composição: geralmente para representar um relacionamento tem (um carro tem um motor)
- Traits (por exemplo, a palavra-chave trait em PHP): ... não tenho muita certeza disso
Embora pareça para mim que os traços possam implementar relacionamentos has-a e is-a, não tenho muita certeza de que tipo de modelagem foi projetado. Para que tipo de situações as características foram projetadas?
object-oriented-design
Extrakun
fonte
fonte
Respostas:
Traços são outra maneira de fazer composição. Pense neles como uma maneira de compor todas as partes de uma classe em tempo de compilação (ou tempo de compilação JIT), montando as implementações concretas das partes necessárias.
Basicamente, você deseja usar características quando se encontra fazendo aulas com diferentes combinações de recursos. Essa situação surge com mais frequência para as pessoas que escrevem bibliotecas flexíveis para outras pessoas consumirem. Por exemplo, aqui está a declaração de uma classe de teste de unidade que escrevi recentemente usando o ScalaTest :
Estruturas de teste de unidade tem uma tonelada de diferentes opções de configuração, e cada equipe tem diferentes preferências sobre como eles querem fazer as coisas. Ao colocar as opções em traços (que são misturados no
with
Scala), o ScalaTest pode oferecer todas essas opções sem a necessidade de criar nomes de classeWordSpecLikeWithMatchersAndFutures
ou uma tonelada de sinalizadores booleanos de tempo de execuçãoWordSpecLike(enableFutures, enableMatchers, ...)
. Isso facilita seguir o princípio Aberto / Fechado . Você pode adicionar novos recursos e novas combinações de recursos simplesmente adicionando uma nova característica. Também facilita seguir o Princípio de Segregação de Interface , porque você pode facilmente colocar funções não universalmente necessárias em uma característica.Os traços também são uma boa maneira de colocar código comum em várias classes que não fazem sentido para compartilhar uma hierarquia de herança. A herança é um relacionamento muito estreitamente associado, e você não deve pagar esse custo se puder ajudá-lo. Traços são um relacionamento muito mais frouxamente acoplado. No meu exemplo acima, eu costumava
MyCustomTrait
compartilhar facilmente uma implementação de banco de dados simulada entre várias classes de teste não relacionadas.A injeção de dependência alcança muitos dos mesmos objetivos, mas em tempo de execução, com base na entrada do usuário, em vez de no tempo de compilação, com base na entrada do programador. Os traços também se destinam mais a dependências que fazem parte semanticamente da mesma classe. Você está montando as partes de uma classe em vez de fazer chamadas para outras classes com outras responsabilidades.
As estruturas de injeção de dependência alcançam muitos dos mesmos objetivos em tempo de compilação, com base nas informações do programador, mas são uma solução alternativa para linguagens de programação sem suporte adequado às características. Os traços trazem essas dependências para o domínio do verificador de tipos do compilador, com sintaxe mais limpa, com um processo de construção mais simples, que faz uma distinção mais clara entre as dependências em tempo de compilação e tempo de execução.
fonte