Realmente precisamos de linguagens OO para gerenciar a complexidade do software?


209

Essa será uma pergunta muito pouco técnica e não técnica, e não tenho certeza se essa é a plataforma certa. Mas eu sou um estudante iniciante em CS, então espero que vocês tolerem.

No primeiro semestre, fomos apresentados aos conceitos de OOP, como encapsulamento, ocultação de dados, modularidade, herança e assim por diante através de Java e UML. (Java é minha primeira linguagem de programação)

Pelo que entendi, OOP é uma maneira de gerenciar a complexidade do software. Mas seus princípios não são novos ou únicos, são, de certo modo, universais em todos os campos da engenharia.

Por exemplo, um carro é uma estrutura muito complexa cuja complexidade é gerenciada por uma hierarquia de componentes modulares e encapsulados com comportamentos e interfaces bem definidos.

Mas não entendo o motivo por trás da introdução de um novo paradigma de programação. Eu acho que todos os princípios usados ​​para gerenciar a complexidade podem ser realizados por linguagens de programação procedurais. Por exemplo, para modularidade, podemos simplesmente dividir o programa em muitos pequenos programas que executam tarefas bem definidas, cujo código está contido em arquivos separados. Esses programas interagem entre si por meio de entradas e saídas bem definidas. Os arquivos podem ser protegidos (criptografados?) Para obter o encapsulamento. Para reutilização de código, podemos chamar esses arquivos sempre que forem necessários em novos programas. Isso não captura tudo o que é OOP ou estou perdendo algo muito óbvio?

Não estou pedindo uma prova de que OOP gerencia a complexidade. Na minha opinião, certamente faz. Mas acho que todos os princípios usados ​​para gerenciar a complexidade, como modularidade, encapsulamento, ocultação de dados etc. podem ser facilmente implementados por linguagens procedurais. Então, por que realmente fazer POO se podemos gerenciar a complexidade sem ela?


41
Está faltando a separação da interface e implementação. Ser capaz de trocar uma implementação por outra em tempo de execução é um recurso muito importante. Basicamente, isso é conseguido pelo envio dinâmico de métodos de linguagens OO com herança. Linguagens procedurais também podem fazer isso (leia-se: void pointers), mas sem a segurança do tipo.
marstato

81
Em grande parte, a idéia de linguagens e design orientados a objetos é justamente tornar esses conceitos universais e intuitivos o mais fácil possível para representar e recriar no código. Se você tivesse um esquema ou um conjunto de diretrizes sobre como conseguir todas essas coisas sem uma linguagem inerentemente orientada a objetos, suas propostas sobre como fazer as coisas seriam efetivamente a metodologia orientada a objetos usada. Os idiomas OO reais são apenas uma maneira de formalizar e simplificar isso.
Standback

14
@RobbieDee você realmente leu minha pergunta? Trata-se de tentar entender o OO em um nível mais fundamental, questionando o tempo em que a complexidade do software pode ser gerenciada sem o OO. Não estou tentando minar o OO, não tentando inventar algo novo, apenas tentando entendê-lo melhor e, se a pergunta é tão "evidente", por que recebeu a excelente resposta de Jorg?
steakexchange

12
Criptografar um arquivo não é encapsulamento. Você pode ter ocultado a visualização do conteúdo do código de outro desenvolvedor, mas não necessariamente protegeu o funcionamento interno do código de outro código. O autor original poderia fazer isso antes ou depois da criptografia, se ele se lembrar de como.
JeffO 20/03/19

8
Você não precisa de nada além da linguagem de máquina - deixe o programador memorizar os códigos de operação e escrever os zeros e os. Mas ter algum tipo de linguagem "simbólica" é muito útil em termos de redução de erros e aumento da produtividade e, como observou Dijkstra, uma linguagem que impõe alguma "estrutura" (ou pelo menos facilita a manutenção da "estrutura") ajuda consideravelmente. As linguagens OO podem não ser a tecnologia ideal, dado o nível atual de sofisticação da linguagem, mas são muito boas para muitos aplicativos. A idéia é gerenciar a complexidade sem atrapalhar.
Daniel R Hicks

Respostas:


177

Deixe-me tentar com uma resposta muito baixa da teoria :)

O que você realmente está perguntando é: Por que incluir suporte à Orientação a Objetos (OO) diretamente no idioma quando linguagens procedurais podem ser usadas para criar e escrever código OO?

E a resposta é: Ter um padrão de como o OO é expresso no código-fonte, para que você não termine com 22 implementações diferentes para a mesma abstração.

Por exemplo, digamos que eu crie um MagicButtone um MagicSliderque possa ser usado em um sistema de interface com o usuário. Eu preciso de uma maneira de agrupar os métodos que podem ser usados ​​com o MagicButton, os métodos que só podem ser usados ​​com o MagicSlider e os métodos que podem ser usados ​​por ambos. Esses objetos compartilham alguns métodos porque são ambos objetos mágicos da GUI.

Eu posso fazer o agrupamento nomeando funções de uma maneira especial MagicSlider_DoSomething ..., incluindo os métodos em arquivos específicos nomeados de uma maneira especial MagicSliderMethods.XXX, ou eu poderia encontrar outra maneira especial de fazer a mesma coisa. Se não houver uma maneira padrão no idioma para fazê-lo, farei diferente de você e de qualquer outra pessoa. Isso torna o compartilhamento de código muito mais difícil.

Sim, o envio tardio - métodos virtuais em linguagens OO - pode ser implementado em linguagens procedurais, mas existem muitas maneiras diferentes de implementá-lo. Dependendo de quem escreveu o código, você terminará com diferentes implementações de OO dentro do mesmo programa.

Pense no pobre desenvolvedor de manutenção. Essa pessoa deve gerenciar diferentes abstrações de objetos e maneiras diferentes de chamar métodos virtuais, dependendo de quem escreveu o código original.

Além disso: ter as abstrações no idioma permite que editores de código avançados, como o Eclipse, façam muitas análises estáticas no código. Por exemplo, o Eclipse pode oferecer uma lista de todos os métodos que podem ser usados ​​em um objeto, bem como a implementação automática de "métodos TODO" vazios. O Eclispe sabe exatamente quais métodos sua classe deve implementar com base em quais classes você estende e em quais interfaces você implementa. Isso seria quase impossível se não houvesse um padrão de linguagem para fazer OO.


40
Exemplo clássico: Lua. Não é OO nativo, mas pode ser feito, mas isso significa que existem cerca de 5 bibliotecas OO igualmente conhecidas e diferentes que não são totalmente interoperáveis.
Kroltan

55
@steakexchange Você se concentra demais em absolutos. Muito pouco tem um "único objetivo". Todos os idiomas fazem muitas coisas diferentes, com diferentes graus de qualidade. Escolher um idioma é escolher o conjunto de trocas que o tornam mais adequado ao objetivo para o qual você precisa.
Tim B

42
@nocomprende Padronizar abstrações é quase literalmente para que servem as linguagens de programação. Até a linguagem assembly abstrai as diferenças em algo como dez gerações de hardware em uma década e meia.
David Moles

56
@DavidMoles As abstrações padronizadas são literalmente o que são linguagens de programação. Não perca a oportunidade perfeita de usar "literalmente" literalmente!
Clement Cherlin

12
É possível padronizar isso. Quando eu estava na universidade, em meados dos anos 90, trabalhei bastante no X-Windows (principalmente baseado no Motif, para aqueles que se lembram dessas coisas). O X-Windows de fato permitiu implementar todos os recursos de orientação a objetos em C regular . A ginástica mental para fazê-lo era bastante substancial e dependia muito de pessoas que não olhavam para dentro da caixa (nesse momento o Código Widget de Schroedinger geralmente acabava morto). As linguagens OO ocultam isso dos codificadores, da mesma maneira que um compilador comum faz para o assembler, e a vida é mais fácil.
Graham

211

No primeiro semestre, fomos apresentados aos conceitos de OOP, como encapsulamento, ocultação de dados, modularidade, herança e assim por diante através de Java e UML. (Java é minha primeira linguagem de programação)

Nenhum desses são conceitos de POO. Todos eles existem fora do OO, independentemente do OO e muitos até foram inventados antes do OO.

Então, se você acha que é disso que se trata o OO, sua conclusão é correta: você pode fazer tudo isso em linguagens processuais, porque eles não têm nada a ver com o OO .

Por exemplo, um dos documentos seminais sobre Modularidade é Sobre os critérios a serem usados ​​na decomposição de sistemas em módulos . Não há menção de OO lá. (Foi escrito em 1972, então o OO ainda era um nicho obscuro, apesar de já ter mais de uma década.)

Embora a Abstração de Dados seja importante no OO, é mais uma consequência do recurso principal do OO (Sistema de Mensagens) do que um recurso definidor. Além disso, é muito importante lembrar que existem diferentes tipos de abstração de dados. Os dois tipos mais comuns de abstração de dados em uso atualmente (se ignorarmos "nenhuma abstração", que provavelmente ainda é usada mais do que as outras duas combinadas) são tipos e objetos de dados abstratos . Assim, apenas dizendo "Information Hiding", "Encapsulation" e "Data Abstraction", você não disse nada sobre OO, pois OO é apenas uma forma de Abstração de Dados, e as duas são de fato fundamentalmente diferentes:

  • Com tipos de dados abstratos, o mecanismo para abstração é o sistema de tipos ; é o sistema de tipos que oculta a implementação. (O sistema de tipos não precisa necessariamente ser estático.) Com Objetos, a implementação fica oculta por trás de uma interface procedural , que não requer tipos. (Por exemplo, ele pode ser implementado com fechamentos, como é feito no ECMAScript.)
  • Com Tipos de dados abstratos, instâncias de ADTs diferentes são encapsuladas uma da outra, mas instâncias do mesmo ADT podem inspecionar e acessar a representação e implementação privada uma da outra. Os objetos são sempre encapsulados de tudo . Somente o próprio objeto pode inspecionar sua própria representação e acessar sua própria implementação privada. Nenhum outro objeto , nem mesmo outros objetos do mesmo tipo, outras instâncias da mesma classe, outros objetos com o mesmo protótipo, clones do objeto ou qualquer outra coisa que possa fazer isso. Nenhuma .

A propósito, o que isso significa é que, em Java, as classes não são orientadas a objetos. Duas instâncias da mesma classe podem acessar a representação e a implementação privada uma da outra. Portanto, instâncias de classes não são objetos, na verdade são instâncias ADT. Java interfaces, no entanto, não fornecem abstração de dados orientado a objetos. Portanto, em outras palavras: apenas instâncias de interfaces são objetos em Java, instâncias de classes não.

Basicamente, para tipos, você só pode usar interfaces. Isso significa tipos de parâmetros de métodos e construtores, tipos de métodos de retorno, tipos de campos de instância, campos estáticos e campos locais, o argumento para um instanceofoperador ou operador de conversão e argumentos de tipo para um construtor de tipo genérico sempre devem ser interfaces. Uma classe pode ser usada apenas diretamente após o newoperador, em nenhum outro lugar.

Por exemplo, para modularidade, podemos simplesmente dividir o programa em muitos pequenos programas que executam tarefas bem definidas, cujo código está contido em arquivos separados. Esses programas interagem entre si por meio de entradas e saídas bem definidas. Os arquivos podem ser protegidos (criptografados?) Para obter o encapsulamento. Para reutilização de código, podemos chamar esses arquivos sempre que forem necessários em novos programas. Isso não captura tudo o que é OOP ou estou perdendo algo muito óbvio?

O que você descreve é OO.

Essa é realmente uma boa maneira de pensar sobre OO. De fato, isso é exatamente o que os inventores originais da OO tinham em mente. (Alan Kay foi um passo além: ele imaginava muitos computadores pequenos enviando mensagens entre si pela rede.) O que você chama de "programa" geralmente é chamado de "objeto" e, em vez de "chamada", costumamos dizer "enviar uma mensagem" "

Orientação a Objetos tem tudo a ver com Mensagens (também conhecido como despacho dinâmico ). O termo "Orientado a Objetos" foi cunhado pelo Dr. Alan Kay, o principal designer do Smalltalk, e ele o define assim :

OOP para mim significa apenas mensagens, retenção e proteção local e ocultação de processos estatais e vinculação extrema de todas as coisas.

Vamos detalhar isso:

  • sistema de mensagens ("despacho de método virtual", se você não estiver familiarizado com o Smalltalk)
  • processo estadual deve ser
    • retido localmente
    • protegido
    • escondido
  • extrema ligação tardia de todas as coisas

Em termos de implementação, o sistema de mensagens é uma chamada de procedimento com limite tardio e, se as chamadas de procedimento são limitadas com atraso, não é possível saber em tempo de design o que você chamará, portanto, não é possível fazer suposições sobre a representação concreta do estado. Então, realmente se trata de mensagens, a ligação tardia é uma implementação de mensagens e o encapsulamento é uma conseqüência disso.

Mais tarde, ele esclareceu que " a grande idéia é ' enviar mensagens' " e lamenta tê-la chamado de "orientado a objetos" em vez de "orientado a mensagens", porque o termo "orientado a objetos" coloca o foco na coisa sem importância (objetos ) e distrai o que é realmente importante (mensagens):

Apenas um lembrete gentil de que eu me esforcei no último OOPSLA para tentar lembrar a todos que o Smalltalk não é apenas NÃO sua sintaxe ou a biblioteca de classes, nem mesmo sobre aulas. Sinto muito que, há muito tempo, cunhei o termo "objetos" para este tópico porque leva muitas pessoas a se concentrarem na idéia menor.

A grande idéia é "mensagens" - é disso que trata o kernal do Smalltalk / Squeak (e é algo que nunca foi totalmente concluído em nossa fase do Xerox PARC). Os japoneses têm uma pequena palavra - ma - para "o que está no meio" - talvez o equivalente em inglês mais próximo seja "intersticial". A chave para criar sistemas grandes e cultiváveis ​​é muito mais para projetar como seus módulos se comunicam do que quais devem ser suas propriedades e comportamentos internos. Pense na Internet - para viver, ela (a) precisa permitir muitos tipos diferentes de idéias e realizações que estão além de qualquer padrão único e (b) permitir graus variados de interoperabilidade segura entre essas idéias.

(É claro que hoje em dia a maioria das pessoas nem se concentra nos objetos, mas nas classes, o que é ainda mais errado.)

As mensagens são fundamentais para o OO, tanto como metáfora quanto como mecanismo.

Se você envia uma mensagem a alguém, não sabe o que ela faz. A única coisa que você pode observar é a resposta deles. Você não sabe se eles próprios processaram a mensagem (por exemplo, se o objeto possui um método), se encaminharam a mensagem para outra pessoa (delegação / proxy), se eles a entenderam. É disso que se trata o encapsulamento, do OO. Você não pode nem distinguir um proxy do real, desde que ele responda como você espera.

Um termo mais "moderno" para "sistema de mensagens" é "envio dinâmico de método" ou "chamada virtual de método", mas que perde a metáfora e se concentra no mecanismo.

Portanto, existem duas maneiras de analisar a definição de Alan Kay: se você a considerar por conta própria, poderá observar que as mensagens são basicamente uma chamada de procedimento de ligação tardia e a ligação tardia implica encapsulamento, para que possamos concluir que # 1 e # 2 são realmente redundantes, e OO é tudo sobre ligação tardia.

No entanto, mais tarde ele esclareceu que o importante é o envio de mensagens e, portanto, podemos vê-lo de um ângulo diferente: o envio de mensagens é tardio. Agora, se as mensagens fossem a única coisa possível, o número 3 seria trivialmente verdadeiro: se houver apenas uma coisa, e essa coisa for atrasada, todas as coisas serão atrasadas. E mais uma vez, o encapsulamento segue as mensagens.

Pontos semelhantes também são apresentados em On Understanding Data Abstraction, revisitado por William R. Cook e também em sua Proposta de definições modernas e simplificadas de "Objeto" e "Objeto Orientado" :

O envio dinâmico de operações é a característica essencial dos objetos. Isso significa que a operação a ser invocada é uma propriedade dinâmica do próprio objeto. As operações não podem ser identificadas estaticamente e, em geral, não há como saber exatamente qual operação será executada em resposta a uma determinada solicitação, exceto executando-a. É exatamente igual às funções de primeira classe, sempre despachadas dinamicamente.

No Smalltalk-72, não havia nenhum objeto! Havia apenas fluxos de mensagens que foram analisados, reescritos e redirecionados. Primeiro vieram os métodos (maneiras padrão de analisar e redirecionar os fluxos de mensagens), depois vieram os objetos (agrupamentos de métodos que compartilham algum estado privado). A herança veio muito mais tarde, e as classes foram introduzidas apenas como uma maneira de apoiar a herança. Se o grupo de pesquisa de Kay já soubesse sobre protótipos, eles provavelmente nunca teriam introduzido aulas em primeiro lugar.

Benjamin Pierce, em Tipos e linguagens de programação, argumenta que o recurso definidor da orientação a objetos é a recursão aberta .

Então: de acordo com Alan Kay, OO é tudo sobre mensagens. De acordo com William Cook, OO tem tudo a ver com o envio de método dinâmico (que é realmente a mesma coisa). De acordo com Benjamin Pierce, OO é tudo sobre Open Recursion, o que basicamente significa que as referências automáticas são resolvidas dinamicamente (ou pelo menos é uma maneira de pensar), ou, em outras palavras, mensagens.

Como você pode ver, a pessoa que cunhou o termo "OO" tem uma visão bastante metafísica dos objetos, Cook tem uma visão bastante pragmática e Pierce uma visão matemática muito rigorosa. Mas o importante é: o filósofo, o pragmatista e o teórico concordam! As mensagens são o único pilar da OO. Período.

Observe que não há menção de herança aqui! A herança não é essencial para o OO. Em geral, a maioria das linguagens OO tem algum modo de reutilização da implementação, mas isso não necessariamente tem que ser herança. Também poderia ser uma forma de delegação, por exemplo. De fato, o Tratado de Orlando discute a delegação como uma alternativa à herança e como diferentes formas de delegação e herança levam a diferentes pontos de design no espaço de design das linguagens orientadas a objetos. (Observe que, mesmo em linguagens que suportam herança, como Java, as pessoas são ensinadas a evitá-la, indicando novamente que não é necessário para o OO).


16
100 - Nós colocamos a culpa inerente nas coisas porque elas estão sendo usadas de maneira inadequada.
JeffO 20/03/19

55
Desculpe, mas isso é incrivelmente errado. Alan Kay pode ter inventado o termo, mas os princípios já existiam antes do Smalltalk. A programação orientada a objetos deriva do Simula, e seu estilo OO não tinha nada a ver com "mensagens". Praticamente todas as linguagens OO que foram bem-sucedidas foram baseadas nos princípios básicos estabelecidos no Simula - os mesmos que vemos em Java - e o OO no estilo Smalltalk foi um fracasso no "mercado de ideias" toda vez que é reintroduzido, porque simplesmente não funciona muito bem. O nome foi a única coisa verdadeiramente significativa que Kay contribuiu.
Mason Wheeler

23
@steakexchange Não. "A essência do OO", o que o torna verdadeiramente distinto, são objetos com métodos virtuais. Há uma razão para ninguém usar o Smalltalk: o sistema de transmissão de mensagens funciona muito mal na escala de computadores individuais. Toda vez que algum designer de linguagem bem-intencionado, mas ingênuo, tenta reimplementar os princípios do Smalltalk, acaba falhando. (O exemplo mais recente seria o Objective-C, que ninguém jamais usaria se Steve Jobs não tivesse empurrado a garganta da comunidade iOS inteira. Nunca houve tração fora do ecossistema da Apple, e há uma razão para isso. )
Mason Wheeler

28
@MasonWheeler Você poderia elaborar seu comentário em uma resposta, já que tem uma visão oposta ao que Jorg está dizendo?
steakexchange

20
Também vale a pena notar que o conceito de linguagens orientadas a objetos evoluiu muito. Hoje em dia, esses conceitos ancestrais podem não ser tão verdadeiros com muitas linguagens que abandonam os modelos antigos e adotam multiparadigmas. Veja o C #, por exemplo - que a linguagem mistura quase tudo ao sol de uma só vez e, embora na maioria das vezes seja referida como uma linguagem OO, na verdade é uma mistura de paradigmas diferentes. Isso permite que seja uma ferramenta realmente expressiva para desenvolvedores ao redor. Além disso, o OO baseado em classe é um dos muitos sabores igualmente válidos da programação OO.
21717

66

Mas acho que todos os princípios usados ​​para gerenciar a complexidade, como modularidade, encapsulamento, ocultação de dados etc. podem ser facilmente implementados por linguagens procedurais.

Quando você diz "muito facilmente", está fazendo uma afirmação muito ousada. O jeito que eu li é: "Não vejo dificuldade, então não deve ser muito grande". Quando formulado dessa maneira, fica claro que você não está perguntando "por que precisamos de OO", mas sim "por que as dificuldades encontradas por outros paradigmas de programação que levam à invenção do OO são imediatamente aparentes para mim?" "

Uma resposta para essa pergunta é que muitas dessas dificuldades não existem nos tipos de programas em que você está trabalhando. Você não está sendo solicitado a atualizar o código de espaguete de 40 anos. Você não está tentando escrever um novo gerenciador de exibição para um sistema operacional. Você não está depurando aplicativos distribuídos multithread.

Para muitos dos tipos de programas de brinquedo que nós, estudantes de CS, somos incumbidos de escrever, podemos escrevê-los no BASIC ou na montagem, como Java ou Python. Isso ocorre porque a complexidade inerente das tarefas é muito baixa, existe apenas um desenvolvedor, não há problemas de interoperabilidade herdados, o desempenho não importa e o código provavelmente será executado apenas algumas vezes em uma máquina.

Imagine pegar um estudante e pedir para eles se fundirem em uma rua movimentada na hora do rush, em uma transmissão manual sem sincronização, subindo uma colina íngreme. Desastre. Por quê? Eles não conseguem gerenciar o nível de complexidade necessário para seguir simultaneamente todas as regras exigidas pela tarefa.

Agora imagine o mesmo aluno, o mesmo veículo, dirigindo a passos largos em um estacionamento vazio. Eles estão bem, porque seu nível de habilidade é adequado à tarefa. Não há pressão, pouco risco, e eles podem realizar as subtarefas individuais de partida, embreagem, mudança, aceleração e direção, uma de cada vez.

Esse aluno pode perguntar por que temos transmissões automáticas, se um motorista experiente pode fazer todas essas coisas simultaneamente? A resposta é que um motorista habilidoso não precisa, em condições ideais, de um automático. Mas nem todos somos condutores profissionais em perfeitas condições e normalmente queremos a conveniência de ter os projetistas do carro cuidando de toda essa complexidade para nós.

Um programador qualificado e disciplinado o suficiente pode realmente criar um sistema de alta complexidade em C ou montagem. Mas não somos todos Linus Torvalds. Nem devemos ter que ser, para criar software útil.

Pessoalmente, não tenho interesse em ter que reinventar todos os recursos de uma linguagem moderna antes que eu possa resolver o problema em questão. Se eu posso tirar proveito de uma linguagem que inclui soluções para problemas já resolvidos, por que não?

Então, eu mudarei sua pergunta e perguntarei se as linguagens oferecem recursos convenientes, como encapsulamento e polimorfismo, por que não devemos usá-las?


13
Então, basicamente, é possível fazer OO com uma linguagem processual, mas isso é feito manualmente, enquanto o uso de uma linguagem OO padronizada automatiza e simplifica.
steakexchange

6
@steakexchange Praticamente exatamente isso.
Tim B

3
@steakexchange Um bom exemplo histórico disso foi o modelo de objeto para o X Windows na época. Foi escrito em C, mas foi baseado em um sistema orientado a objetos. Então, você tinha que seguir certas convenções para interagir com ele, para que suas aulas fossem boas com as de todos os outros.
Ukko

7
@nocomprende Certamente. Mas pode-se tornar o computador não inicializável, fazendo gravações em disco bruto em vez de depender do sistema de arquivos, e será realmente difícil depurar problemas em um sistema de objetos ad-hoc criado por um iniciante. O encapsulamento, quando feito corretamente, nos impede de interferir intencionalmente ou não com coisas que não devemos.
Clement Cherlin

3
É interessante para mim que os exemplos que você dá de aplicativos que se beneficiariam com o OO geralmente não são escritos em idiomas OO. O espaguete de 40 anos provavelmente está escrito em C, COBOL, FORTRAN ou REXX. O gestor de ecrã é provável escrita em C (embora com convenções OO-ish), e diversos sistemas de vários segmentos distribuídos bem sucedidos são escritos no Erlang, Ir ou C.
James_pic

22

O que você está descrevendo não é OOP, é abstração. A abstração está presente em todos os modelos modernos de design, mesmo aqueles que não são OOP. E OOP é um tipo muito específico de abstração.

Primeiro, vale a pena notar que não há uma definição única de OOP, portanto, pode haver pessoas que discordam do que estou caracterizando como OOP.

Em segundo lugar, é importante lembrar que o OOP foi inspirado nos modelos tradicionais de design; portanto, as semelhanças com o design do carro não são coincidência.

No entanto, aqui estão algumas maneiras pelas quais o OOP é mais matizado do que você disse:

  • Encapsulamento: não se trata apenas de ter uma interface definida para um módulo (ou seja, abstração), mas de proibir o acesso além dessa interface. Em Java, acessar uma variável privada é um erro de compilação, enquanto no design do seu carro, você pode (em alguns casos) usar as coisas de uma maneira diferente da interface pretendida.

  • Herança: Isso é realmente o que torna o OOP único. Depois de definir uma interface, você pode fazer várias coisas implementando essa interface e fazer isso de maneira hierárquica, alterando partes específicas de sua implementação e herdando todas as partes anteriores, reduzindo enormemente a duplicação de código.

    Se você pensa em termos dos componentes encapsulados de um carro, não há realmente um equivalente a isso. Não há como eu fazer uma engrenagem, pegando uma engrenagem diferente e alterando uma parte específica de sua implementação. (Pelo menos acho que não, não sei muito sobre carros).

  • Polimorfismo : Depois de definir uma interface, qualquer coisa que use essa interface deve ser indistinguível, do ponto de vista de quais operações estão disponíveis, e você não precisa saber qual implementação está sendo usada para usar uma interface. É aqui que a subtipagem e o Princípio da Substituição de Liskov se tornam importantes.

  • Acoplamento : Um aspecto fundamental do OOP é que relacionamos as coisas com as mesmas operações e espalhamos as diferentes formas que elas podem ter. Os dados são empacotados com operações nesses dados. Isso significa que é muito fácil adicionar uma nova forma de dados (uma nova implementação), mas muito difícil adicionar uma nova operação a uma interface (já que você precisaria atualizar cada classe que implementa a interface). Isso contrasta com os tipos de dados algébricos em linguagens funcionais, onde é muito fácil adicionar uma nova operação (você acabou de escrever uma função que lida com todos os casos), mas difícil adicionar uma nova variante (já que você precisa adicionar uma nova caso a todas as suas funções).


11
Boa resposta! Uma parte com a qual não concordo: a distinção que você está traçando sobre o encapsulamento não é válida. Encapsulamento sempre significa "proibir o acesso além dessa interface" - isso é verdade para configurações de OOP e não-OOP. Portanto, essa parte não é realmente algo exclusivo do OOP.
DW

@DW Tentei esclarecer isso, dizendo que não é exclusivo do OOP, mas que é a diferença entre encapsulamento e abstração. Obrigado pelo feedback!
jmite

2
ESTÁ BEM. Mas ainda tenho uma visão diferente sobre o que está escrito aqui sobre esse assunto. Você escreveu que "aqui estão algumas maneiras pelas quais o OOP é mais sutil do que o que você disse", mas o encapsulamento não é um modo que o OOP é mais sutil do que o que foi escrito na pergunta. Encapsulamento é o que é, em qualquer paradigma. E onde você escreveu que "O que você está descrevendo não é OOP, é abstração", pensei que a pergunta original estava tentando descrever o encapsulamento (não apenas a abstração). Acho que vou deixar esse comentário como uma perspectiva diferente. Eu acho que a resposta é muito útil!
DW

A herança é um recurso comum, mas várias linguagens OO importantes não o possuem.
Bradd Szonye

Boa resposta, mas na IMO você está exagerando no exemplo do carro. Um motor para um determinado modelo possui uma interface bem definida (eixo de came, "receptáculos" do suporte de montagem etc.). Você pode substituir um carburador velho comum por um injetado a combustível, adicionar um turbocompressor, etc., sem afetar a transmissão. (Embora um motor diesel exija um tanque de combustível IIRC modificado.) Por outro lado, você pode substituir uma transmissão manual por uma AFAIK automática e que não afete o motor.
David

11

Realmente precisamos de linguagens OO para gerenciar a complexidade do software?

Isso depende do significado da palavra "necessidade".

Se "necessidade" significa requer, não, nós não exigimos.

Se "necessidade" significa "fornece fortes benefícios", então eu diria "Sim", nós o desejamos.

Quadro grande

Os idiomas OO vinculam funcionalidade aos dados.

Você pode evitar essa ligação e funções de gravação que transmitem valores de dados.

Mas então você provavelmente terminará com constelações de dados que combinam e começará a distribuir tuplas, registros ou dicionários de dados.

E, na verdade, são todas as chamadas de métodos: funções parciais em conjuntos de dados vinculados.

Recurso por recurso

Recursos do OOP:

  • A herança permite a reutilização de código (mixins) e conceito (classes básicas abstratas / interfaces) - mas você pode obtê-lo redecorando funções e variáveis ​​em um sub-escopo.
  • O encapsulamento permite ocultar informações para que possamos trabalhar em níveis mais altos de abstração - mas você pode fazer isso com arquivos de cabeçalho, funções e módulos.
  • O polimorfismo nos permite usar argumentos de tipos diferentes, desde que esses argumentos suportem as mesmas interfaces - mas também podemos fazer isso com funções.

No entanto, nenhuma dessas coisas acontece tão facilmente quanto em uma linguagem orientada a objetos com suporte de primeira classe a esses recursos.

Referências

Existem muitos críticos de OOP .

No entanto, estudos parecem indicar que obtemos maior produtividade do programador da reutilização de código por meio do OOP. Esta é uma descoberta controversa, e alguns pesquisadores dizem que não podem reproduzir esses ganhos de produtividade, dadas certas restrições. (fonte)

Conclusão

Nós não "precisamos" de POO. Mas, em alguns casos, o usuário deseja POO.

Meu entendimento é que programadores maduros podem ser bastante produtivos no estilo orientado a objetos. E quando os pacotes têm objetos principais com interfaces simples que são facilmente compreendidas, até novos programadores podem se tornar bastante produtivos rapidamente.


10

Vou tentar ser breve.

O princípio central do OO é a combinação de dados e comportamento em uma única unidade organizacional (um objeto).

Isso é o que nos permite controlar a complexidade e era um conceito bastante inovador quando surgiu. Compare isso com os arquivos, por um lado (dados puros), os programas que lêem e processam esses arquivos, por outro lado (lógica pura) e a saída (dados puros novamente).

Somente quando você tiver esse pacote de dados e lógica juntos, modelando alguma entidade do mundo real, você poderá começar a trocar mensagens, criar classes-filhos, separar dados e comportamentos públicos e privados, implementar comportamentos polimórficos e fazer toda essa mágica específica de OO.

Então, sim, OO é um grande negócio. E não, não é apenas um monte de coisas antigas com um nome chique.

Desmontar tudo, olhar para os elementos e depois dizer "oh, bem, não há nada aqui que eu não tenha visto antes" não é reconhecer a montagem que sustenta a inovação. O resultado é mais do que a soma de suas partes.


8

Não existe uma definição "oficial" de programação orientada a objetos, e pessoas razoáveis ​​discordam do que realmente está definindo a qualidade do OO. Alguns dizem que mensagens, outros dizem subtipos, outros dizem herança, outros dizem que o agrupamento de dados e comportamento. Isso não significa que o termo não tenha sentido, apenas que você não deve ficar muito envolvido em discussões sobre o que é o verdadeiro OO.

Encapsulamento e modularidade são princípios mais fundamentais do design e devem ser aplicados em todos os paradigmas de programação. Os defensores do OO não afirmam que essas propriedades só podem ser alcançadas com o OO - apenas que o OO é particularmente adequado para isso. É claro que os proponentes de outros paradigmas, como a programação funcional, afirmam o mesmo para o seu paradigma. Na prática, muitas linguagens de sucesso são multiparadigma e o OO, funcional etc. deve ser visto como ferramenta, e não como "o único caminho verdadeiro".

Eu acho que todos os princípios usados ​​para gerenciar a complexidade podem ser realizados por linguagens de programação procedurais.

Verdade, porque no final você pode fazer qualquer coisa em qualquer linguagem de programação. Pode ser mais fácil em alguns idiomas do que em outros, pois todos os idiomas têm pontos fortes e fracos diferentes.


7

Algo que as outras respostas não mencionaram: estado.

Você fala sobre OO como uma ferramenta para gerenciar a complexidade . O que é complexidade? Esse é um termo confuso. Todos nós temos esse senso gestalt do que isso significa, mas é mais difícil identificá-lo. Poderíamos medir a complexidade ciclomática, ou seja, o número de caminhos de tempo de execução através do código, mas não sei sobre o que estamos falando quando usamos o OO para gerenciar a complexidade.

O que acho que estamos falando é da complexidade relacionada ao estado.

Há duas idéias principais por trás do encapsulamento . Um deles, a ocultação de detalhes de implementação , é bastante bem coberto nas outras respostas. Mas outro está escondendo seu estado de tempo de execução . Não mexemos nos dados internos dos objetos; passamos mensagens (ou chamamos métodos, se você preferir os detalhes da implementação do que o conceito, como Jörg Mittag apontou). Por quê?

As pessoas já mencionaram isso porque você não pode alterar a estrutura interna dos seus dados sem alterar o código que os acessa, e você deseja fazer isso em um local (o método acessador) em vez de 300 locais.

Mas também é porque torna o código difícil de raciocinar : o código processual (seja em uma linguagem de natureza processual ou simplesmente escrita nesse estilo) oferece pouca ajuda para impor restrições à mutação de estado. Qualquer coisa pode mudar a qualquer momento e de qualquer lugar. As funções / métodos de chamada podem ter ação assustadora à distância. O teste automatizado é mais difícil, pois o sucesso dos testes é determinado pelo valor de variáveis ​​não locais que são amplamente acessadas / acessíveis.

Os outros dois grandes paradigmas de programação (OO e funcional) oferecem soluções interessantes, mas quase diametralmente opostas, para o problema da complexidade relacionada ao estado. Na programação funcional, tenta-se evitá-lo completamente: as funções são geralmente puras, as operações nas estruturas de dados retornam cópias em vez de atualizar o original no local, etc.

OO, por outro lado, oferece ferramentas para lidar com o gerenciamento de estado (em vez de ferramentas para evitá-lo). Além das ferramentas no nível do idioma, como modificadores de acesso (protegido / público / privado), getters e setters, etc., também existem várias convenções relacionadas, como a Lei de Demeter, que desaconselha o alcance de objetos para obter dados de outros objetos. .

Observe que você não precisa de objetos para fazer realmente nada disso: você pode ter um fechamento com dados inacessíveis e retornar uma estrutura de dados de funções para manipulá-los. Mas isso não é um objeto? Isso não se encaixa intuitivamente na nossa concepção do que é um objeto? E se tivermos esse conceito, não é melhor repeti-lo na linguagem, em vez de (como outras respostas disseram) depender de uma explosão combinatória de implementações ad-hoc concorrentes?


5

Realmente precisamos de linguagens OO para gerenciar a complexidade do software?

Não. Mas eles podem ajudar em muitas situações.

Eu uso principalmente uma única linguagem OO há décadas, mas a maior parte do meu código é realmente estritamente pré-OO. No entanto, para qualquer coisa que envolva uma GUI, uso a vasta biblioteca OO da linguagem de métodos e objetos internos, porque simplifica tremendamente o meu código.

Por exemplo, um aplicativo do Windows que usa a API original do Windows de baixo nível para exibir um formulário, um botão e um campo de edição requer muito código; ao invés disso, o uso das bibliotecas de objetos que acompanham o Visual Basic ou C # ou Delphi fazem o mesmo programa minúsculo e trivial. Portanto, meu código OO geralmente é relativamente pequeno e para a GUI, enquanto o código que esses objetos chamam geralmente é muito maior e geralmente não se preocupa em ser OO (embora possa variar dependendo do problema que estou tentando resolver).

Eu já vi programas de OO muito complicados, baseados em regras esotéricas complicadas sobre como os objetos foram implementados e poderiam ser muito mais simples se escritos sem os conceitos de OO. Eu também vi o oposto: sistemas complexos que clamam por serem reimplementados e simplificados usando objetos.

À medida que você ganha experiência, descobre que situações diferentes exigem ferramentas e soluções diferentes, e um tamanho não serve para todos.


3

Como alguém que está envolvido em um projeto muito grande inteiramente escrito em C, posso definitivamente dizer que a resposta é um claro "não".

A modularidade é importante. Mas a modularidade pode ser implementada em praticamente qualquer linguagem decente. Por exemplo, C suporta compilação modular, arquivos de cabeçalho e tipos de estrutura. Isso é suficiente para 99% dos casos. Defina um módulo para cada novo tipo de dados abstratos necessário e defina as funções para operar no tipo de dados. Às vezes, você deseja desempenho e essas funções estão no arquivo de cabeçalho como funções embutidas; outras vezes, você usará funções padrão. É tudo invisível para o usuário de que maneira é escolhida.

Estruturas suportam composição. Por exemplo, você pode ter uma tabela de hash bloqueada que consiste em um bloqueio mutex e uma tabela de hash regular. Isso não é programação orientada a objetos; nenhuma subclasse é feita. A composição é uma ferramenta muito mais antiga que a idéia de programação orientada a objetos.

Para 1% dos casos em que a modularidade no nível de compilação não é suficiente e você precisa de modularidade no tempo de execução, existe uma coisa chamada ponteiros de função. Eles permitem ter implementações individuais de uma interface bem definida. Observe que isso não é programação orientada a objetos em uma linguagem não orientada a objetos. Isso está definindo uma interface e, em seguida, implementando-a. Por exemplo, a subclasse não é usada aqui.

Considere talvez o projeto de código aberto mais complexo que existe. Ou seja, o kernel do Linux. Está escrito inteiramente na linguagem C. Isso é feito principalmente usando as ferramentas de modularidade de nível de compilação padrão, incluindo composição e, ocasionalmente, sempre que a modularidade de tempo de execução é necessária, ponteiros de função são usados ​​para definir e implementar uma interface.

Se você tentar encontrar um exemplo de programação orientada a objetos no kernel do Linux, tenho certeza de que é muito difícil encontrar esse exemplo, a menos que você estenda a programação orientada a objetos para incluir tarefas padrão como "definir uma interface e implementá-la".

Observe que mesmo a linguagem de programação C suporta programação orientada a objetos, se você realmente precisar. Por exemplo, considere o kit de ferramentas da interface gráfica do usuário GTK. Na verdade, é orientado a objetos, embora escrito em uma linguagem não orientada a objetos. Portanto, isso mostra que a idéia de que você precisa de uma "linguagem orientada a objetos" é profundamente falha. Não há nada que uma linguagem orientada a objetos possa fazer que outro tipo de linguagem não possa fazer. Além disso, se você é um programador especialista, sabe como escrever código orientado a objetos em qualquer idioma com muita facilidade. Não é um fardo usar C, por exemplo.

Portanto, as conclusões são de que as linguagens orientadas a objetos provavelmente são úteis apenas para programadores iniciantes que não conseguem entender como o conceito é realmente implementado. No entanto, eu não gostaria de estar perto de qualquer projeto em que os programadores sejam programadores iniciantes.


11
"[...] as conclusões são de que as linguagens orientadas a objetos provavelmente são úteis apenas para programadores iniciantes que não conseguem entender como o conceito é realmente implementado." Interessante. Quais idiomas você tem em mente? Você tem exemplos de projetos de código aberto escritos nesses idiomas que falharam ou não?
22717 Vincent Savard

3
Você levanta alguns bons pontos, mas sua idéia principal é falha. Sim, é possível implementar conceitos de OO, como encapsulamento, despacho virtual, herança e até coleta de lixo em um idioma como C. Também é possível fazer isso no assembly. Não facilita a programação. Programar e projetar especialmente em uma linguagem como C é definitivamente mais difícil do que em uma linguagem OO. Em C, você precisa mapear os conceitos para sua implementação; em uma linguagem OO, você não precisa executar essa etapa (pelo menos não para os conceitos OO).
fishinperto de 22/03/19

11
"[ponteiros de função] permitem ter implementações individuais de uma interface bem definida. Observe que isso não é uma programação orientada a objetos em uma linguagem não orientada a objetos. Isso está definindo uma interface e implementando-a." Desculpe, mas isso está completamente errado, porque é exatamente isso que é OOP. "Por exemplo, a subclasse não é usada aqui" A subclasse não é um recurso obrigatório do OOP. Observe, por exemplo, que o JavaScript é uma linguagem orientada a objetos que não possui subclassificação (ou, nesse caso, classes de todo ... Apenas objetos que contêm referências de função).
Jules

11
Para esclarecer meu último comentário, meu argumento é que o principal fator de distinção entre OOP (não necessariamente qualquer linguagem OO específica) e outros métodos é que no OOP definimos interfaces que operam abstratamente nos dados sem a necessidade de conhecer o formato desses dados. vinculando a implementação das interfaces aos próprios dados. Isso é o que é POO. O método de implementação é irrelevante, seja uma classe de estilo Java, um objeto JavaScript (efetivamente um mapa de nome a ser atribuído, que pode ser dados ou código) ou uma estrutura que contém ponteiros de função e um nulo * para os dados.
Jules

11
"Portanto, as conclusões são de que as linguagens orientadas a objetos provavelmente são úteis apenas para programadores iniciantes que não conseguem entender como o conceito é realmente implementado." ... E isso, francamente, é um insulto. Sei muito bem como esses conceitos são implementados. Eu já fiz bastante trabalho usando para ser proficiente, até. Até implementei um intérprete e um compilador para idiomas OO no passado. Mas como eu prefiro trabalhar em linguagens de nível superior com objetos de primeira classe, devo ser um programador iniciante com quem você prefere não trabalhar ?!
Jules

2

A razão para introduzir paradigmas de programação, incluindo métodos orientados a objetos, é facilitar a criação de programas mais sofisticados e poderosos. Na edição de agosto de 1981 da Byte Magazine, Daniel Ingalls , um dos principais criadores do Smalltalk, definiu "orientado a objetos" como envolvendo os seguintes recursos:

  • gerenciamento de armazenamento automático
  • capacidade de trocar mensagens
  • uma metáfora uniforme que se aplica a todas as operações da linguagem
  • nenhum componente depende das partes internas de outro componente (modularidade)
  • O programa define apenas o comportamento dos objetos, não sua representação (polimorfismo)
  • cada componente deve aparecer em apenas um lugar (fatoração)
  • o uso de uma máquina virtual independente de hardware
  • todo componente acessível ao usuário deve estar disponível para observação e controle (princípio reativo)
  • não deve haver controlador geral (sem sistema operacional)

Esses foram os princípios que Ingalls identificou como as principais considerações de design do SmallTalk-80, desenvolvido pela Xerox Parc Research. No artigo da revista acima mencionado, você pode ler uma descrição detalhada de cada um desses princípios e como eles contribuem para o paradigma orientado a objetos, de acordo com Ingalls.

Todos esses princípios podem ser aplicados usando qualquer linguagem completa de Turing, seja processual, linguagem assembly ou qualquer outra coisa. Estes são princípios de design, não uma especificação de linguagem. Uma linguagem orientada a objetos visa facilitar o uso desses princípios ao criar software.

Por exemplo, para adotar o primeiro dos princípios da Ingall (gerenciamento automático de armazenamento), qualquer pessoa pode escrever seu próprio sistema de gerenciamento automático de armazenamento em uma linguagem processual, mas seria muito trabalhoso fazê-lo. Ao usar uma linguagem como SmallTalk ou Java que possui gerenciamento de armazenamento automático embutido, o programador não precisa trabalhar tanto para gerenciar a memória. A desvantagem é que o programador obtém menos controle sobre o modo como a memória é usada. Portanto, há um benefício e uma desvantagem. A idéia de um paradigma de design como a programação orientada a objetos é que os benefícios do paradigma superam as desvantagens de pelo menos alguns programadores.


Penso que as mesmas regras se aplicariam no caso de idiomas específicos do domínio. Mesmas vantagens e desvantagens ... A única diferença é que as DSLs podem ser simplificadas o suficiente para que os usuários finais trabalhem, porque a 'linguagem' corresponde à sua compreensão do espaço do problema e nada mais está incluído.

0

Uma maneira de gerenciar a complexidade do software é separar completamente a estrutura das ações desejadas usando um idioma específico do domínio . Isso significa que o nível do código de programação é distinto do nível em que os resultados desejados são configurados - uma linguagem ou sistema completamente diferente. Quando isso é feito corretamente, o código convencional torna-se essencialmente uma biblioteca e o usuário ou outra pessoa que cria os resultados desejados conecta as coisas a uma linguagem de script ou ferramenta de design visual, como um gerador de relatórios.

Para funcionar, isso requer o estabelecimento de um limite estrito em torno de quais operações serão possíveis e como elas serão vinculadas (linguagem de script ou design visual, como uma ferramenta de construção de formulário). Os metadados são uma maneira importante de abstrair a configuração de tempo de execução dos detalhes de codificação, possibilitando que um sistema suporte uma ampla variedade de resultados desejados. Se os limites forem definidos e mantidos (não aceitando todas as solicitações de extensão que surgirem), você poderá ter um sistema robusto e duradouro que funcione para as pessoas, sem que elas precisem ser programadores para realizar o que desejam.

Martin Fowler escreveu um livro sobre isso, e a técnica é quase tão antiga quanto a própria programação. Você quase poderia dizer que todas as linguagens de programação são linguagens específicas do domínio e, portanto, a idéia é endêmica, esquecida por ser tão óbvia. Mas você ainda pode criar suas próprias ferramentas de script ou design visual para facilitar sua vida. Às vezes, generalizar um problema facilita muito a solução!


0

Esta é uma pergunta muito boa e considero que as respostas dadas aqui não fizeram justiça, por isso irei adiante e acrescentarei meus pensamentos.

O objetivo é - Gerenciar a complexidade do software . O objetivo não é "usar linguagem OO".

Não há razão para a introdução de um novo paradigma. É algo que aconteceu naturalmente quando a codificação se tornou mais madura. Faz mais sentido escrever código onde adicionamos um coach no final do trem (o trem sendo modelado usando uma lista vinculada) em vez de adicionar um novo nó ao final da lista vinculada.


Codificação em termos de entidades do mundo real é simplesmente a maneira mais óbvia e correcta para codificar quando são codificação sobre as entidades do mundo real.


Um computador pode trabalhar com a adição de um nó ao final da lista vinculada tão facilmente quanto com a adição de um coach extra ao final do trem. Mas para os seres humanos é mais fácil trabalhar com o trem e o treinador do que com a lista e os nós vinculados, embora quando formos um nível profundo, encontramos o trem sendo modelado por meio de uma lista vinculada.

Proteger ou criptografar os arquivos não pode alcançar o encapsulamento. O oposto da criptografia é descriptografia. O oposto do encapsulamento é Decapsulation, que significa decomposição de estruturas e classes em linguagens de programação para obter melhor desempenho. O desempenho obtido com a redução do tráfego de memória e a evitar verificações de regras OOP.

Portanto, você pode escrever um código que seja criptografado e bem encapsulado, porque esses dois são conceitos diferentes.

O encapsulamento ajuda a gerenciar a complexidade em virtude de estar próxima da realidade.

Portanto, programe em objetos porque é mais fácil para você codificar e é mais rápido para você e todos os outros entenderem.


0

A única coisa a lembrar é o seguinte:
OOP não é sobre recursos de linguagem; é sobre a maneira como você estrutura seu código .

OOP é uma maneira de pensar e projetar a arquitetura do seu código, e isso pode ser feito em praticamente qualquer idioma. Isso inclui especialmente aquelas linguagens de baixo nível e não OO, chamadas assembler e C. Você pode executar uma programação perfeitamente orientada a objetos no assembler, e o kernel Linux, escrito em C, é bastante orientado a objetos em muitos aspectos. .

Dito isso, os recursos de OO em um idioma reduzem bastante a quantidade de código padrão que você precisa escrever para alcançar os resultados desejados . Onde você precisa definir explicitamente uma tabela de função virtual e preenchê-la com os ponteiros de função apropriados em C, você simplesmente não faz nada em Java e está pronto. As linguagens OO simplesmente removem tudo o que habilita o cruft do código-fonte, escondendo-o por trás de abstrações agradáveis ​​no nível da linguagem (como classes, métodos, membros, classes base, chamadas implícitas de construtor / destruidor, etc.).

Portanto, não, não precisamos de idiomas OO para fazer OOP. Só que OOP é muito mais fácil de fazer com uma linguagem OO decente.


-1

A programação orientada a objetos é mais do que apenas módulos + encapsulamento. Como você diz, é possível usar módulos + encapsulamento em uma linguagem não-orientada a objetos (procedural). OOP envolve mais do que apenas isso: envolve objetos e métodos. Então, não, isso não captura OOP. Veja, por exemplo, https://en.wikipedia.org/wiki/Object-oriented_programming ou uma boa introdução a OOP de um livro didático.


Obrigado pela resposta. Você poderia recomendar um?
steakexchange

-2

O maior motivo é que, à medida que um programa se torna mais complexo, você precisa tornar invisíveis algumas partes dele, ou a complexidade do aplicativo e o número de funções farão o seu cérebro escorrer pelos ouvidos.

Vamos imaginar um sistema de 100 classes, cada uma com cerca de 20 operações que podem ser executadas nelas; isso é 2.000 funções. No entanto, desses, talvez apenas 500 sejam operações completas como 'Salvar' e 'Excluir', enquanto 1500 são funções internas que executam um pouco de manutenção ou têm alguma função de utilidade. Considerar;

// intentionally in a non-specific language!

setName(person, name) {
    nameParts = splitPersonName(name);
    person.firstName = nameParts[0];
    person.lastName = nameParts[1];
    person.modified = true;
}

splitPersonName(name) {
    var result = [];
    result.add(name.substring(0, name.indexOf(" ")));
    result.add(name.substring(name.indexOf(" ") + 1));
    return result;
}

Assim, SetNameé uma função que as pessoas deveriam estar desempenhando com uma pessoa, mas SplitPersonNameé uma função utilitária usada pela pessoa.

A programação procedural direta não faz distinção entre essas duas operações. Isso significa que seus 2.000 funcionais disputam sua atenção. No entanto, se pudéssemos marcar essas funções como 'disponíveis para todos que possuem um registro pessoal' e 'usadas apenas como uma função utilitária dentro do registro pessoal', nossa atenção agora é de 500 'disponíveis para todas as funções' e 15 'utilitários' funções para a turma que você está editando.

Isso é o que publice privatefazer;

public class Person {
    public void setName(...) {...}
    private string[] splitPersonName(...) { ...}
}

11
Não tenho certeza se você entendeu minha pergunta corretamente. Eu já estou ciente do encapsulamento e ocultação de dados como uma maneira de gerenciar a complexidade. Apenas acho que isso pode ser feito facilmente em linguagens procedurais, dividindo o programa em módulos que executam tarefas simples bem definidas, cujo funcionamento interno é especificado em fontes protegidas separadas. Então, por que OOP quando podemos fazer essas coisas em linguagens procedurais? Essa é a minha pergunta.
steakexchange

2
Acho que minha resposta é que, se você quiser fazer esse tipo de coisa, precisará escrever ferramentas especiais e construções de linguagem para fazê-lo (por exemplo, uma chamada especial 'include' para incluir um arquivo que pode não ser ser incluído em outro lugar). Depois de começar esse caminho, você começou a implementar uma linguagem orientada a objetos à sua maneira. Por exemplo, C ++ foi originalmente um pré-processador que produziu simples C , e eu suspeito que uma vez que você está implementando seu sistema, ele se parece muito com C ++ no topo da C.
user62575

3
@steakexchange Observe que o OOP foi desenvolvido em uma época em que muitas linguagens procedurais não tinham módulos como esse. Alguns nem chamariam essas linguagens de procedimentais. De fato, nada diz que uma linguagem processual não deva ser OO ou vice-versa. Cuidado com os rótulos - eles podem facilmente enganá-lo. Se sua linguagem processual suportar módulos que possuem campos e procedimentos públicos e privados, é bom para você :) A principal diferença entre "procedimento tradicional" e "OOP" é que o envio de chamadas é mais flexível no OOP - de fato, no OOP estrito, você nunca saiba qual código você chama.
21817 Luaan

2
@steakexchange Nas linguagens da família ML, os módulos funcionam muito bem e, em combinação com lambdas, oferecem todo o poder de qualquer linguagem OO (afinal, uma função é uma interface com um único método - não é exatamente o que é recomendado por "bom código" pessoal em OO?: P). Por várias razões, eles ainda são menos usados ​​que as linguagens mais procedurais como C ++ ou Java, mas têm seu apelo e muitas pessoas estão tentando educar as pessoas sobre como elas podem simplificar sua vida (com mais ou menos sucesso).
Luaan 20/03/19

C efetivamente tem essas coisas. Possui módulos (arquivos .c) com interfaces (arquivos .h) e pode ter métodos públicos (externos) e não públicos (externos) (funções). Você pode até ter polimorfismo pobre homem com matrizes de ponteiros de função, eu não estou dizendo que OO é fácil em C (ou talvez, sane), mas encapsulamento é muito fácil,
Nick Keighley
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.