Acho que você pode achar útil uma publicação minha sobre abstrações com vazamentos. Aqui está o contexto relevante:
A abstração é um mecanismo para ajudar a entender o que é comum entre um conjunto de fragmentos de programas relacionados, remover suas diferenças e permitir que os programadores trabalhem diretamente com uma construção que representa esse conceito abstrato. Esse novo construto (virtualmente) sempre possui parametrizações : um meio de personalizar o uso do construto para atender às suas necessidades específicas.
Por exemplo, uma List
classe pode abstrair os detalhes de uma implementação de lista vinculada - onde, em vez de pensar em termos de manipulação next
e previous
ponteiros, você pode pensar no nível de adicionar ou remover valores a uma sequência. A abstração é uma ferramenta essencial para criar recursos úteis, ricos e às vezes complexos a partir de um conjunto muito menor de conceitos mais primitivos.
A abstração está relacionada ao encapsulamento e à modularidade, e esses conceitos geralmente são mal compreendidos.
No List
exemplo, o encapsulamento pode ser usado para ocultar os detalhes de implementação de uma lista vinculada; em uma linguagem orientada a objetos, por exemplo, você pode tornar os ponteiros next
e previous
privados, onde apenas a implementação da Lista tem permissão para acessar esses campos.
O encapsulamento não é suficiente para abstração, porque não implica necessariamente que você tenha uma concepção nova ou diferente das construções. Se tudo o que uma List
classe fez foi fornecer métodos acessadores de estilo ' getNext
' / ' setNext
', eles seriam encapsulados a partir dos detalhes da implementação (por exemplo, você nomeou o campo ' prev
' ou ' previous
'? Qual era o tipo estático?), Mas teria um grau muito baixo de abstração.
A modularidade está preocupada com a ocultação de informações : propriedades estáveis são especificadas em uma interface e um módulo implementa essa interface, mantendo todos os detalhes de implementação dentro do módulo. A modularidade ajuda os programadores a lidar com as mudanças, porque outros módulos dependem apenas da interface estável.
A ocultação de informações é auxiliada pelo encapsulamento (para que seu código não dependa de detalhes instáveis da implementação), mas o encapsulamento não é necessário para modularidade. Por exemplo, você pode implementar uma List
estrutura em C, expondo os ' next
' e ' prev
ponteiros' para o mundo, mas também proporcionar uma interface, que contém initList()
, addToList()
eremoveFromList()
funções. Desde que as regras da interface sejam seguidas, você pode garantir que certas propriedades sempre serão mantidas, como garantir que a estrutura de dados esteja sempre em um estado válido. [O artigo clássico de Parnas sobre modularidade, por exemplo, foi escrito com um exemplo em montagem. A interface é um contrato e uma forma de comunicação sobre o design, não precisa necessariamente ser verificada mecanicamente, embora seja nisso que confiamos hoje.]
Embora termos como abstrato, modular e encapsulado sejam usados como descrições positivas do design, é importante perceber que a presença de qualquer uma dessas qualidades não fornece automaticamente um bom design:
Se um algoritmo n ^ 3 for "bem encapsulado", ele ainda terá desempenho pior que um algoritmo n log n aprimorado.
Se uma interface se comprometer com um sistema operacional específico, nenhum dos benefícios de um design modular será alcançado quando, digamos, um videogame precisar ser portado do Windows para o iPad.
Se a abstração criada expor muitos detalhes não essenciais, ela falhará ao criar uma nova construção com suas próprias operações: será simplesmente outro nome para a mesma coisa.