Nota : esta pergunta é um trecho editado de uma postagem de blog que escrevi há alguns meses atrás. Depois de colocar um link para o blog em um comentário no Programmers.SE alguém solicitou que eu publicasse uma pergunta aqui para que eles pudessem responder. Esta postagem é o meu mais popular, como as pessoas parecem tipo "Eu não entendo de programação orientada a objeto" no Google um monte . 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?
fonte
Respostas:
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, são feitas muitas suposições sobre a condição dos componentes quando eles são processados; 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 algum componente específico e entregá-lo a uma máquina menor. A máquina maior responsável pelo processo informa à máquina específica do componente qual operação ela espera que seja realizada, mas deixa os detalhes das etapas para a máquina específica do componente manipular.
Quanto às vantagens da orientação a objetos sobre o software não orientado a objetos:
fonte
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ê.
Na sua essência, a OOP é uma maneira de usar o paradigma imperativo para gerenciar melhor os altos graus de complexidade, criando estruturas de dados "inteligentes" que modelam o domínio do problema. Em um programa (procedimento padrão não orientado a objetos), você tem duas coisas básicas: variáveis e código que sabe o que fazer com elas. O código recebe a entrada do usuário e de várias outras fontes, armazena-a em variáveis, opera nele e produz dados de saída que vão para o usuário ou para 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 preexistentes, personalizando-as para atender às suas necessidades específicas, sem ter que modificar os originais ou reescrever tudo desde o início. (O que é algo que você nunca deve fazer , se puder evitá-lo.) Apenas tome cuidado para entender seu objeto base ou poderá 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 segurança aumentada sem sacrificar o poder ou 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,
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 chamaApplication.Initialize
, depois uma chamadaApplication.CreateForm
para todos os formulários que você deseja carregar na memória desde o início e, em seguida,Application.Run,
exibe o formulário principal na tela e inicia o loop de entrada / evento que forma o núcleo de qualquer programas de computador interativos.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 estamos de volta ao encapsulamento.) Essa é uma ideia que eu não tinha noção de voltar antes de ter aulas de OOP na faculdade.
fonte
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 era.
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.
fonte
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 para puxar todos os dados juntos 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á naCircle
definição e, se queremos adicionar umQuartercircle
, 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 fazer com que nosso código manipuleShape
s, e é o trabalho 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 asShape
subclasses. 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
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 capturar o uso incompatível de nossas classes.fonte
OO tem muitas definições diferentes, sim. Tenho certeza que você pode encontrar muitos desses por conta própria. Eu, pessoalmente, gosto de Rees Re: OO como uma maneira de compreendê-los. 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 definição de 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.
Não acho que o OO seja muito útil em pequena escala, digamos, em algumas centenas de linhas. Em particular, linguagens OO sem boas influências funcionais tendem a 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 cena; eles são curativos na baixa potência do idioma subjacente .
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.
O Java-ish OO é uma solução intermediária para esses problemas que venceram o concurso de popularidade. Como é o mesmo mecanismo que o pessoal de Java aplica aos problemas de pequena escala criados por uma linguagem pouco potente, ele 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 presas em C ++, ou então (como eu, trabalhando diariamente em C #) usam OO, mas não ficam tão empolgadas com isso .
fonte
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 possuem certas propriedades e podem fazer coisas como interagir com outros objetos. OOP permite modelar o mundo em termos semelhantes. Por exemplo,
Mas um carro não pode se mover sozinho, ele precisa de uma pessoa para dirigir - interação entre Objetos.
fonte
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 balançar um martelo não significa que você sabe como projetar e construir uma casa. ;-)
fonte
Eu escrevi um post no blog há um tempo atrás que você pode achar útil: Procedural vs. OOP Explained .
fonte
A maneira como eu entendi pela primeira vez é:
Antes da programação orientada a objetos, você tinha a 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 fazer é " Informações sobre as bruxas com as quais eu preciso lidar? ". Isso facilita a abstração.
fonte
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 as 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 é 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.
A programação TL; DR: OO é como a programação tradicional, exceto que você concentra mais seu esforço em definir as estruturas de dados antecipadamente e essas estruturas de dados se comunicam entre si por meio de ponteiros de função.
fonte
Eu acho que a página da Wikipedia é um bom lugar para obter os fundamentos:
http://en.wikipedia.org/wiki/Object-oriented_programming
Basicamente, a idéia é que a programação procedural, que é o que a OOP estava tentando melhorar, focada nos processos que estão sendo modelados. OOP muda para um modelo em que o foco está nas "coisas" que você está modelando e os processos e dados dessas coisas estão contidos nessas coisas.
Então, como exemplo, digamos que você estava projetando um aplicativo para rastrear uma lista de tarefas. Na programação procedural, suas entidades de nível superior no modelo seriam os processos que ocorrem, como criar uma tarefa, remover uma tarefa, alterar as informações da tarefa etc. Em um modelo OOP, você focaria na criação de uma tarefa e pense sobre quais dados e processos pelos quais a Tarefa deve ser responsável. E, em seguida, concentre-se em com quais outros objetos a Tarefa deve interagir, como possivelmente uma Nota ou algo assim, se você deseja fazer anotações sobre Tarefas.
Espero que ajude. Continue lendo e olhando o código, e de repente ele "clicará". Essa foi a minha experiência.
fonte