JavaRush /Blogue Java /Random-PT /Programação orientada a objetos (tradução do artigo)
Exidnus
Nível 38
Санкт-Петербург

Programação orientada a objetos (tradução do artigo)

Publicado no grupo Random-PT
Do tradutor: Infelizmente, não tenho nenhuma experiência significativa em tradução do inglês, embora leia bastante em inglês. Mas descobriu-se que ler e traduzir são duas coisas diferentes. Além disso, infelizmente, não tenho experiência significativa em programação (recentemente criei uma aplicação web simples em Spring MVC e Hibernate). Portanto, a tradução ficou muito pior do que poderia ter sido. Tomei a liberdade de corrigir um pouco os exemplos de código fornecidos no artigo, pois eles não atendem às convenções de nomenclatura em Java. Talvez não valesse a pena traduzir os nomes de alguns padrões (tal tradução não proporciona muita compreensão), mas pensei que esse fosse o mal menor. Vale a pena mencionar separadamente sobre “alta coesão” como uma tradução de “alta coesão”. Eu concordo, não é a melhor tradução. Mas “conectividade forte” é “alto acoplamento” (outro conceito importante), e é pouco provável que “coerência” seja adequada aqui. Estou aberto a críticas e aceitarei com gratidão comentários sobre o artigo de qualquer forma. A programação orientada a objetos é um estilo de programação em que um programa é composto de componentes que correspondem a objetos do mundo real. Qualquer objeto real possui algumas propriedades (que podem ou não mudar com o tempo) e comportamento (que podem ou não mudar dependendo de outros). Por exemplo, um lápis é um objeto do mundo real que possui as seguintes propriedades:
  • É vermelho (isso não muda com o tempo).
  • Agora tem 10 centímetros de comprimento (isso pode mudar se o lápis estiver apontado).
E tem o seguinte comportamento:
  • Deixa marcas se usado corretamente.
  • O traço pode diferir dependendo da pressão (dependendo de fatores externos).
  • Seu comprimento diminui se for afiado (comportamento permanente).
Como neste exemplo, os objetos do mundo real podem ter muitas propriedades, mas ao escrever programas levamos em consideração apenas as propriedades necessárias. A programação orientada a objetos tem suas vantagens. Por exemplo, torna mais fácil estabelecer uma conexão entre um objeto do mundo real e um programa da maneira esperada. Isso realmente ajuda à medida que o aplicativo cresce e muitos objetos interagem entre si. Isso ajuda na distribuição de responsabilidades dentro do mundo objetivo, permitindo que você se concentre em pensar na aplicação. Outra característica importante associada à POO (Programação Orientada a Objetos) é a classificação de objetos. Como o mundo (real/virtual) está repleto de objetos, é difícil controlá-los individualmente. Precisamos de uma forma de classificar esses objetos que nos ajude a associar diferentes objetos e suas propriedades, como um lápis preto. Seria indistinguível (mesmo?) se usado no exemplo anterior, mas é um objeto diferente. Mas como ambos são lápis, pertencem à mesma classe “Lápis”. Já uma caneta, que é muito semelhante a um lápis, pertence a uma classe diferente. No entanto, caneta e lápis são “instrumentos de escrita”. A programação orientada a objetos tem os seguintes princípios:
Abstração
A abstração é definida como a qualidade da interação com ideias e não com eventos ou, em outras palavras, a liberdade de qualidades representacionais . Isto permite que os programadores se concentrem no que programar e não em como programar . A abstração pode ser pensada como um contrato através do qual fornecemos funcionalidade. Os detalhes da implementação podem ficar ocultos ao usar este conceito. Por exemplo, se precisarmos de uma classe que escreva, então devemos ter certeza de que ela possui um método “write” abstract class writer { write (); } . Projetamos uma classe de alto nível que é abstrata, ou seja, ela sabe de qual funcionalidade precisamos, mas como implementá-la está fora do escopo desta classe. Isso oferece muitos benefícios:
  • Divulgamos a informação mínima necessária a entidades externas, o que nos permite concentrar-nos na reflexão sobre o programa (isto permite um pensamento focado), evitar confusões e evitar fazer promessas não intencionais.
  • Deixamos espaço para melhorias futuras que não seriam possíveis se os detalhes da implementação fossem revelados.
Herança
"Herança" em inglês comum significa "adquirir e transmitir". Esta palavra existe em nossa cultura há muito tempo. Os ancestrais adquiriram terras com muito trabalho e as repassaram aos filhos, até a natureza favorece a herança. Todas as propriedades do corpo, como altura, cor da pele/olhos/cabelo, etc. dependem dos genes que herdamos de nossos pais. A herança evita reinventar a roda e acelera o progresso. É o mesmo em OOP. Criamos uma classe pai com algumas propriedades/comportamentos básicos. Todas as classes que herdam deste pai conterão as mesmas propriedades/comportamento de seu pai. No entanto, classes herdadas podem ganhar mais propriedades/comportamento ou alterar a implementação do comportamento. class WritingInstrument { colour; write() { } } class Pen (child of parent) { inkcolour; } No exemplo acima, a classe pai (WritingInstrument) possui uma propriedade “color” e um comportamento “write”. Quando a classe descendente (handle) é declarada, a propriedade "color" e o comportamento "write" não precisam ser declarados novamente. Eles estão presentes na classe “handle” devido à herança. No entanto, uma classe descendente pode declarar suas próprias propriedades/comportamento adicionais. Como podemos usar isso na prática? Nós, desenvolvedores, somos muito preguiçosos. Não queremos imprimir algo repetidamente. A existência de múltiplas cópias do mesmo código é desencorajada devido às seguintes considerações:
  • Quanto menos cópias de código, mais fácil será sua manutenção.
  • Se não houver muitas cópias do código, uma alteração em um local se tornará visível em todos os lugares.
  • Quanto menos código, menos erros.
  • Se um código for usado em muitos lugares, a generalização será alcançada.
  • Nós nos concentramos em escrever código.
  • Nós nos concentramos em testes.
A herança em Java é obtida usando as palavras-chave "extends" e "implements". class WritingInstrument { } class Pen extends WritingInstrument { }
Polimorfismo
A palavra “polimorfismo” vem de duas palavras: “Poly” , ou seja, “muitos” / “mais de um” “metamorfose” , ou seja, “forma” Literalmente, a palavra “polimorfismo” refere-se à capacidade dos objetos de se comportarem de maneiras diferentes dependendo das condições. Na programação, o polimorfismo pode ser implementado em vários lugares:
  • Aulas
  • Métodos
  • Operadores
Todos os itens acima podem se comportar de maneira diferente dependendo das condições, talvez do contexto, em que são usados. Isso é útil porque o cliente (o programador que usa suas bibliotecas) não precisa conhecer muitas sutilezas, e a funcionalidade desejada é implementada selecionando as informações necessárias no contexto. Class WritingObject { wrire() { // пишем, используя стандартные (по дефолту) цвета } } class Pencil extends WritingObject { write() { // пишем, используя серый цвет, написанный текст можно стереть } } class Pen extends WritingObject { write() { // пишем, используя голубой цвет, написанный текст нельзя стереть } } class Main { main() { WritingObject wr = new WritingObject(); wr.write(); // первый вызов WritingObject wr = new Pen(); wr.write(); // второй вызов WritingObject wr2 = new Pencil(); wr2.write(); // третий вызов } } O exemplo acima tem uma implementação padrão em WritingObject, que é estendida/substituída pelas classes derivadas pen e pen. O método write() é chamado três vezes na classe Main. Cada vez que uma implementação diferente é chamada, dependendo de qual objeto o método é chamado. Nesse caso, o método write() possui muitos tipos de comportamento porque é polimórfico.
Encapsulamento
O encapsulamento é definido como a coleta de dados/funcionalidades relacionadas em uma unidade. Isso ajuda a facilitar o acesso/modificação de dados. Por exemplo, se precisarmos imprimir todas as propriedades que um determinado usuário possui, temos as seguintes opções: printUserProperties(userName, userId, firstname, lastname, email, phone, … … ….) Criamos um método que pega todas as propriedades e as imprime uma após a outra. À medida que o número de elementos na lista aumenta, não será mais possível identificar os campos corretos e adicionar/remover um campo alterará a assinatura do método. Portanto, precisamos substituir todos os usuários deste método, mesmo que eles não necessitem dos campos adicionados recentemente. Para tornar o código mais legível e facilitar modificações futuras, encapsulamos propriedades em uma classe e a transformamos em um objeto coletivo.Um class User { userName userId firstname lastname email phone .. .. .. } printUserProperties(user) {} objeto é um pacote de software de variáveis ​​e métodos associados. Você pode representar objetos do mundo real usando objetos de programa. Você pode imaginar cães reais em um programa de animação ou uma bicicleta real como um objeto de software dentro de uma bicicleta ergométrica. Em OOP, uma classe é um modelo extensível (modelo de código de programa) para criar objetos, fornecendo-lhes um estado inicial (variáveis) e implementando comportamento (funções, métodos). A sigla SOLID foi cunhada por Michael Feather para os “cinco primeiros princípios” nomeados por Robert C. Martin no início dos anos 2000. O objetivo dos princípios, quando implementados em conjunto, é aumentar a probabilidade de o programador criar um sistema fácil de manter e estender. Os princípios SOLID são diretrizes no desenvolvimento de programas necessárias para remover código “podre” por meio de refatoração, e como resultado o código deve se tornar facilmente legível e extensível. Isso faz parte da estratégia de programação ágil e adaptativa.
Princípio de Responsabilidade Única
Na POO, o princípio da responsabilidade única afirma que cada classe deve ser responsável por uma parte da funcionalidade fornecida pelo programa, e que a responsabilidade deve ser completamente encapsulada por essa classe. Todas as suas funcionalidades devem estar intimamente relacionadas com esta responsabilidade.
Princípio Aberto/Fechado
Na OOP, o princípio aberto/fechado afirma que “entidades de software (classes, módulos, métodos, etc.) devem estar abertas à extensão, mas fechadas à mudança”. Em outras palavras, a entidade deve permitir que seu comportamento seja estendido sem alterar o código-fonte.
Princípio da Substituição de Liskov
A substituibilidade é um princípio em OOP. Afirma que se S em um programa de computador é um subtipo de T, então os objetos do tipo T devem ser tais que possam ser substituídos por objetos do tipo S (ou seja, objetos do tipo S podem ser substituídos por objetos do tipo T) sem alterar quaisquer programas de propriedades necessários (precisão, conclusão de tarefas, etc.).
Princípio de segregação de interface
O princípio da separação de interfaces afirma que o programador cliente não deve ser forçado a depender de métodos que não utiliza. Segundo este princípio, é necessário dividir interfaces grandes em interfaces menores e mais específicas para que o programador cliente conheça apenas os métodos que lhe interessam. O objetivo do princípio de desacoplamento de interface é manter o sistema desacoplado, o que tornará mais fácil refatorar, fazer alterações e reimplantar.
Princípio de Inversão de Dependência
Na POO, o princípio da inversão de dependência significa uma forma específica de desconexão dos módulos do programa. Seguindo este princípio, os relacionamentos de dependência padrão estabelecidos a partir de módulos de alto nível que formam a arquitetura do aplicativo (configuração de política) para módulos dependentes de baixo nível são invertidos (revertidos), de modo que os módulos de alto nível modificados se tornem independentes dos detalhes de implementação de módulos de baixo nível. Este princípio afirma:
  • Módulos de alto nível não devem depender de módulos de baixo nível. Ambos os tipos de módulos devem depender de abstrações.
  • As abstrações não devem depender de detalhes de implementação. Os detalhes devem depender de abstrações.
O princípio inverte a forma como as pessoas podem pensar sobre o design orientado a objetos, argumentando que objetos de alto e baixo nível devem depender das mesmas abstrações.

Princípios GRASP

Os General Responsibility Assignment Software Patterns (GRASP) fornecem diretrizes para atribuir responsabilidades a classes e objetos no design orientado a objetos.
Controlador
O padrão Controller atribui a responsabilidade de interagir com eventos do sistema a classes não GUI que representam todo o sistema ou cenário de caso de uso. Controlador:
  • Este é um objeto que não interage diretamente com o usuário e é responsável por receber e responder aos eventos do sistema.
  • Deve ser usado para lidar com todos os eventos do sistema de um (ou muitos casos de uso inter-relacionados).
  • É o primeiro objeto por trás da GUI que controla as operações do sistema.
  • Ele não precisa fazer o trabalho sozinho; sua tarefa é controlar o fluxo dos eventos.
O Criador
A tarefa da classe criadora é criar e iniciar objetos para uso posterior. Ele conhece os parâmetros de inicialização, bem como qual objeto será criado. Às vezes, a classe criadora cria objetos ativamente e os coloca no cache e fornece uma instância quando necessário.
Alta Coesão
A alta coesão é um padrão avaliativo cujo objetivo é preservar os objetos em tal estado que sejam destinados a realizar uma tarefa clara, sejam facilmente controlados e compreendidos. O acoplamento alto geralmente é usado para suportar o acoplamento baixo. Alta coerência significa que as responsabilidades de um determinado elemento estão claramente definidas (fortemente relacionadas e altamente focadas). Dividir um programa em classes e subsistemas é um exemplo de ações que aumentam a coesão das propriedades do sistema. O acoplamento fraco, por outro lado, é uma situação em que um elemento tem muitas tarefas não relacionadas. Elementos fracamente acoplados tendem a ser difíceis de entender, reutilizáveis, difíceis de manter e difíceis de alterar.
Indireção
O padrão Roundabout mantém o acoplamento fraco (e a capacidade de reutilização) entre dois elementos, atribuindo a responsabilidade pela interação entre eles a um objeto intermediário. Um exemplo é a introdução de um controlador para mediar entre os dados (modelo) e sua exibição (view) no padrão Model-View-Controller (MVC).
Especialista em Informação
Especialista em Informação (também Especialista ou Princípio do Especialista) é um princípio usado para determinar a quem delegar responsabilidades. As responsabilidades incluem métodos, campos calculados, etc. Ao utilizar este princípio na atribuição de responsabilidades, a abordagem principal é a seguinte sequência de ações: analisar a responsabilidade, identificar as informações necessárias para cumpri-la e, finalmente, estabelecer onde essas informações estão localizadas. Usar o princípio do Especialista em Informação resulta na atribuição de responsabilidade à classe que possui mais informações para executá-la.
Acoplamento baixo
O acoplamento fraco é um padrão de avaliação que especifica como atribuir responsabilidades: o acoplamento fraco entre classes, a alteração de uma deve ter impacto mínimo na outra, maximizando a reutilização.
Polimorfismo
De acordo com o polimorfismo, a variação do comportamento baseada no tipo é atribuída aos tipos para os quais essa variação ocorre. Isto é conseguido usando operações polimórficas.
Variações Protegidas
O padrão Protected Changes protege elementos de alterações em outros elementos (objetos, sistemas, subsistemas) envolvendo o foco de instabilidade em uma interface e usando polimorfismo para criar diferentes implementações dessa interface.
Fabricação Pura
A construção pura envolve uma classe que não representa um conceito no domínio do problema e é projetada especificamente para obter acoplamento fraco, alto acoplamento e, portanto, máximo potencial de reutilização (a solução oferecida pelo padrão Information Expert não atinge isso). Essa classe é geralmente chamada de “Serviço” no design orientado a domínio.

Crítica

A pesquisa de Potok et al.não mostrou diferenças significativas entre POO e abordagens procedimentais.
A comparação crítica de OOP com outras tecnologias, especialmente tecnologias relacionais, é difícil devido à falta de uma definição de OOP que seja rigorosa e amplamente aceita (Christopher J. Date)
Em comparação com outras linguagens (dialetos LISP, linguagens funcionais, etc.), as linguagens OOP não possuem uma vantagem única e impõem complexidade desnecessária. (Lawrence Krubner)
Acho a programação orientada a objetos tecnicamente frágil. Tenta decompor o mundo em partes em termos de interfaces que variam dentro de um único tipo. Para lidar com problemas reais, você precisa de álgebras multiclassificadas – famílias de interfaces que se estendem por vários tipos. Acho a programação orientada a objetos filosoficamente prejudicial à saúde. Afirma que tudo é um objeto. Mesmo que isto seja verdade, não é muito interessante: dizer que tudo é um objeto é não dizer absolutamente nada. (Alexandre Stepanov)
A popularidade da OOP entre as grandes empresas se deve a "grandes (e em constante mudança) grupos de programadores medíocres". A disciplina imposta pela OOP evita que o programador cause “muito dano”. (Paulo Graham)
A programação orientada a objetos coloca os substantivos em primeiro lugar. Por que tomar medidas tão extremas e colocar uma classe gramatical em um pedestal? Por que um conceito tem precedência sobre outro? É impossível para a POO tornar subitamente os verbos menos importantes para o nosso pensamento. É uma perspectiva estranhamente distorcida. (Steve Yegge)
Rick Hickey, o criador do Clojure, descreveu os sistemas de objetos como modelos extremamente simplificados do mundo real. Ele enfatizou a incapacidade da OOP de modelar o tempo corretamente, o que cria enormes problemas quando o multithreading se torna comum em programas. Eric S. Raymond, um programador Unix e defensor do software de código aberto, criticou a afirmação de que OOP é "A Solução Única" e escreveu que OOP incentiva programas multicamadas, o que dificulta a transparência. Como abordagem oposta, Raymond deu o exemplo do Unix e do C.

Ligações

Por Margaret Rouse @ WhatIs.com Wikipédia! ( versão russa ) herança é polimorfismo SOLID (Object Oriented Design) ( versão russa ) Princípio de Responsabilidade ÚnicaArgumentos contra OOPS ( versão russa ) O que é OOPS (sem exagero) Tradução: Varygin D.V.
Comentários
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION