Encapsulamento (programação de computador) - Encapsulation (computer programming)

Na programação orientada a objetos (OOP), o encapsulamento se refere ao agrupamento de dados com os métodos que operam nesses dados ou à restrição do acesso direto a alguns dos componentes de um objeto. O encapsulamento é usado para ocultar os valores ou estado de um objeto de dados estruturados dentro de uma classe , evitando o acesso direto a eles pelos clientes de uma forma que poderia expor detalhes de implementação ocultos ou violar a invariância de estado mantida pelos métodos.

Métodos publicamente acessíveis são geralmente fornecidos na classe para acessar ou modificar o estado de forma mais abstrata. Na prática, às vezes, métodos (chamados de "getters" e "setters" ) são fornecidos para acessar os valores indiretamente, mas, embora não necessariamente uma violação do encapsulamento abstrato, eles são frequentemente considerados um sinal de programação orientada a objetos potencialmente pobre (OOP) prática de design (um Anti-padrão ).

Este mecanismo não é exclusivo para OOP. Implementações de tipos de dados abstratos , por exemplo, módulos , oferecem uma forma semelhante de encapsulamento. A semelhança foi explicada pelos teóricos da linguagem de programação em termos de tipos existenciais .

Significado

Em linguagens de programação orientadas a objetos e outros campos relacionados, o encapsulamento se refere a uma de duas noções relacionadas, mas distintas e, às vezes, à combinação delas:

  • Um mecanismo de linguagem para restringir o acesso direto a alguns dos componentes do objeto .
  • Uma construção de linguagem que facilita o agrupamento de dados com os métodos (ou outras funções) que operam nesses dados.

Alguns pesquisadores e acadêmicos de linguagens de programação usam o primeiro significado sozinho ou em combinação com o segundo como uma característica distintiva da programação orientada a objetos , enquanto algumas linguagens de programação que fornecem fechamentos lexicais visualizam o encapsulamento como um recurso da linguagem ortogonal à orientação a objetos.

A segunda definição é motivada pelo fato de que em muitas linguagens orientadas a objetos e outros campos relacionados, os componentes não são ocultados automaticamente e isso pode ser substituído; assim, a ocultação de informações é definida como uma noção separada por aqueles que preferem a segunda definição.

Os recursos de encapsulamento são suportados usando classes na maioria das linguagens orientadas a objetos, embora outras alternativas também existam.

Encapsulamento e herança

Os autores de Design Patterns discutem longamente a tensão entre herança e encapsulamento e afirmam que, em sua experiência, os designers abusam da herança. Eles afirmam que a herança freqüentemente quebra o encapsulamento, visto que a herança expõe uma subclasse aos detalhes da implementação de seu pai. Conforme descrito pelo problema do ioiô , o uso excessivo de herança e, portanto, o encapsulamento pode se tornar muito complicado e difícil de depurar.

Esconder informações

De acordo com a definição de que o encapsulamento "pode ​​ser usado para ocultar membros de dados e funções de membro", a representação interna de um objeto é geralmente oculta da visualização fora da definição do objeto. Normalmente, apenas os próprios métodos do objeto podem inspecionar ou manipular diretamente seus campos. Ocultar as partes internas do objeto protege sua integridade, evitando que os usuários configurem os dados internos do componente em um estado inválido ou inconsistente. Um suposto benefício do encapsulamento é que ele pode reduzir a complexidade do sistema e, assim, aumentar a robustez , permitindo ao desenvolvedor limitar as interdependências entre os componentes de software.

Algumas linguagens como Smalltalk e Ruby só permitem o acesso por meio de métodos de objeto, mas a maioria das outras (por exemplo, C ++ , C # , Delphi ou Java ) oferece ao programador um grau de controle sobre o que está oculto, normalmente por meio de palavras-chave como publice private. Padrão ISO C ++ refere-se a protected, privatee publiccomo " especificadores de acesso " e que não "esconder qualquer informação". O ocultamento de informações é realizado fornecendo uma versão compilada do código-fonte que é interfaceado por meio de um arquivo de cabeçalho.

Quase sempre, há uma maneira de substituir essa proteção - geralmente por meio de API de reflexão (Ruby, Java, C #, etc.), às vezes por mecanismo como nome mutilado ( Python ) ou uso de palavras-chave especiais como friendem C ++. Os sistemas que fornecem segurança baseada em capacidade em nível de objeto (aderindo ao modelo de capacidade de objeto ) são uma exceção e garantem um encapsulamento forte.

Exemplos

Restringindo campos de dados

Linguagens como C ++ , C # , Java , PHP , Swift e Delphi oferecem maneiras de restringir o acesso aos campos de dados.

Abaixo está um exemplo em C # que mostra como o acesso a um campo de dados pode ser restrito por meio do uso de uma privatepalavra-chave:

class Program
{
    public class Account
    {
        private decimal accountBalance = 500.00m;

        public decimal CheckBalance()
        {
            return this.accountBalance;
        }
    }

    static void Main()
    {
        Account myAccount = new Account();
        decimal myBalance = myAccount.CheckBalance();

        /* This Main method can check the balance via the public
         * "CheckBalance" method provided by the "Account" class 
         * but it cannot manipulate the value of "accountBalance" */
    }
}

Abaixo está um exemplo em Java :

public class Employee {
    private BigDecimal salary = new BigDecimal(50000.00);
    
    public BigDecimal getSalary() {
        return this.salary;
    }

    public static void main() {
        Employee e = new Employee();
        BigDecimal sal = e.getSalary();
    }
}

O encapsulamento também é possível em linguagens não orientadas a objetos. Em C , por exemplo, uma estrutura pode ser declarada na API pública por meio do arquivo de cabeçalho para um conjunto de funções que operam em um item de dados contendo membros de dados que não são acessíveis aos clientes da API com a externpalavra - chave.

// Header file "api.h"

struct Entity;          // Opaque structure with hidden members

// API functions that operate on 'Entity' objects
extern struct Entity *  open_entity(int id);
extern int              process_entity(struct Entity *info);
extern void             close_entity(struct Entity *info);
// extern keywords here are redundant, but don't hurt.
// extern defines functions that can be called outside the current file, the default behavior even without the keyword

Os clientes chamam as funções da API para alocar, operar e desalocar objetos de um tipo de dados opaco . O conteúdo desse tipo é conhecido e acessível apenas para a implementação das funções da API; os clientes não podem acessar diretamente seu conteúdo. O código-fonte para essas funções define o conteúdo real da estrutura:

// Implementation file "api.c"

#include "api.h"

struct Entity {
    int     ent_id;         // ID number
    char    ent_name[20];   // Name
    ... and other members ...
};

// API function implementations
struct Entity * open_entity(int id)
{ ... }

int process_entity(struct Entity *info)
{ ... }

void close_entity(struct Entity *info)
{ ... }

Nome mutilado

Abaixo está um exemplo de Python , que não oferece suporte a restrições de acesso variável. No entanto, a convenção é que uma variável cujo nome é precedido por um sublinhado deve ser considerada privada.

class Car: 
    def __init__(self) -> None:
        self._maxspeed = 200
 
    def drive(self) -> None:
        print(f"Maximum speed is {self._maxspeed}.")
 
redcar = Car()
redcar.drive()  # This will print 'Maximum speed is 200.'

redcar._maxspeed = 10
redcar.drive()  # This will print 'Maximum speed is 10.'

Veja também

Referências