Traço (programação de computador) - Trait (computer programming)

Na programação de computadores , um traço é um conceito usado na programação orientada a objetos , que representa um conjunto de métodos que podem ser usados ​​para estender a funcionalidade de uma classe .

Características

As características fornecem um conjunto de métodos que implementam o comportamento para uma classe e exigem que a classe implemente um conjunto de métodos que parametrizam o comportamento fornecido.

Para a comunicação entre objetos, as características estão em algum lugar entre um protocolo orientado a objetos (interface) e um mixin . Uma interface pode definir um ou mais comportamentos por meio de assinaturas de método , enquanto uma característica define comportamentos por meio de definições de método completas: ou seja, inclui o corpo dos métodos . Em contraste, os mixins incluem definições de método completas e também podem transportar o estado por meio da variável membro, enquanto as características geralmente não.

Portanto, um objeto definido como uma característica é criado como a composição de métodos, que podem ser usados ​​por outras classes sem exigir herança múltipla . No caso de uma colisão de nomenclatura , quando mais de um traço a ser usado por uma classe tem um método com o mesmo nome, o programador deve esclarecer explicitamente qual desses métodos será usado na classe; resolvendo assim manualmente o problema do diamante de herança múltipla. Isso é diferente de outros métodos de composição na programação orientada a objetos, onde nomes conflitantes são resolvidos automaticamente por regras de escopo .

Considerando que os mixins podem ser compostos apenas usando a operação de herança , os traits oferecem uma seleção muito mais ampla de operações, incluindo:

  • soma simétrica : uma operação que mescla duas características disjuntas para criar uma nova característica
  • override (ou soma assimétrica ): uma operação que forma uma nova característica adicionando métodos a uma característica existente, possivelmente substituindo alguns de seus métodos
  • alias : uma operação que cria uma nova característica adicionando um novo nome para um método existente
  • exclusão : uma operação que forma um novo traço ao remover um método de um traço existente. (Combinar isso com a operação de alias resulta em uma operação de renomeação superficial ).

As características são compostas das seguintes maneiras:

  • A composição do traço é comutativa; a ordem de adição de características não importa. Por exemplo, dada característica S = A + B , em seguida, traço T = B + A é o mesmo que S .
  • Métodos conflitantes são excluídos da composição.
  • Os traços aninhados são equivalentes aos traços achatados; a hierarquia de composição não afeta o comportamento das características. Por exemplo, dada característica S = A + X , onde X = B + C , em seguida característica T = A + B + C é o mesmo que S .

Idiomas suportados

As características vêm originalmente da linguagem de programação Self e são suportadas pelas seguintes linguagens de programação:

  • AmbientTalk : combina as propriedades de auto traços (com base em objectos de herança múltipla) e Smalltalk 's rangido traços (exigindo composição explícito de traços pelo programador). Ele se baseia na pesquisa sobre características stateful e freezable para habilitar o estado dentro das características, o que não era permitido nas primeiras definições.
  • C # : desde a versão 8.0, C # tem suporte para métodos de interface padrão , que têm algumas propriedades de características.
  • C ++ : Usado na Biblioteca de Modelos Padrão e na biblioteca padrão C ++ para oferecer suporte a classes de contêiner genéricas e na biblioteca Boost TypeTraits.
  • Curl : Classes abstratas como mixins permitem implementações de métodos e, portanto, constituem características com outro nome.
  • D : Desde a versão 2.003, a extensão de linguagem __traits e os modelos auxiliares do módulo std.traits fornecem características de tempo de compilação. Junto com outros recursos de linguagem (notadamente modelos e mixins), eles permitem a geração automática e flexível de métodos baseados em interfaces e tipos. D também permite o aliasing explícito de métodos e variáveis ​​de membro, incluindo o encaminhamento para várias classes de membro.
  • Fortaleza
  • Groovy : desde a versão 2.3
  • Haskell : Em Haskell, os traços são conhecidos como classes de tipo .
  • Haxe : desde a versão 2.4.0. Chamada de extensão estática no manual, ela usa a usingpalavra - chave
  • Java : desde a versão 8, o Java tem suporte para métodos padrão , que possuem algumas propriedades de características.
  • JavaScript : as características podem ser implementadas por meio de funções e delegações ou por meio de bibliotecas que fornecem características.
  • Julia : Vários pacotes implementam características, por exemplo,
  • Kotlin : Os traços são chamados de interfaces desde M12.
  • Laço
  • OCaml : Traits podem ser implementados usando uma variedade de recursos de linguagem: módulo e inclusão de tipo de módulo, functores e tipos de functor, classe e herança de tipo de classe, etc.
  • Perl : funções chamadas , são implementadas em bibliotecas Perl como Moose , Role :: Tiny e Role :: Basic. Os papéis fazem parte da linguagem irmã Raku .
  • PHP : Desde a versão 5.4, o PHP permite aos usuários especificar modelos que fornecem a habilidade de "herdar" de mais de uma classe (característica), como uma herança pseudo múltipla .
  • Python : por meio de uma biblioteca de terceiros ou de classes mixin de ordem superior
  • Racket : oferece suporte a traits como uma biblioteca e usa macros, estruturas e classes de primeira classe para implementá-los.
  • Ruby : Os mixins de módulo podem ser usados ​​para implementar características.
  • Ferrugem
  • O traço Scala é embutido com suporte na palavra-chave trait.
  • Smalltalk : Traits são implementados em dois dialetos de Smalltalk, Squeak e Pharo .
  • Swift : os traços podem ser implementados com extensões de protocolo .

Exemplos

C #

No C # 8.0, é possível definir uma implementação como membro de uma interface.

using System;

namespace CSharp8NewFeatures
{
    interface ILogger
    {
        // Traditional interface methods
        void Log(string message);
        void LogError(Exception exception);

        // Default interface method
        void LogWarning(string message)
        {
            Console.WriteLine(message);
        }        
    }

    class Logger : ILogger
    {
        public void Log(string message)
        {
            Console.WriteLine(message);
        }

        public void LogError(Exception exception)
        {
            Console.WriteLine(exception.ToString());
        }
    }

    class Program
    {
        static void Main(string[] args)
        {
            ILogger logger = new Logger();

            logger.LogWarning("Some warning message");
        }
    }
}

PHP

Este exemplo usa uma característica para aprimorar outras classes:

// The template
trait TSingleton
{
    private static $_instance = null;

    private function __construct() {} // Must have private default constructor and be aware not to open it in the class

    public static function getInstance()
    {
        if (null === self::$_instance) {
            self::$_instance = new self();
        }

        return self::$_instance;
    }
}

class FrontController
{
    use TSingleton;
}

// Can also be used in already extended classes
class WebSite extends SomeClass
{
    use TSingleton;
}

Isso permite simular aspectos de herança múltipla:

trait TBounding
{
    public $x, $y, $width, $height;
}

trait TMoveable
{
    public function moveTo($x, $y)
    {
        // …
    }
}

trait TResizeable
{
    public function resize($newWidth, $newHeight)
    {
        // …
    }
}

class Rectangle
{
    use TBounding, TMoveable, TResizeable;

    public function fillColor($color)
    {
        // …
    }
}

Ferrugem

Uma característica em Rust declara um conjunto de métodos que um tipo deve implementar. Os compiladores Rust exigem que os traços sejam explicados, o que garante a segurança dos genéricos no Rust.

// type T must have the "Ord" trait
// so that ">" and "<" operations can be done
fn get_max<T: Ord>(a: &[T]) -> Option<&T> {
    let mut result = a.get(0)?;
    for n in a {
        if *n > *result {
            result = &n;
        }
    }
    Some(result)
}

Para simplificar a implementação entediante e repetida de características como Debuge Ord, a derivemacro pode ser usada para solicitar que os compiladores gerem certas implementações automaticamente. Traços deriváveis incluem: Clone, Copy, Debug, Default, PartialEq, Eq, PartialOrd, Orde Hash.

Veja também

Referências

links externos