ti-enxame.com

Vantagens da programação orientada a objetos

Nota : esta pergunta é um trecho editado de um postagem no blog Eu escrevi alguns meses atrás. Depois de colocar um link para o blog em comentário no Programmers.SE alguém solicitou que eu publicasse uma pergunta aqui para que eles pudessem respondê-la. Esta postagem é a mais popular, pois as pessoas parecem digitar "Não entendo programação orientada a objetos" no Google muito. Sinta-se à vontade para responder aqui ou em um comentário no Wordpress.

O que é programação orientada a objetos? Ninguém me deu uma resposta satisfatória. Eu sinto que você não vai conseguir uma boa definição de alguém que sai por aí dizendo "objeto" e "orientado a objeto" com o nariz no ar. Você também não obterá uma boa definição de alguém que não fez nada além de programação orientada a objetos. Ninguém que entenda programação procedural e orientada a objetos jamais me deu uma idéia consistente do que realmente faz um programa orientado a objetos.

Alguém pode me dar suas idéias sobre as vantagens da programação orientada a objetos?

35
Joel J. Adamson

Pense no software como uma máquina ou linha de montagem que existe dentro do computador. Algumas matérias-primas e componentes são alimentados na máquina e segue um conjunto de procedimentos para processá-los em algum produto final. Os procedimentos são configurados para executar uma operação específica em alguma matéria-prima ou componente de um conjunto específico de parâmetros (por exemplo, tempo, temperatura, distância etc.) em uma ordem específica. Se os detalhes da operação a ser executada estiverem incorretos, ou os sensores da máquina não estiverem calibrados corretamente, ou se alguma matéria-prima ou componente não estiver dentro dos padrões de qualidade esperados, isso poderá alterar o resultado da operação e o produto não sairá. como esperado.

Essa máquina é muito rígida em sua operação e entradas aceitáveis. Máquinas não questionam a inteligência dos projetistas nem seu ambiente operacional atual. Ele continuará a seguir os procedimentos, desde que direcionado. Mesmo que uma alteração nas matérias-primas ou nos componentes possa ter um efeito dramático no que aconteceu em operações posteriores, a máquina ainda executaria seus procedimentos. O processo precisaria ser revisto para ver quais alterações nos procedimentos eram necessárias para compensar e produzir o resultado desejado. Uma alteração no design ou na configuração do produto também pode exigir uma alteração significativa nas operações executadas ou em seu pedido. Embora os responsáveis ​​pela produção tenham aprendido rapidamente a importância de isolar as operações o máximo possível para reduzir os efeitos indesejáveis ​​entre eles, muitas suposições são feitas sobre as condições em que os componentes estão quando passam pelo processamento; suposições que podem não ser detectadas até que o produto final esteja nas mãos do usuário em algum ambiente operacional diferente.

É assim que é a programação procedural.

O que a orientação a objetos fornece é uma maneira de remover as suposições da condição dos componentes; portanto, as operações a serem executadas nesse componente e como integrá-lo ao produto final. Em outras palavras, OOP é como pegar os detalhes do processo para lidar com um componente em particular e entregá-lo a uma máquina menor. A máquina maior responsável pelo processo informa à máquina específica do componente que operação que espera ser realizada, mas deixa os detalhes das etapas para a máquina específica do componente.

Quanto às vantagens da orientação a objetos sobre o software não orientado a objetos:

  • comportamento específico do componente - detalhando como lidar com um componente específico, a responsabilidade da máquina menor específica do componente garante que sempre que o componente for manuseado, sua máquina o fará adequadamente;
  • expressões polimórficas - como máquinas específicas de componentes executam operações personalizadas para seu componente específico, a mesma mensagem enviada para máquinas diferentes pode agir de maneira diferente;
  • abstração de tipo - geralmente faz sentido que vários tipos diferentes de componentes usem o mesmo vocabulário para as operações que suas máquinas fazem;
  • separação de interesses - deixar detalhes específicos de componentes em suas máquinas significa que a máquina de processo precisa lidar apenas com as preocupações mais gerais e maiores de seu processo e com os dados necessários para gerenciá-la; além disso, é menos provável que seja afetado por alterações em outros componentes;
  • adaptabilidade - os componentes que se concentram em sua área de especialidade podem ser adaptados para uso imprevisto simplesmente alterando os componentes que utiliza ou disponibilizando-o para outra máquina de processo;
  • reutilização de código - componentes com foco limitado e maior adaptabilidade podem alavancar seu custo de desenvolvimento ao serem usados ​​com mais frequência.
7
Huperniketes

No seu blog, parece que você está familiarizado com a programação imperativa e funcional e com os conceitos básicos envolvidos na programação orientada a objetos, mas você nunca teve realmente um "clique" sobre o que torna útil. Vou tentar explicar em termos desse conhecimento e espero que seja útil para você.

Em sua essência, OOP é uma maneira de usar o paradigma imperativo para gerenciar melhor altos graus de complexidade, criando estruturas de dados "inteligentes" que modelam o domínio do problema. Em um (não-objeto processual padrão orientado), você tem duas coisas básicas: variáveis ​​e código que sabe o que fazer com eles.O código recebe a entrada do usuário e várias outras fontes, armazena-a em variáveis, opera-a e produz dados de saída que vai para o usuário ou vários outros locais.

A programação orientada a objetos é uma maneira de simplificar seu programa, pegando esse padrão básico e repetindo-o em uma escala menor. Assim como um programa é uma grande coleção de dados com código que sabe o que fazer com ele, cada objeto é um pequeno pedaço de dados vinculado ao código que sabe o que fazer com ele.

Ao dividir o domínio do problema em partes menores e garantir que o máximo de dados possível seja vinculado diretamente ao código que sabe o que fazer com ele, você facilita muito o raciocínio sobre o processo como um todo e também sobre os sub- questões que compõem o processo.

Ao agrupar dados em classes de objetos, você pode centralizar o código relacionado a esses dados, facilitando o código relevante para localizar e depurar. E, encapsulando os dados por trás dos especificadores de acesso e acessando-os apenas por métodos (ou propriedades, se o seu idioma os suportar), você reduz bastante o potencial de corrupção de dados ou violação de invariantes.

E, usando herança e polimorfismo, você pode reutilizar classes pré-existentes, personalizando-as para atender às suas necessidades específicas, sem precisar modificar os originais ou reescrever tudo desde o início. (O que é um algo que você nunca deve fazer , se você puder evitá-lo.) Apenas tome cuidado para entender seu objeto base, ou você pode acabar com cangurus assassinos .

Para mim, esses são os princípios fundamentais da programação orientada a objetos: gerenciamento de complexidade, centralização de código e modelagem aprimorada de domínios de problemas através da criação de classes de objetos, herança e polimorfismo e maior segurança sem sacrificar o poder ou o controle através do uso de encapsulamento e propriedades. Espero que isso ajude você a entender por que muitos programadores acham útil.

EDIT: Em resposta à pergunta de Joel nos comentários,

Você pode explicar o que um "programa orientado a objetos" contém (além dessas definições sofisticadas que você descreveu) que são fundamentalmente diferentes de um programa imperativo? Como você "faz a bola rolar?"

Um pequeno aviso aqui. Meu modelo de "um programa orientado a objetos" é basicamente o modelo Delphi, que é muito semelhante ao modelo C # /. NET desde que eles foram criados por ex-membros da equipe Delphi. O que estou dizendo aqui pode não se aplicar, ou não se aplica tanto, em outros idiomas OO.

Um programa orientado a objetos é aquele em que toda a lógica é estruturada em torno de objetos. Claro que isso precisa ser iniciado em algum lugar. Seu programa Delphi típico contém código de inicialização que cria um objeto singleton chamado Application. No início do programa, ele chama Application.Initialize, em seguida, uma chamada para Application.CreateForm para todos os formulários que você deseja carregar na memória desde o início e, em seguida, Application.Run, que exibe o formulário principal na tela e inicia o loop de entrada/evento que forma o núcleo de qualquer programa de computador interativo.

O aplicativo e seus formulários pesquisam os eventos recebidos do sistema operacional e os convertem em chamadas de método no seu objeto. Uma coisa que é muito comum é o uso de manipuladores de eventos, ou "delegados" no .NET-speak. Um objeto possui um método que diz "faça X e Y, mas também verifique se esse manipulador de eventos específico está atribuído e chame-o se for". Um manipulador de eventos é um ponteiro de método - um fechamento muito simples que contém uma referência ao método e uma referência à instância do objeto - usado para estender o comportamento dos objetos. Por exemplo, se eu tiver um objeto de botão no meu formulário, personalizo seu comportamento anexando um manipulador de eventos OnClick, que faz com que outro objeto execute um método quando o botão é clicado.

Portanto, em um programa orientado a objetos, a maior parte do trabalho é realizada definindo objetos com certas responsabilidades e vinculando-os, por meio de ponteiros de método ou por um objeto que chama diretamente um método definido na interface pública de outro objeto. (E agora voltamos ao encapsulamento.) Essa é uma ideia que eu não tinha noção de voltar antes de ter aulas OOP na faculdade.

46
Mason Wheeler

Eu acho que OOP é basicamente apenas um nome dado a algo que você pode ter sido tentado a fazer ao longo do caminho, como eu.

Há muito tempo, quando eu era programador de bebês, mesmo em Fortran, havia um ponteiro para uma sub-rotina. É realmente útil poder passar um ponteiro para uma sub-rotina como argumento para outra sub-rotina.

A próxima coisa que seria realmente útil seria armazenar um ponteiro para uma sub-rotina dentro de um registro de uma estrutura de dados. Dessa forma, você pode dizer que o registro "sabe" como executar operações sozinho.

Não tenho certeza se eles construíram isso no Fortran, mas é fácil fazer isso em C e seus descendentes.

Então, por baixo, é uma idéia simples e útil que você pode ter tentado fazer sozinho, e é mais fácil de fazer em idiomas mais recentes, mesmo que algumas pessoas o transformem em um gigantesco movimento cheio de chavões assustadores.

6
Mike Dunlavey

Existem vários tipos de sistemas OO, e é difícil obter uma definição com a qual todos concordem. Em vez de tentar mostrar como o OO do Java é semelhante ao Common LISP Object System, começarei com algo mais convencional, passo a passo.

Suponha que você tenha muitos objetos como dados dispersos. Os pontos, por exemplo, podem ser elementos em uma matriz X, Y e Z. Para considerar um ponto em si, faz sentido reunir todos os dados em algo como um C struct.

Agora, para qualquer objeto de dados, reunimos os dados. No entanto, em um programa processual, o código está disperso. Suponha que estamos lidando com formas geométricas. Há uma grande função para desenhar formas, e ela precisa conhecer todas as formas. Há uma grande função para encontrar a área e outra para o perímetro. O código para um círculo está espalhado por várias funções e, para adicionar outro tipo de forma, precisamos saber quais funções alterar. Em um sistema orientado a objetos, reunimos as funções no mesmo tipo de coisa (class) que os dados. Portanto, se queremos olhar para todo o código do círculo, ele está na definição Circle e, se queremos adicionar um Quartercircle, simplesmente escrevemos sua classe e obtemos o código .

Um lado beneficia disso é que podemos manter invariantes de classe, coisas verdadeiras sobre cada membro da classe. Ao restringir o código fora da classe de mexer diretamente com os membros dos dados da classe, temos todo o código que pode alterar os dados da classe em um só lugar e podemos confirmar que ele não faz nada de maluco (como ter um triângulo com uma perna mais do que os outros dois combinados). Isso significa que podemos contar com algumas propriedades de todos os membros da classe e não precisamos verificar se um objeto é sadio toda vez que o usamos.

O principal benefício vem com a herança e o polimorfismo. Ao definir todas essas formas como subclasses de uma classe chamada Shape, podemos manipular nosso código Shapes, e é tarefa dos subobjetos da forma fazer o que for exigido pelas manipulações . Isso significa que não precisamos tocar no código antigo testado quando adicionamos novas formas ou refinamos o comportamento das antigas. Temos automaticamente um código antigo que pode tirar vantagem diretamente do novo código. Em vez de tornar o código de controle ciente de todas as diferentes formas possíveis, e ter que manter funções cientes de todas as diferentes formas possíveis, apenas lidamos com as formas e suas propriedades, mantendo as subclasses Shape. Isso simplifica o código de controle.

Temos várias vantagens aqui. Como temos invariantes de classe, podemos raciocinar sobre objetos de dados maiores da mesma maneira que raciocinar sobre tipos internos, o que significa que geralmente podemos dividir conceitos complexos em conceitos mais simples. Como o código do círculo está amplamente contido em Circle, aumentamos a localidade. Como não há conceitos de círculo espalhados por várias funções diferentes em lugares diferentes, obtemos menos acoplamento entre as rotinas e não precisamos nos preocupar em mantê-las sincronizadas. Como as classes são, na verdade, tipos, podemos tirar proveito do sistema de tipos existente para obter um uso incompatível de nossas classes.

5
David Thornley

OO tem muitas definições diferentes, sim. Tenho certeza que você pode encontrar muitos desses por conta própria. Eu pessoalmente gosto Rees Re: OO como uma maneira de fazer sentido deles. Acho que você já leu isso desde que cita Paul Graham. (Eu recomendo a qualquer pessoa interessada em OO.) Vou adotar mais ou menos a Java aqui {1,2,3,7,8,9}.

A questão da utilidade do OO, especialmente a maneira como a abordo, merece uma resposta muito maior com alguns milhares de linhas de código (em parte para não ser apenas um monte de afirmações). No entanto, aqui está um resumo desse documento hipotético.

Eu não acho que OO é terrivelmente útil em pequena escala, digamos, cerca de algumas centenas de linhas. Em particular, OO idiomas sem boas influências funcionais tendem a para tornar realmente doloroso realizar tarefas simples com qualquer tipo de coleção ou qualquer coisa que precise de muitos tipos de dados.É aqui que a maioria dos padrões de design entra em ação; eles são band-aid na baixa potência do subjacente idioma .

Em cerca de mil linhas, torna-se mais difícil acompanhar todas as operações e estruturas de dados e como elas se relacionam. Neste ponto, ajuda a ter uma maneira de organizar explicitamente estruturas e operações de dados, definir limites de módulos e definir responsabilidades e ter uma maneira conveniente de entender essas definições enquanto você tenta programá-las.

Java-ish OO é uma solução incompleta para esses problemas que venceram o concurso de popularidade. Porque é o mesmo mecanismo que Java se aplicam às pequenas problemas de escala criados por uma linguagem pouco potente, ela tende a parecer mais uma solução mágica para tudo do que apenas uma maneira de se manter organizado.As pessoas familiarizadas com a programação funcional tendem a preferir outras soluções, como as classes de tipo CLOS ou Haskell, ou a metaprogramação de modelos quando preso em C++, ou então (como eu, trabalhando diariamente em C #) use OO mas apenas não fique tão animado com isso.

3
Jesse Millikan

OOP = estruturas de dados + passagem de mensagem + herança, todas evoluções lógicas nos modelos de programação.

OOP pode ser entendido (pelos programadores) em cerca de 90 segundos (veja meu perfil para obter um link). Os conceitos são muito simples.

Como aplicá-lo é outra questão. Só porque você sabe como balançar um martelo não significa que você sabe como projetar e construir uma casa. ;-)

1
Steven A. Lowe

OOP tenta modelar conceitos do mundo real em termos de objetos e interações entre eles. Como seres humanos, tendemos a processar o mundo em termos de objetos. O mundo está cheio de objetos que têm certas propriedades e podem fazer coisas como interagir com outros objetos. OOP permite modelar o mundo em termos semelhantes. Por exemplo,

  • Pessoa é um objeto. Uma pessoa tem algumas propriedades, como idade e sexo. Uma pessoa pode fazer coisas: comer, dormir, dirigir um carro.
  • Carro também é um objeto (embora de tipo diferente). Também possui propriedades como marca, modelo e ano. Um carro pode fazer coisas: se mover.

Mas um carro não pode se mover sozinho, ele precisa de uma pessoa para dirigir - interação entre Objetos.

1
ysolik

Como você entende estruturas, e você entende ponteiros de função, e você entende estruturas com ponteiros de função, da sua perspectiva, eu definiria programação orientada a objetos como simplesmente "programação, com uso pesado de estruturas que possuem ponteiros de função". Ainda está programando no sentido tradicional - são todos os dados e códigos que atuam sobre os dados. A diferença é simplesmente como todas essas informações são definidas e como você as define.

Talvez uma simplificação exagerada seja que a programação tradicional é "código, com algumas estruturas de dados", e a programação orientada a objetos é "estruturas de dados, com algum código". Ambos ainda possuem estruturas de dados e ambos ainda possuem código. A programação orientada a objetos, portanto, nada mais é do que o ato de definir tipos de dados antecipadamente e impor contratos de como eles se comunicam por meio de conjuntos de funções.

Como você observou, há uma enorme classe de aplicativos para os quais essa não é uma ótima maneira de implementar uma solução. Você parece viver em um mundo predominantemente composto por esses aplicativos. No seu blog, você menciona a observação das implementações do problema "99 garrafas de cerveja" (sua "vitrine de programação favorita"). 99 garrafas de cerveja certamente fazem parte dessa categoria. Tentar entender a programação orientada a objetos observando implementações de 99 garrafas de cerveja é um pouco como tentar entender a arquitetura de arranha-céus olhando uma casa na árvore. Mesmo uma casa na árvore muito bem construída só pode lhe ensinar muito.

TL; DR: OO é como a programação tradicional, exceto que você concentra mais seu esforço na definição das estruturas de dados antecipadamente, e essas estruturas de dados se comunicam entre si por meio de ponteiros de função.

0
Bryan Oakley

A primeira vez que entendi é:

Antes da programação orientada a objetos, você tinha Programação estruturada . Tudo está centrado no processo. A primeira pergunta que você deve se fazer é " O que eu quero fazer com as informações? ".

Com a programação orientada a objetos, ela é centrada nos dados. A primeira pergunta que você deve se perguntar é " Informações sobre as bruxas com as quais preciso lidar? ". Isso facilita a abstração.

0
DavRob60

Eu escrevi um post há um tempo atrás que você pode achar útil: Procedimental vs. OOP Explained .

0
VirtuosiMedia