Eu estudei o livro "C ++ Desmistificado" . Agora comecei a ler "Programação Orientada a Objetos no Turbo C ++ primeira edição (1ª edição)", de Robert Lafore. Eu não tenho nenhum conhecimento de programação que esteja além desses livros. Este livro pode estar desatualizado porque tem 20 anos. Eu tenho a edição mais recente, estou usando a antiga porque gosto, principalmente apenas estudando os conceitos básicos de OOP usados em C ++ na primeira edição do livro de Lafore.
O livro de Lafore enfatiza que "OOP" é útil apenas para programas maiores e complexos . Diz-se em todo livro de OOP (também no livro de Lafore) que o paradigma processual é propenso a erros, por exemplo, os dados globais tão facilmente vulneráveis pelas funções. Diz-se que o programador pode cometer erros honestos em linguagens procedurais, por exemplo, criando uma função que corrompe acidentalmente os dados.
Honestamente falando, estou postando minha pergunta porque não estou entendendo a explicação dada neste livro: Programação Orientada a Objetos em C ++ (4ª Edição) Não estou entendendo essas declarações escritas no livro de Lafore:
A programação orientada a objetos foi desenvolvida porque foram descobertas limitações em abordagens anteriores de programação ... À medida que os programas se tornam cada vez maiores e mais complexos, até a abordagem de programação estruturada começa a mostrar sinais de tensão ... .... Analisando as razões para essas falhas revelam que há fragilidades no próprio paradigma processual. Não importa o quão bem a abordagem de programação estruturada seja implementada, os grandes programas se tornam excessivamente complexos ... ... Existem dois problemas relacionados. Primeiro, as funções têm acesso irrestrito aos dados globais. Segundo, funções e dados não relacionados, a base do paradigma processual, fornecem um modelo pobre do mundo real ...
Estudei o livro "C ++ dismistificado" de Jeff Kent, gosto muito deste livro, neste livro é explicada principalmente a programação procedural. Não entendo por que a programação procedural (estruturada) é fraca!
O livro de Lafore explica muito bem o conceito com alguns bons exemplos. Também apreendi uma intuição ao ler o livro de Lafore de que OOP é melhor que a programação procedural, mas estou curioso para saber como exatamente na prática a programação procedural é mais fraca que a OOP.
Eu quero me ver quais são os problemas práticos que alguém enfrentaria na programação processual, como o OOP tornará a programação mais fácil. Acho que receberei minha resposta apenas lendo o livro de Lafore de maneira contemplativa, mas quero ver com meus próprios olhos os problemas no código processual. Quero ver como o código de estilo OOP de um programa remove os erros anteriores que aconteceriam se o o mesmo programa deveria ser escrito usando paradigma processual.
Existem muitos recursos do OOP e eu entendo que não é possível alguém me explicar como todos esses recursos removem os erros anteriores que seriam gerados ao escrever o código no estilo processual.
Então aqui está a minha pergunta:
Quais limitações da programação processual o OOP aborda e como ele remove efetivamente essas limitações na prática?
Em particular, existem exemplos de programas difíceis de projetar usando o paradigma processual, mas que são facilmente projetados usando OOP?
PS: Cross publicado em: /programming//q/22510004/3429430
Respostas:
Em uma linguagem processual, você não pode necessariamente expressar restrições necessárias para provar que o chamador está usando um módulo de uma maneira suportada. Na ausência de uma restrição verificável do compilador, você deve escrever a documentação e esperar que ela seja seguida e usar testes de unidade para demonstrar os usos pretendidos.
Tipos de declaração é a restrição declarativa mais óbvia (por exemplo: "prove que x é um float"). Forçar mutações de dados a passar por uma função conhecida por ser projetada para esses dados é outra. A imposição de protocolo (método de solicitação de chamada) é outra restrição parcialmente suportada, ou seja: "construtor -> outros métodos * -> destruidor".
Também existem benefícios reais (e algumas desvantagens) quando o compilador conhece o padrão. A digitação estática com tipos polimórficos é um pouco problemática quando você emula o encapsulamento de dados de uma linguagem procedural. Por exemplo:
o tipo x1 é um subtipo de x, t1 é um subtipo de t
Esta é uma maneira de encapsular dados em uma linguagem processual para ter um tipo t com os métodos feg, e uma subclasse t1 que faça o mesmo:
t_f (t, x, y, z, ...), t_g (t, x, y, ...) t1_f (t1, x, y, z, ...)
Para usar esse código, é necessário verificar o tipo e ativar o tipo de t antes de decidir o tipo de f que você chamará. Você poderia contornar isso assim:
digite t {d: dados f: função g: função}
Para que você invoque tf (x, y, z), em que uma verificação e uma opção para encontrar o método agora é substituída por apenas cada instância armazenar explicitamente os ponteiros do método. Agora, se você tiver um grande número de funções por tipo, essa é uma representação inútil. Você poderia usar outra estratégia, como apontar para uma variável m que contém todas as funções-membro. Se esse recurso fizer parte do idioma, você poderá deixar o compilador descobrir como lidar com a representação eficiente desse padrão.
Mas o encapsulamento de dados é o reconhecimento de que o estado mutável é ruim. A solução orientada a objetos é ocultá-la atrás dos métodos. Idealmente, todos os métodos em um objeto teriam uma ordem de chamada bem definida (ou seja: construtor -> aberto -> [ler | escrever] -> fechar -> destruir); que às vezes é chamado de 'protocolo' (pesquisa: "Microsoft Singularity"). Mas, além da construção e destruição, esses requisitos geralmente não fazem parte do sistema de tipos - ou são bem documentados. Nesse sentido, objetos são instâncias simultâneas de máquinas de estado que são transferidas por chamadas de método; de modo que você possa ter várias instâncias e usá-las de maneira arbitrariamente intercalada.
Mas, ao reconhecer que o estado compartilhado mutável é ruim, pode-se observar que a orientação a objetos pode criar um problema de simultaneidade porque a estrutura de dados do objeto é um estado mutável ao qual muitos objetos fazem referência. A maioria das linguagens orientadas a objetos é executada no encadeamento do chamador, o que significa que existem condições de corrida nas invocações de métodos; muito menos em seqüências não atômicas de chamadas de função. Como alternativa, todo objeto pode receber mensagens assíncronas em uma fila e atendê-las todas no encadeamento do objeto (com seus métodos particulares) e responder ao chamador enviando mensagens.
Compare as chamadas de método Java em um contexto multithread com os processos Erlang que enviam mensagens (que referenciam apenas valores imutáveis) entre si.
A orientação irrestrita a objetos em combinação com o paralelismo é um problema devido ao bloqueio. Existem técnicas que vão da Memória Transacional de Software (ou seja: transações ACID em objetos de memória semelhantes aos bancos de dados) ao uso de uma abordagem de "compartilhamento de memória através da comunicação (dados imutáveis)" (híbrido de programação funcional).
Na minha opinião, a literatura de Orientação a Objetos concentra-se muito na herança e não o suficiente no protocolo (ordenação de chamada de método verificável, pré-condições, pós-condições, etc.). A entrada que um objeto consome geralmente deve ter uma gramática bem definida, expressável como um tipo.
fonte
A programação processual / funcional não é de modo algum mais fraca que a OOP , mesmo sem entrar em argumentos de Turing (minha linguagem tem poder de Turing e pode fazer qualquer outra coisa que faça), o que não significa muito. Na verdade, as técnicas orientadas a objetos foram primeiramente experimentadas em linguagens que não as incorporavam. Nesse sentido, a programação OO é apenas um estilo específico de programação procedural . Mas ajuda a impor disciplinas específicas, como modularidade, abstração e ocultação de informações, essenciais para a compreensão e manutenção do programa.
Alguns paradigmas de programação evoluem da visão teórica da computação. Uma linguagem como Lisp evoluiu do lambda-calculus e da idéia de meta-circularidade das línguas (semelhante à reflexividade na linguagem natural). As cláusulas de Horn criaram o Prolog e a programação de restrições. A família Algol também deve ao cálculo lambda, mas sem reflexividade embutida.
O Lisp é um exemplo interessante, pois foi testado por muita inovação em linguagem de programação, que é rastreável à sua dupla herança genética.
No entanto, os idiomas evoluem, geralmente sob novos nomes. Um fator importante da evolução é a prática de programação. Os usuários identificam práticas de programação que melhoram as propriedades dos programas, como legibilidade, capacidade de manutenção, probabilidade de correção. Em seguida, eles tentam adicionar aos idiomas recursos ou restrições que darão suporte e às vezes reforçam essas práticas, a fim de melhorar a qualidade dos programas.
O que isso significa é que essas práticas já são possíveis na linguagem de programação mais antiga, mas é preciso compreensão e disciplina para usá-las. Incorporá-los em novas linguagens como conceitos primários com sintaxe específica facilita o uso e a compreensão dessas práticas, principalmente para usuários menos sofisticados (ou seja, a grande maioria). Isso também facilita a vida dos usuários sofisticados.
De alguma forma, é para o design da linguagem o que é um subprograma / função / procedimento para um programa. Depois que o conceito útil é identificado, ele recebe um nome (possivelmente) e uma sintaxe, para que possa ser usado facilmente em todos os programas desenvolvidos com esse idioma. E, quando for bem-sucedido, também será incorporado em idiomas futuros.
Exemplo: recriando a orientação do objeto
Agora tento ilustrar isso em um exemplo (que certamente poderia ser mais polido, com o tempo). O objetivo do exemplo não é mostrar que um programa orientado a objetos pode ser escrito no estilo de programação procedural, possivelmente à custa da lisibilidade e manutenção. Tentarei mostrar que algumas linguagens sem instalações OO podem realmente usar funções de ordem superior e estrutura de dados para criar meios de imitar efetivamente a Orientação a Objetos , a fim de se beneficiar de suas qualidades em relação à organização do programa, incluindo modularidade, abstração e ocultação de informações. .
Como eu disse, o Lisp foi o teste de muita evolução da linguagem, incluindo o paradigma OO (embora o que pudesse ser considerado a primeira linguagem OO fosse o Simula 67, na família Algol). O Lisp é muito simples, e o código para seu intérprete básico é menor que uma página. Mas você pode fazer programação OO no Lisp. Tudo que você precisa é de funções de ordem superior.
Não usarei a sintaxe esotérica do Lisp, mas sim o pseudo-código, para simplificar a apresentação. E considerarei um problema essencial simples: ocultação de informações e modularidade . Definir uma classe de objetos e impedir que o usuário acesse (a maioria) a implementação.
Suponha que eu queira criar uma classe chamada vetor, representando vetores bidimensionais, com métodos que incluem: adição de vetor, tamanho de vetor e paralelismo.
Então eu posso atribuir o vetor criado aos nomes das funções reais a serem usadas.
[vector, xcoord, ycoord, vplus, vsize, vparallel] = vectorclass ()
Por que ser tão complicado? Porque eu posso definir na função construções intermediárias vectorrec que não quero que sejam visíveis para o resto do programa, de modo a preservar a modularidade.
Podemos fazer outra coleção em coordenadas polares
Mas eu posso querer usar indiferentemente as duas implementações. Uma maneira de fazer isso é adicionar um componente de tipo a todos os valores e definir todas as funções acima no mesmo ambiente: Então eu posso definir cada uma das funções retornadas para que primeiro teste o tipo de coordenadas e aplique a função específica por isso.
O que eu ganhei: as funções específicas permanecem invisíveis (por causa do escopo dos identificadores locais) e o restante do programa pode usar apenas os mais abstratos retornados pela chamada para a classe de vetor.
Uma objeção é que eu poderia definir diretamente cada uma das funções abstratas no programa e deixar dentro da definição das funções dependentes do tipo coordenada. Então estaria escondido também. Isso é verdade, mas o código para cada tipo de coordenada seria cortado em pequenos pedaços espalhados pelo programa, o que é menos redutível e sustentável.
Na verdade, eu nem preciso dar um nome a eles, e eu poderia manter os valores funcionais como anônimos em uma estrutura de dados indexada pelo tipo e uma string que representa o nome da função. Essa estrutura sendo local para o vetor de função seria invisível para o restante do programa.
Para simplificar o uso, em vez de retornar uma lista de funções, posso retornar uma única função chamada apply, tendo como argumento um valor explícito do tipo e uma string, e aplicar a função com o tipo e o nome adequados. Parece muito com chamar um método para uma classe OO.
Vou parar por aqui, nesta reconstrução de uma instalação orientada a objetos.
O que tentei fazer é mostrar que não é muito difícil criar orientação para objetos utilizáveis em uma linguagem suficientemente poderosa, incluindo herança e outros recursos. A metacircularidade do intérprete pode ajudar, mas principalmente em nível sintático, que ainda está longe de ser insignificante.
Os primeiros usuários de orientação a objetos experimentaram os conceitos dessa maneira. E isso geralmente acontece com muitas melhorias nas linguagens de programação. Obviamente, a análise teórica também tem um papel e ajudou a entender ou refinar esses conceitos.
Mas a ideia de que idiomas que não possuem recursos de OO estão fadados ao fracasso em alguns projetos é simplesmente injustificada. Se necessário, eles podem imitar a implementação desses recursos com bastante eficiência. Muitas linguagens têm o poder sintático e semântico de orientar objetos de maneira bastante eficaz, mesmo quando não está embutido. E isso é mais do que um argumento de Turing.
OOP não trata das limitações de outras linguagens, mas suporta ou aplica metodologias de programação que ajudam a escrever programas melhores, ajudando usuários menos experientes a seguir boas práticas que programadores mais avançados estão usando e desenvolvendo sem esse suporte.
Acredito que um bom livro para entender tudo isso possa ser Abelson & Sussman: estrutura e interpretação de programas de computador .
fonte
Um pouco de história está em ordem, eu acho.
A era entre meados da década de 1960 e meados da década de 1970 é hoje conhecida como "crise de software". Não posso dizer melhor do que Dijkstra em sua palestra sobre o prêmio Turing de 1972:
Essa foi a época dos primeiros computadores de 32 bits, dos primeiros multiprocessadores verdadeiros e dos primeiros computadores incorporados, e ficou claro para os pesquisadores que esses seriam importantes para a programação no futuro. Era uma época na história em que a demanda do cliente ultrapassava a capacidade do programador pela primeira vez.
Sem surpresa, foi um período notavelmente fértil na pesquisa de programação. Antes de meados da década de 1960, tínhamos LISP e AP / L, mas as "principais" linguagens eram fundamentalmente processuais: FORTRAN, ALGOL, COBOL, PL / I e assim por diante. De meados da década de 1960 a meados da década de 1970, obtivemos Logo, Pascal, C, Forth, Smalltalk, Prolog, ML e Modula, e isso não inclui DSLs como SQL e seus predecessores.
Foi também uma época na história em que muitas das principais técnicas para implementar linguagens de programação estavam sendo desenvolvidas. Nesse período, obtivemos análise de LR, análise de fluxo de dados, eliminação de subexpressão comum e o primeiro reconhecimento de que certos problemas do compilador (por exemplo, alocação de registro) eram difíceis para o NP e tentamos resolvê-los como tal.
Este é o contexto em que o POO surgiu. Portanto, no início da década de 1970, responda à sua pergunta sobre quais problemas o OOP resolve na prática, a primeira resposta é que parecia resolver muitos dos problemas (contemporâneos e antecipados) que os programadores enfrentavam naquele período da história. No entanto, este não é o momento em que o OO se tornou popular. Chegaremos a isso em breve.
Quando Alan Kay cunhou o termo "orientação a objetos", a imagem que ele tinha em mente era que os sistemas de software seriam estruturados como sistema biológico. Você teria algo como células individuais ("objetos") que interagem entre si enviando algo análogo a sinais químicos ("mensagens"). Você não podia (ou pelo menos não queria) espiar dentro de uma célula; você só interagia com ele pelos caminhos de sinalização. Além disso, você pode ter mais de um de cada tipo de célula, se necessário.
Você pode ver que existem alguns temas importantes aqui: o conceito de um protocolo de sinalização bem definido (na terminologia moderna, uma interface), o conceito de ocultar a implementação de fora (na terminologia moderna, a privacidade) e o conceito de tendo várias "coisas" do mesmo tipo penduradas ao mesmo tempo (na terminologia moderna, instanciação).
Uma coisa que você pode notar está faltando, e é a herança, e há uma razão para isso.
A programação orientada a objetos é uma noção abstrata, e a noção abstrata pode ser implementada de diferentes maneiras em diferentes linguagens de programação. O conceito abstrato de "método", por exemplo, poderia ser implementado em C usando ponteiros de função, e em C ++ usando funções-membro e em Smalltalk usando métodos (o que não deveria ser surpreendente, uma vez que o Smalltalk implementa o conceito abstrato praticamente diretamente). É isso que as pessoas querem dizer quando apontam (com toda a razão) que você pode "fazer" POO (quase) em qualquer idioma.
A herança, por outro lado, é um recurso concreto da linguagem de programação. A herança pode ser útil para implementar sistemas OOP. Ou pelo menos, esse foi o caso até o início dos anos 90.
O período de meados da década de 80 a meados da década de 90 também foi um período histórico em que as coisas estavam mudando. Durante esse período, tivemos o surgimento de um computador barato e onipresente de 32 bits, para que empresas e muitas residências pudessem se dar ao luxo de colocar um computador quase tão poderoso quanto os mainframes mais modernos do dia em todas as mesas. Foi também o auge de Essa também foi a era da ascensão da GUI moderna e do sistema operacional em rede.
Foi nesse contexto que surgiu a Análise e o Design Orientados a Objetos.
A influência do OOAD, o trabalho dos "três Amigos" (Booch, Rumbar e Jacobson) e outros (por exemplo, o método Shlaer-Mellor, design orientado a responsabilidades, etc.) não pode ser subestimado. É a razão pela qual a maioria das novas linguagens que foram desenvolvidas desde o início dos anos 90 (pelo menos, a maioria das que você já ouviu falar) tem objetos no estilo Simula.
Portanto, a resposta da década de 90 à sua pergunta é que ela suporta a melhor solução (na época) para análise orientada a domínio e metodologia de design.
Desde então, porque tínhamos um martelo, aplicamos OOP a praticamente todos os problemas que surgiram desde então. O OOAD e o modelo de objeto usado encorajaram e permitiram o desenvolvimento ágil e orientado a testes, cluster e outros sistemas distribuídos, etc.
As GUIs modernas e quaisquer sistemas operacionais que foram projetados nos últimos 20 anos tendem a fornecer seus serviços como objetos; portanto, qualquer nova linguagem de programação prática precisa, no mínimo, de uma maneira de se conectar aos sistemas que usamos hoje.
Portanto, a resposta moderna é: resolve o problema da interface com o mundo moderno. O mundo moderno é construído no OOP pela mesma razão que o mundo de 1880 foi construído no vapor: nós o compreendemos, podemos controlá-lo e ele faz o trabalho bem o suficiente.
Isso não quer dizer que a pesquisa pare aqui, é claro, mas indica fortemente que qualquer nova tecnologia precisará de OO como um caso limitante. Você não precisa ser OO, mas não pode ser fundamentalmente incompatível com ele.
fonte
Nenhuma, realmente. OOP não resolve realmente um problema, estritamente falando; não há nada que você possa fazer com um sistema orientado a objetos que você não poderia fazer com um sistema não orientado a objetos; de fato, não há nada que você possa fazer com algo que não possa ser feito com uma máquina de Turing. Eventualmente, tudo se transforma em código de máquina, e o ASM certamente não é orientado a objetos.
O que o paradigma OOP faz por você é que facilita a organização de variáveis e funções e permite movê-las juntas mais facilmente.
Digamos que eu queira escrever um jogo de cartas em Python. Como eu representaria os cartões?
Se eu não soubesse sobre OOP, poderia fazê-lo desta maneira:
Eu provavelmente escreveria algum código para gerar esses cartões em vez de apenas escrevê-los à mão, mas você entendeu. "1S" representa o 1 de espadas, "JD" representa o valete de ouros e assim por diante. Eu também precisaria de um código para o Coringa, mas vamos fingir que não há Coringa por enquanto.
Agora, quando quero embaralhar o baralho, preciso apenas "embaralhar" a lista. Então, para tirar uma carta do topo do baralho, tiro a entrada da lista, dando-me a corda. Simples.
Agora, se eu quiser descobrir com qual cartão estou trabalhando com a finalidade de exibi-lo para o jogador, precisaria de uma função como esta:
Um pouco grande, longo e ineficiente, mas funciona (e é muito antitônico, mas isso não vem ao caso aqui).
Agora, e se eu quiser que os cartões possam se mover pela tela? Eu tenho que guardar a posição deles de alguma forma. Eu poderia adicioná-lo ao final do código do cartão, mas isso pode ser um pouco complicado. Em vez disso, vamos fazer outra lista de onde cada cartão está:
Depois, escrevo meu código para que o índice da posição de cada cartão na lista seja o mesmo do índice do cartão no baralho.
Ou, pelo menos, deveria ser. A menos que eu cometa um erro. O que eu poderia muito bem, porque meu código terá que ser bastante complexo para lidar com essa configuração. Quando quero embaralhar as cartas, preciso embaralhar as posições na mesma ordem. O que acontece se eu tirar uma carta completamente do baralho? Vou ter que tomar sua posição também e colocá-la em outro lugar.
E se eu quiser armazenar ainda mais informações sobre os cartões? E se eu quiser armazenar se cada cartão é invertido? E se eu quiser algum tipo de mecanismo de física e precisar conhecer a velocidade das cartas também? Vou precisar de outra lista inteiramente para armazenar os gráficos de cada placa! E para todos esses pontos de dados, precisarei de um código separado para mantê-los todos organizados corretamente, para que cada cartão seja mapeado de alguma forma para todos os dados!
Agora vamos tentar isso da maneira OOP.
Em vez de uma lista de códigos, vamos definir uma classe Card e criar uma lista de objetos Card.
Agora, de repente, tudo é muito mais simples. Se eu quiser mover a carta, não preciso descobrir onde ela está no baralho, então use-a para obter sua posição fora do conjunto de posições. Eu só tenho que dizer
thecard.pos=newpos
. Quando tiro o cartão da lista do baralho principal, não preciso fazer uma nova lista para armazenar todos os outros dados; quando o objeto do cartão se move, todas as suas propriedades se movem com ele. E se eu quero um cartão que se comporte de maneira diferente quando é invertido, não preciso modificar a função de inversão no meu código principal para que ele detecte esses cartões e faça esse comportamento diferente; Eu só tenho que subclass Card e modificar a função flip () na subclasse.Mas nada que eu fiz lá não poderia ter sido feito sem OO. É que, com uma linguagem orientada a objetos, a linguagem está fazendo muito trabalho para manter as coisas unidas por você, o que significa que você tem muito menos chance de cometer erros, e seu código é mais curto e fácil de ler e escrever.
Ou, para resumir ainda mais, o OO permite que você escreva programas aparentemente mais simples que executam o mesmo trabalho que os programas mais complexos, ocultando muitas das complexidades comuns de manipulação de dados por trás de um véu de abstração.
fonte
Tendo escrito C incorporado por alguns anos gerenciando coisas como dispositivos, portas seriais e pacotes de comunicação entre as portas seriais, portas de rede e servidores; Eu me encontrei, um engenheiro elétrico treinado, com experiência limitada em programação processual, inventando minhas próprias abstrações do hardware que acabou se manifestando no que mais tarde percebi serem o que as pessoas comuns chamam de 'Programação Orientada a Objetos'.
Quando mudei para o lado do servidor, fui exposto a uma fábrica que configurava a representação do objeto de cada dispositivo na memória na instanciação. Eu não entendi as palavras ou o que estava acontecendo a princípio - eu apenas sabia que fui ao arquivo chamado assim e tal e escrevi o código. Mais tarde, me vi novamente reconhecendo finalmente o valor do POO.
Pessoalmente, acho que essa é a única maneira de ensinar orientação a objetos. Eu tive uma aula de Introdução à OOP (Java) no meu primeiro ano e foi completamente demais. As descrições de OOP baseadas na classificação de gatinho-> gato-> mamífero-> vivo-> coisa ou folha-> galho-> árvore-> jardim são, na minha humilde opinião, metodologias absolutamente ridículas, porque ninguém nunca tentará resolvê-las. problemas, se você pudesse chamá-los de problemas ...
Eu acho que é mais fácil responder à sua pergunta se você a analisar em termos menos absolutos - não 'o que resolve', mas mais da perspectiva de 'aqui está um problema e aqui está como é mais fácil'. No meu caso específico de portas seriais, tínhamos vários #ifdefs em tempo de compilação que adicionavam e removiam código que abria e fechava estaticamente portas seriais. As funções de porta aberta eram chamadas em todo o lugar e podiam estar localizadas em qualquer lugar nas 100 mil linhas de código do sistema operacional que tínhamos, e o IDE não esmaecia o que não estava definido - era necessário rastrear isso manualmente, e carregue na sua cabeça. Inevitavelmente, você poderia ter várias tarefas tentando abrir uma determinada porta serial esperando o dispositivo na outra extremidade e, em seguida, nenhum código que você acabou de escrever funciona, e você não consegue entender o porquê.
A abstração era, embora ainda em C, uma 'classe' de porta serial (bem, apenas um tipo de dados de estrutura) em que tínhamos uma matriz de-- uma para cada porta serial - e em vez de ter [o equivalente de DMA em portas seriais] "OpenSerialPortA" "SetBaudRate" etc. funções chamadas diretamente no hardware a partir da tarefa, chamamos uma função auxiliar para a qual você passou todos os parâmetros de comunicação (baud, paridade etc.) para, que primeiro checavam a matriz da estrutura para verificar se isso a porta já havia sido aberta - se sim, por qual tarefa, que seria informada como uma depuração printf, para que você pudesse pular imediatamente para a seção de código que precisava desabilitar-- e, caso contrário, prosseguiu para definir todos os parâmetros através de suas funções de montagem HAL e, finalmente, abriu a porta.
Claro, também há perigos para o POO. Quando finalmente limpei a base de código e tornei tudo arrumado e limpo - escrever novos drivers para essa linha de produtos estava finalmente em uma ciência calculável e previsível, meu gerente fez a EOL do produto especificamente porque era um projeto a menos que ele precisaria para gerenciar, e ele era um gerente intermediário removível limítrofe. O que tirou muito de mim / achei muito desanimador, então deixei meu emprego. RI MUITO.
fonte
existem muitas alegações e intenções sobre o que / onde a programação OOP tem uma vantagem sobre a programação procedural, inclusive por seus inventores e usuários. mas apenas porque uma tecnologia foi projetada para um determinado propósito por seus projetistas, não garante que terá sucesso nesses objetivos. esse é um entendimento essencial no campo da engenharia de software, datado do famoso ensaio de Brooks "No bullet silver", que ainda é relevante apesar da revolução da codificação OOP. (consulte também o Gartner Hype Cycle para novas tecnologias.)
muitos que usaram os dois também têm opiniões de experiências anedóticas, e isso tem algum valor, mas é conhecido em muitos estudos científicos que a análise autorreferida pode ser imprecisa. parece haver pouca análise quantitativa dessas diferenças ou, se houver, não é tão citada. é surpreendente como muitos cientistas da computação falam com autoridade sobre certos tópicos centrais de seu campo, mas ainda não citam a pesquisa científica para apoiar seus pontos de vista e não percebem que estão transmitindo a sabedoria convencional em seu campo (ainda que generalizada ).
como este é um site / fórum científico , aqui está uma breve tentativa de colocar as numerosas opiniões em pé mais firme e quantificar a diferença real. pode haver outros estudos e espero que outros possam apontá-los se souberem de algum.(pergunta zen: se realmente existe uma grande diferença e tanto esforço maciço no campo comercial de engenharia de software e em outros lugares foi aplicado / investido para concretizá-lo, por que as evidências científicas disso são tão difíceis de encontrar? alguma referência clássica e altamente citada no campo que quantifique definitivamente a diferença?)
este trabalho emprega experimental / quantitativo / científico análise e apóia especificamente que a compreensão por programadores iniciantes é aprimorada com métodos de codificação OOP em alguns casos, mas foi inconclusiva em outros casos (em relação ao tamanho do programa). note que esta é apenas uma das muitas / principais reivindicações sobre a superioridade do POO sendo avançada em outras respostas e pelos defensores do POO. o estudo estava possivelmente medindo um elemento psicológico conhecido como "carga cognitiva / sobrecarga", através da compreensão da codificação.
Uma comparação da compreensão de programas orientados a objetos e de procedimentos por programadores iniciantes que interagem com computadores. Susan Wiedenbeck, Vennila Ramalingam, Suseela Sarasamma, Cynthia L Corritore (1999)
Veja também:
Qual é o benefício da programação orientada a objetos sobre a programação procedural?programmers.se
A programação processual tem alguma vantagem sobre o POO? stackoverflow
fonte
Seja cuidadoso. Leia o clássico de R. King "Meu gato é orientado a objetos" em "Conceitos, bancos de dados e aplicativos orientados a objetos" (Kim e Lochovsky, orgs) (ACM, 1989). "Orientado a objetos" tornou-se mais uma palavra da moda do que um conceito claro.
Além disso, existem muitas variações sobre o tema, com pouco em comum. Existem linguagens baseadas em protótipo (a herança é de objetos, não há classes como tais) e linguagens baseadas em classes. Existem idiomas que permitem herança múltipla, outros que não. Algumas linguagens têm uma idéia como as interfaces de Java (podem ser tomadas como uma forma de herança múltipla diluída). Existe a ideia de mixins. A herança pode ser bastante rigorosa (como em C ++, não pode realmente mudar o que você obtém em uma subclasse) ou manipulada de maneira muito liberal (em Perl, a subclasse pode redefinir quase tudo). Alguns idiomas têm uma única raiz para herança (normalmente chamada Objeto, com comportamento padrão), outros permitem que o programador crie várias árvores. Algumas línguas insistem que "tudo é um objeto", outras lidam com objetos e não-objetos, alguns (como Java) têm "a maioria são objetos, mas esses poucos tipos aqui não são". Algumas linguagens insistem no encapsulamento estrito do estado nos objetos, outras o tornam opcional (privado, protegido, público) do C ++, outras não possuem encapsulamento. Se você olhar de soslaio para um idioma como Scheme do ângulo certo, verá OOP incorporado sem nenhum esforço especial (pode definir funções que retornam funções que encapsulam algum estado local).
fonte
Para ser conciso, a Programação Orientada a Objetos aborda os problemas de segurança de dados presentes na programação procedural. Isso é feito usando o conceito de encapsular os dados, permitindo que apenas as classes legítimas herdem os dados. Modificadores de acesso facilitam alcançar esse objetivo. Espero que ajude.:)
fonte