<?xml version="1.0" encoding="UTF-8"?>
<rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/"
    xmlns:atom="http://www.w3.org/2005/Atom" xmlns:media="http://search.yahoo.com/mrss/" version="2.0">
    <channel>
        
        <title>
            <![CDATA[ Programação orientada a objetos - freeCodeCamp.org ]]>
        </title>
        <description>
            <![CDATA[ Aprenda a codificar - de graça. Tutoriais de programação em Python, JavaScript, Linux e muito mais. ]]>
        </description>
        <link>https://www.freecodecamp.org/portuguese/news/</link>
        <image>
            <url>https://cdn.freecodecamp.org/universal/favicons/favicon.png</url>
            <title>
                <![CDATA[ Programação orientada a objetos - freeCodeCamp.org ]]>
            </title>
            <link>https://www.freecodecamp.org/portuguese/news/</link>
        </image>
        <generator>Eleventy</generator>
        <lastBuildDate>Sat, 23 May 2026 08:28:36 +0000</lastBuildDate>
        <atom:link href="https://www.freecodecamp.org/portuguese/news/tag/programacao-orientada-a-objetos/rss.xml" rel="self" type="application/rss+xml" />
        <ttl>60</ttl>
        
            <item>
                <title>
                    <![CDATA[ Significado de OOP – o que é Programação Orientada a Objetos? ]]>
                </title>
                <description>
                    <![CDATA[ Na sociedade de hoje, impulsionada pela tecnologia, o conhecimento de programação de computadores está em alta demanda. Como desenvolvedor, você precisará conhecer várias linguagens de programação. Nas últimas décadas, muitas linguagens de programação ganharam popularidade. Você pode ver como as linguagens populares são classificadas neste gráfico de classificação em tempo ]]>
                </description>
                <link>https://www.freecodecamp.org/portuguese/news/significado-de-oop-o-que-e-programacao-orientada-a-objetos/</link>
                <guid isPermaLink="false">6684d63823266d03fc8b80c5</guid>
                
                    <category>
                        <![CDATA[ Programação orientada a objetos ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Kris Lagerström ]]>
                </dc:creator>
                <pubDate>Wed, 10 Jul 2024 21:00:00 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/portuguese/news/content/images/2024/07/OOP--1-.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <p data-test-label="translation-intro">
        <strong>Artigo original:</strong> <a href="https://www.freecodecamp.org/news/what-is-object-oriented-programming/" target="_blank" rel="noopener noreferrer" data-test-label="original-article-link">OOP Meaning – What is Object-Oriented Programming?</a>
      </p><p>Na sociedade de hoje, impulsionada pela tecnologia, o conhecimento de programação de computadores está em alta demanda. Como desenvolvedor, você precisará conhecer várias linguagens de programação.</p><p>Nas últimas décadas, muitas linguagens de programação ganharam popularidade. Você pode ver como as linguagens populares são classificadas neste gráfico de classificação em tempo real <a href="https://innovationgraph.github.com/global-metrics/programming-languages">aqui</a> (site em inglês).</p><p>Enquanto novas linguagens estão sendo criadas, as existentes estão sempre sendo atualizadas para ficarem cada vez melhores.</p><p>Embora a maioria das linguagens de programação tenham algumas semelhanças, cada uma tem regras e métodos específicos que a tornam única.</p><p>Um conceito que é comum entre muitas linguagens de programação é a <strong>Programação Orientada a Objetos</strong>.</p><p>Quando me deparei com esse termo pela primeira vez, foi um pouco confuso. Levei algum tempo para realmente entender sua importância na programação. Isso, porém, serviu também como uma oportunidade para aprender seus conceitos-chave e saber da importância do conceito para a carreira de um desenvolvedor e para ser capaz de resolver desafios.</p><p>Neste artigo, abordaremos a Programação Orientada a Objetos (OOP – do inglês <em>Object-Oriented Programming</em>) como um todo, sem depender de uma linguagem específica. Você aprenderá o que é, por que é tão popular como paradigma de programação, sua estrutura, como funciona, seus princípios e muito mais.</p><p>Vamos começar.</p><h1 id="o-que-a-programa-o-orientada-a-objetos">O que é a Programação Orientada a Objetos?</h1><p>Se você fizesse uma pesquisa rápida na internet sobre o que é programação orientada a objetos, descobriria que a OOP é definida como um paradigma de programação que se baseia no conceito de classes e objetos.</p><p>Agora, para um iniciante, isso pode ser um pouco confuso – mesmo assim, você não precisa se preocupar. Tentarei explicar da maneira mais simples possível, como na famosa frase: "Explique para mim como se eu tivesse 5 anos".</p><p>Aqui está uma breve visão geral do que você pode alcançar com a OOP: você pode usá-la para estruturar um programa em blocos de código simples e reutilizáveis (neste caso, geralmente chamados de classes), que você, então, usará para criar instâncias individuais dos objetos.</p><p>Então, vamos encontrar uma definição mais fácil de programação orientada a objetos e aprender mais sobre ela.</p><h2 id="explique-oop-como-se-eu-tivesse-5-anos">Explique OOP como se eu tivesse 5 anos</h2><p>A expressão "orientada a objetos" é uma combinação de dois termos, objeto e orientada.</p><p>O significado dicionarizado de objeto é "uma entidade que existe no mundo real", e orientada significa "interessada em um tipo particular de coisa ou entidade".</p><p>Em termos básicos, OOP é um padrão de programação que é construído em torno de objetos ou entidades. Por isso, ela é chamada de programação orientada a objetos.</p><p>Para entender melhor o conceito, vamos dar uma olhada em programas comumente usados: um bom exemplo para explicar isso seria o uso de uma impressora quando você está imprimindo um documento.</p><p>A primeira etapa é iniciar a ação clicando no comando de impressão ou usando atalhos de teclado. Em seguida, você precisa selecionar sua impressora. Depois, você esperará uma resposta informando se o documento foi impresso ou não.</p><p>Por trás do que não podemos ver, o comando que você clicou interage com um objeto (impressora) para realizar a tarefa de impressão.</p><p>Talvez você se pergunte, como exatamente a OOP se tornou tão popular?</p><h1 id="como-a-oop-se-tornou-popular">Como a OOP se tornou popular</h1><p>Os conceitos de OOP começaram a surgir na década de 1960 com uma linguagem de programação chamada <a href="https://pt.wikipedia.org/wiki/Simula">Simula</a>. Embora, naquela época, os desenvolvedores não abraçassem completamente os primeiros avanços nas linguagens OOP, as metodologias continuaram a evoluir.</p><p>Avançando para a década de 1980, um editorial escrito por David Robinson foi uma das primeiras introduções à OOP, já que muitos desenvolvedores não sabiam que ela existia.</p><p>Até então, linguagens como C++ e Eiffel se tornaram mais populares e comuns entre os programadores de computadores. O reconhecimento continuou a crescer durante a década de 1990 e, com a chegada do Java, a OOP atraiu um grande número de seguidores.</p><p>Em 2002, em conjunto com o lançamento do .NET Framework, a Microsoft introduziu uma nova linguagem OOP chamada C# – que é frequentemente descrita como a linguagem de programação mais poderosa.</p><p>É interessante que, gerações depois, o conceito de organizar seu código em objetos significativos que modelam as partes do seu problema continua a intrigar os programadores.</p><p>Muitas pessoas que não têm ideia de como um computador funciona acham o pensamento de programação orientada a objetos bastante natural. Em contraste, muitas pessoas que têm experiência com computadores inicialmente acham que há algo de estranho nos sistemas orientados a objetos.</p><h1 id="estrutura-da-oop">Estrutura da OOP</h1><figure class="kg-card kg-image-card"><img src="https://www.freecodecamp.org/portuguese/news/content/images/2024/07/OOP.png" class="kg-image" alt="OOP" srcset="https://www.freecodecamp.org/portuguese/news/content/images/size/w600/2024/07/OOP.png 600w, https://www.freecodecamp.org/portuguese/news/content/images/size/w1000/2024/07/OOP.png 1000w, https://www.freecodecamp.org/portuguese/news/content/images/size/w1600/2024/07/OOP.png 1600w, https://www.freecodecamp.org/portuguese/news/content/images/2024/07/OOP.png 1921w" sizes="(min-width: 720px) 720px" width="1921" height="1080" loading="lazy"></figure><p>Imagine que você está administrando uma loja de animais de estimação, com muitas raças diferentes, e que você precisa controlar os nomes, a idade, os dias de atendimento e outros detalhes comuns de manutenção. Como você projetaria um software reutilizável para lidar com isso?</p><p>Lembre-se de que temos muitas raças. Assim, escrever código para cada uma seria cansativo. Podemos, no entanto, agrupar informações relacionadas para que possamos produzir código mais curto e reutilizável.</p><p>É aí que os blocos de construção entram para nos ajudar a fazer isso usando <strong>Classes, Objetos, Métodos</strong> e <strong>Atributos</strong>.</p><p>Vamos mergulhar a fundo e entender exatamente o que são esses blocos de construção:</p><p><strong>Classes</strong> – são tipos de dados definidos pelo usuário que atuam como o modelo para objetos, atributos e métodos.</p><p><strong>Objetos</strong> – são instâncias de uma classe com dados especificamente definidos. Quando uma classe é definida inicialmente, a descrição é o único objeto que é definido.</p><p><strong>Métodos</strong> – são funções definidas dentro de uma classe que descrevem o comportamento de um objeto. Eles são úteis para a reutilização ou para manter a funcionalidade encapsulada dentro de um objeto por vez. A reutilização de código é um grande benefício ao depurar.</p><p><strong>Atributos</strong> – são definidos no modelo de classe e representam o estado de um objeto. Os objetos contêm dados armazenados no campo de atributo.</p><h1 id="princ-pios-da-oop">Princípios da OOP</h1><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://www.freecodecamp.org/portuguese/news/content/images/2024/07/Creative-Business-Template-Presentation--2-.png" class="kg-image" alt="Creative-Business-Template-Presentation--2-" srcset="https://www.freecodecamp.org/portuguese/news/content/images/size/w600/2024/07/Creative-Business-Template-Presentation--2-.png 600w, https://www.freecodecamp.org/portuguese/news/content/images/size/w1000/2024/07/Creative-Business-Template-Presentation--2-.png 1000w, https://www.freecodecamp.org/portuguese/news/content/images/size/w1600/2024/07/Creative-Business-Template-Presentation--2-.png 1600w, https://www.freecodecamp.org/portuguese/news/content/images/2024/07/Creative-Business-Template-Presentation--2-.png 1920w" sizes="(min-width: 720px) 720px" width="1920" height="1080" loading="lazy"><figcaption>Princípios da OOP – encapsulamento, abstração, herança e polimorfismo</figcaption></figure><p>Para que possamos saber como escrever um bom código OOP, precisamos entender os 4 pilares da OOP que devemos seguir:</p><ul><li>Encapsulamento</li><li>Abstração</li><li>Herança</li><li>Polimorfismo</li></ul><p>Vamos mergulhar a fundo e entender melhor o que exatamente cada um deles significa.</p><h2 id="encapsulamento">Encapsulamento</h2><p>Esse é o conceito que vincula os dados. As funções manipulam as informações e as mantêm seguras. Nenhum acesso direto é concedido às informações, caso elas estejam ocultas. Se você deseja obter acesso às informações, precisa interagir com o artigo responsável pelas informações.</p><p>Se você trabalha em uma empresa, é muito provável que tenha tido experiência com encapsulamento.</p><p>Pense em um departamento de recursos humanos. Os membros da equipe de recursos humanos encapsulam (escondem) os dados sobre os funcionários. Eles determinam como esses dados serão usados e manipulados. Qualquer solicitação de dados do trabalhador ou solicitação para atualizar as informações deve ser encaminhada por meio deles.</p><p>Ao encapsular dados, você torna as informações do seu sistema mais seguras e confiáveis. Você também pode monitorar como as informações estão sendo acessadas e quais operações estão sendo realizadas nelas. Isso torna a manutenção do programa mais fácil e simplifica o processo de depuração.</p><h2 id="abstra-o">Abstração</h2><p>Abstração se refere ao uso de classes simples para representar a complexidade. Basicamente, usamos a abstração para lidar com a complexidade, permitindo que o usuário veja apenas informações relevantes e úteis.</p><p>Um bom exemplo para explicar isso é dirigir um carro automático. Quando você tem um carro automático e deseja ir do ponto A ao ponto B, tudo o que precisa fazer é informar o destino e dar partida no carro. Então, ele o levará ao seu destino.</p><p>O que você não precisa saber é como o carro é feito, como ele recebe e segue as instruções corretamente, como o carro filtra diferentes opções para encontrar a melhor rota e assim por diante.</p><p>O mesmo conceito é aplicado ao construir aplicações em OOP. Você faz isso ocultando detalhes que o usuário não precisa ver. A abstração facilita e permite que você gerencie seus projetos em partes pequenas e gerenciáveis.</p><h2 id="heran-a">Herança</h2><p>A herança permite que as classes herdem recursos de outras classes. Como exemplo, você poderia classificar todos os gatos juntos como tendo certas características comuns, como ter quatro patas. Suas raças os classificam ainda mais em subgrupos com atributos comuns, como tamanho e cor.</p><p>Você usa a herança na OOP para classificar os objetos em seus programas de acordo com características e desempenho comuns. Isso torna o trabalho com os objetos e a programação mais fácil, pois permite que você tenha características gerais em um objeto pai e faça com que os objetos filhos herdem essas características.</p><p>Por exemplo, você definirá um objeto funcionário, que define todas as características gerais dos funcionários da sua empresa.</p><p>Você poderá, então, definir um objeto gerente que herda as características do objeto funcionário, mas também adiciona características exclusivas dos gerentes da sua empresa. O objeto gerente refletirá automaticamente quaisquer alterações na implementação do objeto funcionário.</p><h2 id="polimorfismo">Polimorfismo</h2><p>Esse é o poder de dois objetos diferentes responderem de um mesmo modo. O programa determinará qual uso é crítico para cada execução da coisa da classe pai, o que reduz a duplicação de código. Também permite que diferentes tipos de objetos interajam com a mesma interface.</p><h2 id="exemplos-de-linguagens-oop">Exemplos de linguagens OOP</h2><p>Tecnologia e linguagens de programação estão evoluindo o tempo todo. Vimos o surgimento de muitas linguagens sob a categoria OOP, mas a <strong>Simula</strong> é creditada como a primeira linguagem OOP.</p><p>Linguagens de programação que são consideradas OOP puras tratam tudo como objetos, enquanto as outras são projetadas principalmente com algum processo procedural.</p><p><em>Exemplos de linguagens OOP:</em></p><ul><li>Scala</li><li>Emerald</li><li>Ruby</li><li>JADE</li><li>Java</li><li>Python</li><li>C++</li><li>JavaScript</li><li>Visual Basic .NET</li><li>PHP</li></ul><p>Ainda existem várias outras, mas essas são as mais conhecidas.</p><h2 id="benef-cios-da-oop">Benefícios da OOP</h2><p>Durante as décadas de 1970 e 1980, linguagens de programação orientadas a procedimentos, como C e Pascal, eram amplamente usadas para desenvolver sistemas de software orientados a negócios. À medida que os programas executavam funcionalidades de negócios mais complexas e interagiam com outros sistemas, porém, as deficiências da metodologia de programação estrutural começaram a aparecer.</p><p>Devido a isso, muitos desenvolvedores de software recorreram a metodologias e linguagens de programação orientadas a objetos para resolver os problemas encontrados. Os benefícios de se usar essas linguagens incluíam:</p><p><strong>Reutilização de código</strong> – por meio da herança, você pode reutilizar o código. Isso significa que uma equipe não precisa escrever o mesmo código várias vezes.</p><p>Integração aprimorada com sistemas operacionais modernos.</p><p><strong>Produtividade aprimorada</strong> – os desenvolvedores podem criar programas com facilidade e rapidez por meio do uso de várias bibliotecas.</p><p>O polimorfismo permite que uma única função se adapte à classe em que é colocada.</p><p>É fácil de atualizar – e os programadores também podem implementar funcionalidades do sistema de modo independente.</p><p>Por meio do <strong>encapsulamento</strong>, os objetos podem ser autocontidos. Isso também torna a solução de problemas e a colaboração no desenvolvimento mais fáceis.</p><p>Por meio do uso de encapsulamento e abstração, o código complexo é ocultado, a manutenção do software é mais fácil e os protocolos da Internet são protegidos.</p><h2 id="conclus-o">Conclusão</h2><p>Hoje, a maioria das linguagens permitem que os desenvolvedores misturem paradigmas de programação. Isso geralmente ocorre porque eles serão usados para vários métodos de programação.</p><p>Veja o JavaScript, por exemplo – você pode usá-lo para programação OOP e funcional. Quando você está programando em JavaScript orientado a objetos, você precisa pensar cuidadosamente sobre a estrutura do programa e planejar no início da programação. Você pode fazer isso visualizando como poderá dividir as necessidades em classes simples e reutilizáveis que serão instâncias de modelo de objetos personalizados.</p><p>Os desenvolvedores que trabalham com OOP geralmente concordam que, em geral, usá-la permite melhores estruturas de dados e reutilização de código. Isso economiza tempo a longo prazo.</p> ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ Princípios de programação orientada a objetos em Java: Conceitos de POO para iniciantes ]]>
                </title>
                <description>
                    <![CDATA[ > A programação orientada à objetos oferece uma forma sustentável de escrever código espaguete. Ela permite que você escreva programas como se fosse uma colcha de retalhos. ― Paul Graham Princípios de programação orientada a objetos  A programação orientada a objetos é um paradigma de programação onde tudo é ]]>
                </description>
                <link>https://www.freecodecamp.org/portuguese/news/principios-de-programacao-orientada-a-objetos-em-java-conceitos-de-poo-para-iniciantes/</link>
                <guid isPermaLink="false">62c2ea08a3520206e79cfe3a</guid>
                
                    <category>
                        <![CDATA[ Programação orientada a objetos ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Cássio Leodegario ]]>
                </dc:creator>
                <pubDate>Thu, 15 Sep 2022 21:00:00 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/portuguese/news/content/images/2022/09/Love-Home.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <p data-test-label="translation-intro">
        <strong>Artigo original:</strong> <a href="https://www.freecodecamp.org/news/java-object-oriented-programming-system-principles-oops-concepts-for-beginners/" target="_blank" rel="noopener noreferrer" data-test-label="original-article-link">Object-Oriented Programming Principles  in Java:  OOP Concepts for Beginners</a>
      </p><blockquote><em>A programação orientada à objetos<em> </em>oferece uma forma sustentável de escrever código espaguete<em>. </em>Ela permite que você escreva programas como se fosse uma colcha de retalhos<em>.</em></em><br><em><em>― Paul Graham</em></em></blockquote><h2 id="princ-pios-de-programa-o-orientada-a-objetos"><strong>Princípios de programação orientada a objetos </strong></h2><p>A programação orientada a objetos é um paradigma de programação onde tudo é representado como um objeto.</p><p>Objetos passam mensagens uns para os outros. Cada objeto decide o que fazer com uma mensagem recebida. A POO (em inglês, <em>OOP</em> - <em>Object Oriented Programming</em>) foca nos estados e comportamentos de cada objeto.</p><h3 id="o-que-s-o-objetos"><strong>O que são objetos?</strong></h3><p><strong>Um objeto é uma entidade que possui estados e comportamentos.</strong></p><p>Por exemplo, cão, gato e veículo. Para ilustrar, um cão possui estados como idade, cor, nome e comportamentos como comer, dormir e correr.</p><p>Os estados nos dizem como o objeto se parece ou quais propriedades ele possui.</p><p>O comportamento nos diz o que o objeto faz.</p><p>Podemos representar um cão do mundo real em um programa como um objeto de software definindo seus estados e comportamentos.</p><p>Objetos de software são uma representação de um objeto do mundo real. É alocado espaço em memória sempre que um objeto lógico é criado.</p><p>Um objeto pode também ser referenciado como uma instância de uma classe. Instanciar uma classe significa a mesma coisa que criar um objeto.</p><p>Algo importante de se lembrar quando estamos criando um objeto é: o tipo de referência deve ser <strong>do mesmo tipo</strong> ou um <strong>supertipo</strong> do tipo do objeto. Veremos o que é um tipo de referência mais a frente neste artigo.</p><h3 id="o-que-s-o-classes"><strong>O que são classes?</strong></h3><p><strong>Uma classe é um <em>template </em>- algo como a "planta" de uma construção - a partir do qual os objetos são criados<strong>.</strong></strong></p><p>Imagine uma classe como um cortador de biscoitos e os objetos como os próprios biscoitos.</p><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://www.freecodecamp.org/portuguese/news/content/images/2022/09/cookie-cutter.jpg" class="kg-image" alt="cookie-cutter" srcset="https://www.freecodecamp.org/portuguese/news/content/images/size/w600/2022/09/cookie-cutter.jpg 600w, https://www.freecodecamp.org/portuguese/news/content/images/2022/09/cookie-cutter.jpg 910w" sizes="(min-width: 720px) 720px" width="910" height="607" loading="lazy"><figcaption>Figura 1: ilustra a relação entre classe e objeto por meio do cortador de biscoitos e dos biscoitos em si. <a href="https://www.piqsels.com/en/public-domain-photo-sswme" rel="noopener">Fonte da imagem</a>.</figcaption></figure><p>Classes definem estados como variáveis de instância e comportamentos como métodos de instância.</p><p>Variáveis de instância também são conhecidas como "variáveis membro".</p><p>Classes não consomem espaço em memória.</p><p>Para dar uma ideia sobre classes e objetos, vamos criar uma classe Cat (Gato) que representa estados e comportamentos de um gato no mundo real.</p><pre><code class="language-java">public class Cat {
    /*
    Variáveis de instancia: Estados do gato
     */
    String name;
    int age;
    String color;
    String breed;

    /*
    Métodos de instancia: Comportamento do gato
     */
    void sleep(){
        System.out.println("Dormindo");
    }
    void play(){
        System.out.println("Brincando");
    }
    void feed(){
        System.out.println("Comendo");
    }

}</code></pre><p>Agora que definimos um <em>template </em>de gatos, vamos dizer que temos dois gatos, chamados Thor e Rambo.</p><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://www.freecodecamp.org/portuguese/news/content/images/2022/09/Russian-Blue_01.jpg" class="kg-image" alt="Russian-Blue_01" srcset="https://www.freecodecamp.org/portuguese/news/content/images/size/w600/2022/09/Russian-Blue_01.jpg 600w, https://www.freecodecamp.org/portuguese/news/content/images/2022/09/Russian-Blue_01.jpg 970w" sizes="(min-width: 720px) 720px" width="970" height="505" loading="lazy"><figcaption>Figura 2: Thor está dormindo. <a href="https://www.petfinder.com/cat-breeds/collections/cutest-cat-breeds/" rel="noopener">Fonte da imagem</a></figcaption></figure><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://www.freecodecamp.org/portuguese/news/content/images/2022/09/Maine-Coon_02.jpg" class="kg-image" alt="Maine-Coon_02" srcset="https://www.freecodecamp.org/portuguese/news/content/images/size/w600/2022/09/Maine-Coon_02.jpg 600w, https://www.freecodecamp.org/portuguese/news/content/images/2022/09/Maine-Coon_02.jpg 970w" sizes="(min-width: 720px) 720px" width="970" height="505" loading="lazy"><figcaption>Figura 3: Rambo está brincando. <a href="https://www.petfinder.com/cat-breeds/collections/cutest-cat-breeds/" rel="noopener">Fonte da imagem</a></figcaption></figure><p>Como podemos defini-los em nossos programas?</p><p>Primeiro, precisamos criar dois objetos da classe Cat.</p><pre><code class="language-java">public class Main {
    public static void main(String[] args) {
       Cat thor = new Cat();
       Cat rambo = new Cat();
    }
}</code></pre><p>Agora, vamos definir seus estados e comportamentos.</p><pre><code class="language-java">public class Main {

    public static void main(String[] args) {
       /*
       Criando os objetos
        */
       Cat thor = new Cat();
       Cat rambo = new Cat();

       /*
       Definindo o gato Thor
        */
       thor.name = "Thor";
       thor.age = 3;
       thor.breed = "Azul russo";
       thor.color = "Marrom";

       thor.sleep();

       /*
       Definindo o gato Rambo
        */
       rambo.name = "Rambo";
       rambo.age = 4;
       rambo.breed = "Maine Coon";
       rambo.color = "Marrom";

       rambo.play();
    }

}</code></pre><p>Como nos exemplos de código acima, podemos definir nossas classes, instanciá-las (criar objetos) e especificar os estados e comportamentos para esses objetos.</p><p>Até aqui já cobrimos o básico de orientação a objetos. Vamos avançar para os princípios da orientação a objetos.</p><h2 id="princ-pios-da-programa-o-orientada-a-objetos"><strong>Princípios da programação orientada a objetos</strong></h2><p>Esses são os quatro princípios fundamentais do paradigma de programação orientada a objetos. Entendê-los é essencial para se tornar um programador de sucesso.</p><ol><li>Encapsulamento</li><li>Herança</li><li>Abstração</li><li>Polimorfismo</li></ol><p>Agora, vamos dar uma olhada neles com mais detalhes.</p><h2 id="encapsulamento"><strong>Encapsulamento</strong></h2><p><strong>Encapsulamento é um processo de envolver dados e código em uma única unidade<strong>.</strong></strong></p><p>É como uma capsula que possui uma mistura de diversos medicamentos, é uma técnica que ajuda a manter as variáveis de instância protegidas.</p><p>Essa proteção pode ser conquistada utilizando o modificador de acesso <code>private</code>, que indica que a variável ou dado não pode ser acessado de fora da classe. Para acessar estados privados de modo seguro, temos que providenciar métodos <em>getters </em>e <em>setters </em>públicos (em Java, esses métodos devem seguir os padrões de nomenclatura "JavaBeans").</p><p>Digamos que existe uma loja de discos que vende álbuns de músicas de diferentes artistas e um estoque para o gerenciamento.</p><figure class="kg-card kg-image-card kg-width-wide kg-card-hascaption"><img src="https://www.freecodecamp.org/portuguese/news/content/images/2022/09/classDiagramWithoutEncapsulation.png" class="kg-image" alt="classDiagramWithoutEncapsulation" srcset="https://www.freecodecamp.org/portuguese/news/content/images/size/w600/2022/09/classDiagramWithoutEncapsulation.png 600w, https://www.freecodecamp.org/portuguese/news/content/images/size/w1000/2022/09/classDiagramWithoutEncapsulation.png 1000w, https://www.freecodecamp.org/portuguese/news/content/images/2022/09/classDiagramWithoutEncapsulation.png 1331w" sizes="(min-width: 1200px) 1200px" width="1331" height="291" loading="lazy"><figcaption>Figura 4: diagrama de classes sem encapsulamento</figcaption></figure><p>Se você observar a figura 4, a classe <code>StockKeeper</code> pode acessar os estados da classe <code>Album</code> diretamente, já que os atributos da classe <code>Album</code> estão definidos como <code>public</code> (sinal de +).</p><p>Se o gerenciador de estoque criar um álbum e definir seus estados como negativos, ele pode acabar fazendo isso mesmo que sem intenção.</p><p>Para ilustrar, vamos ver um exemplo de um programa em Java que explica o diagrama e a afirmação acima.</p><p>Classe Album:</p><pre><code class="language-java">public class Album {
    public String name;
    public String artist;
    public double price;
    public int numberOfCopies;
    public void sellCopies(){
        if(numberOfCopies &gt; 0){
            numberOfCopies--;
            System.out.println("Um album foi vendido!");
        }
        else{
            System.out.println("Não há albuns disponíveis!");
        }
    }
    public void orderCopies(int num){
        numberOfCopies += num;
    }
}</code></pre><p>Classe StockKeeper:</p><pre><code class="language-java">public class StockKeeper {
    public String name;
    public StockKeeper(String name){
        this.name = name;
    }
    public void manageAlbum(Album album, String name, String artist, double price, int numberOfCopies){
      /*
       Definindo os estados e comportamentos para album
       */
        album.name = name;
        album.artist = artist;
        album.price = price;
        album.numberOfCopies = numberOfCopies;

       /*
       Imprimindo os detalhes do album
        */
        System.out.println("Album gerenciado por :"+ this.name);
        System.out.println("Detalhes do album::::::::::");
        System.out.println("Nome do album: " + album.name);
        System.out.println("Artista do Album : " + album.artist);
        System.out.println("Preço do Album : " + album.price);
        System.out.println("Número de cópias do album : " + album.numberOfCopies);
    }
}</code></pre><p>Classe Main:</p><pre><code class="language-java">public class Main {
    public static void main(String[] args) {
       StockKeeper johnDoe = new StockKeeper("John Doe");
       /*
       O gerenciador de estoque cria um album e atribui valores negativos para o preço e o numero de cópias disponíveis
        */
       johnDoe.manageAlbum(new Album(), "Slippery When Wet", "Bon Jovi", -1000.00, -50);
    }
}</code></pre><p>Saída:</p><pre><code class="language-java">Album gerenciado por :John Doe
Detalhes do album::::::::::
Nome do album : Slippery When Wet
Artista do Album : Bon Jovi
Preço do Album :  -1000.0
Número de cópias do album : -50</code></pre><p>O preço do álbum e número de cópias não podem ser valores negativos. Como podemos evitar essa situação? Aqui é onde usamos o encapsulamento.</p><figure class="kg-card kg-image-card kg-width-wide kg-card-hascaption"><img src="https://www.freecodecamp.org/portuguese/news/content/images/2022/09/classDiagramWithEncapsulation-1.png" class="kg-image" alt="classDiagramWithEncapsulation-1" srcset="https://www.freecodecamp.org/portuguese/news/content/images/size/w600/2022/09/classDiagramWithEncapsulation-1.png 600w, https://www.freecodecamp.org/portuguese/news/content/images/size/w1000/2022/09/classDiagramWithEncapsulation-1.png 1000w, https://www.freecodecamp.org/portuguese/news/content/images/2022/09/classDiagramWithEncapsulation-1.png 1331w" sizes="(min-width: 1200px) 1200px" width="1331" height="291" loading="lazy"><figcaption>Figura 5: diagrama de classes com encapsulamento</figcaption></figure><p>Neste cenário, podemos impedir o gerenciador de estoque de atribuir valores negativos. Se ele tentar atribuir valores negativos para o preço e o número de cópias do álbum, definiremos 0.0 como o valor e 0 como o número de cópias.</p><p>Classe Album:</p><pre><code class="language-java">public class Album {
    private String name;
    private String artist;
    private double price;
    private int numberOfCopies;
    public void sellCopies(){
        if(numberOfCopies &gt; 0){
            numberOfCopies--;
            System.out.println("Um álbum foi vendido!");
        }
        else{
            System.out.println("Nenhum álbum disponível!");
        }
    }
    public void orderCopies(int num){
        numberOfCopies += num;
    }
   public String getName() {
      return name;
   }
   public void setName(String name) {
      this.name = name;
   }
   public String getArtist() {
      return artist;
   }
   public void setArtist(String artist) {
      this.artist = artist;
   }
   public double getPrice() {
      return price;
   }
   public void setPrice(double price) {
      if(price &gt; 0) {
         this.price = price;          
      }
      else {
         this.price = 0.0;
      }
   }
   public int getNumberOfCopies() {
      return numberOfCopies;
   }
   public void setNumberOfCopies(int numberOfCopies) {
      if(numberOfCopies &gt; 0) {
         this.numberOfCopies = numberOfCopies;        
      }
      else {
         this.numberOfCopies = 0;
      }
   }
}</code></pre><p>Classe StockKeeper:</p><pre><code class="language-java">public class StockKeeper {
    private String name;
    StockKeeper(String name){
        setName(name);
    }
    public void manageAlbum(Album album, String name, String artist, double price, int numberOfCopies){
         /*
          Definindo estados e comportamentos para o album
          */
        album.setName(name);
        album.setArtist(artist);
        album.setPrice(price);
        album.setNumberOfCopies(numberOfCopies);
          /*
          Imprimindo os detalhes do album
           */
        System.out.println("Album gerenciado por :"+ getName());
        System.out.println("Detalhes do album::::::::::");
        System.out.println("Nome do album : " + album.getName());
        System.out.println("Artista do Album : " + album.getArtist());
        System.out.println("Preço do Album : " + album.getPrice());
        System.out.println("Número de cópias do album : " + album.getNumberOfCopies());
    }
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
}</code></pre><p>Classe Main:</p><pre><code class="language-java">public class Main {
    public static void main(String[] args) {
       StockKeeper johnDoe = new StockKeeper("John Doe");
       /*
       Gerenciador de estoque cria um album e atribui valores negativos para o preço e o número de cópias disponíveis do album
        */
       johnDoe.manageAlbum(new Album(), "Slippery When Wet", "Bon Jovi", -1000.00, -50);
    }
}</code></pre><p>Saída:</p><pre><code class="language-java">Album gerenciado por :John Doe
Detalhes do album::::::::::
Nome do album : Slippery When Wet
Artista do Album : Bon Jovi
Preço do Album : 0.0
Número de cópias do album : 0</code></pre><p>Com o encapsulamento, impedimos nosso gerenciador de estoque de definir valores negativos, o que significa que temos o controle sobre as informações.</p><h3 id="vantagens-do-encapsulamento-em-java"><strong>Vantagens do encapsulamento em Java</strong></h3><ol><li>Podemos fazer uma classe <strong>somente leitura </strong>ou<strong> somente escrita.</strong> Para uma classe somente leitura, temos que informar apenas os métodos <em>getters</em>. Para uma classe somente escrita, devemos informar apenas os métodos <em>setters</em>.</li><li>Controle sobre os dados: podemos controlar os dados adicionando lógica nos métodos <em>setters</em>, assim como fizemos para evitar que o gerenciador de estoques definisse valores negativos nos exemplos acima.</li><li>Proteção dos dados: outras classes não podem acessar membros privados de uma classe diretamente.</li></ol><h2 id="heran-a"><strong>Herança</strong></h2><p>Consideremos que a loja de discos que falamos anteriormente também venda filmes em Blu-ray.</p><figure class="kg-card kg-image-card kg-width-wide kg-card-hascaption"><img src="https://www.freecodecamp.org/portuguese/news/content/images/2022/09/classDiagramForMovie.png" class="kg-image" alt="classDiagramForMovie" srcset="https://www.freecodecamp.org/portuguese/news/content/images/size/w600/2022/09/classDiagramForMovie.png 600w, https://www.freecodecamp.org/portuguese/news/content/images/size/w1000/2022/09/classDiagramForMovie.png 1000w, https://www.freecodecamp.org/portuguese/news/content/images/2022/09/classDiagramForMovie.png 1351w" sizes="(min-width: 1200px) 1200px" width="1351" height="291" loading="lazy"><figcaption>Figura 6: diagrama de classes para Movie (filme) e StockKeeper (gerenciador de estoque)</figcaption></figure><p>Como você pode ver no diagrama acima, existem muitos estados e comportamentos em comum (código duplicado) entre <code>Album</code> e <code>Movie</code>.</p><p>Quando for transformar esse diagrama de classes em código, você vai reescrever/copiar todo o código novamente para <code>Movie</code>? Caso você faça isso, você estará se repetindo. Como você pode evitar a duplicação de código?</p><p>Aqui é onde usamos a herança.</p><p><strong>Herança é um mecanismo onde um objeto recebe todos os comportamentos e estados de um objeto pai.</strong></p><p>A herança utiliza um relacionamento de pais e filhos (relacionamento "É um" ).</p><h3 id="ent-o-o-que-exatamente-herdado"><strong>Então o que exatamente é herdado?</strong></h3><p><strong>Visibilidade/modificadores de acesso </strong>impacta o que pode ser herdado de uma classe para a outra.</p><p>Em Java, como <strong>regra fundamental</strong>,<strong> </strong>tornamos as varáveis de instância <code>private</code> e os métodos de instância <code>public</code>.</p><p>Neste caso, certamente podemos dizer que o seguinte será herdado:</p><ol><li>métodos públicos de instância.</li><li>variáveis de instância privadas (que podem ser acessadas apenas por meio de métodos <em>getters </em>e <em>setters </em>públicos) .</li></ol><h3 id="tipos-de-heran-a-no-java"><strong>Tipos de herança no Java</strong></h3><p>Existem cinco tipos diferentes de herança no Java. Elas são: &nbsp;simples, multinível, hierárquica, múltipla e híbrida.</p><p>Classes permitem heranças simples, multinível e hierárquicas. Interfaces permitem heranças múltiplas e híbridas.</p><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://www.freecodecamp.org/portuguese/news/content/images/2022/09/InheritanceTypes.jpg" class="kg-image" alt="InheritanceTypes" srcset="https://www.freecodecamp.org/portuguese/news/content/images/size/w600/2022/09/InheritanceTypes.jpg 600w, https://www.freecodecamp.org/portuguese/news/content/images/2022/09/InheritanceTypes.jpg 721w" sizes="(min-width: 720px) 720px" width="721" height="681" loading="lazy"><figcaption>Figura 7: tipos de herança no Java</figcaption></figure><p>Uma classe pode estender apenas uma classe. Entretanto, não há limite para a implementação de interfaces. Uma interface pode estender mais de uma interface.</p><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://www.freecodecamp.org/portuguese/news/content/images/2022/09/inheritanceKeywords.jpg" class="kg-image" alt="inheritanceKeywords" width="481" height="281" loading="lazy"><figcaption>Figura 8: palavras-chaves para herança no Java</figcaption></figure><h3 id="relacionamentos"><strong>Relacionamentos</strong></h3><p><strong><strong>I. </strong>Relacionamento É UM</strong></p><p>Um relacionamento É UM refere-se à herança ou implementação.</p><h4 id="a-generaliza-o"><strong><strong>a. </strong>Generalização</strong></h4><p>Generalização usa um relacionamento É UM de uma classe especializada para uma classe generalizada.</p><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://www.freecodecamp.org/portuguese/news/content/images/2022/09/generalization.jpg" class="kg-image" alt="generalization" width="121" height="221" loading="lazy"><figcaption>Figura 9: diagrama de generalização (recursos especiais para recursos gerais)</figcaption></figure><h4 id="ii-relacionamento-tem-um"><strong><strong>II. </strong>Relacionamento TEM UM</strong></h4><p>Uma instância de uma classe TEM UMA referência para uma instância de outra classe.</p><h4 id="a-agrega-o"><strong><strong>a. </strong>Agregação</strong></h4><p>Neste relacionamento, a existência de uma classe A e B não são dependentes umas das outras.</p><p>Para essa parte de agregação, vamos ver um exemplo da classe <code>Student</code> e da classe <code>ContactInfo</code>.</p><pre><code class="language-java">class ContactInfo {
    private String homeAddress;
    private String emailAddress;
    private int telephoneNumber; //12025550156
}
public class Student {
    private String name;
    private int age;
    private int grade;
    private ContactInfo contactInfo;//Student TEM UM ContactInfo
    public void study() {
        System.out.println("Study");
    }
}</code></pre><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://www.freecodecamp.org/portuguese/news/content/images/2022/09/aggregation-1.png" class="kg-image" alt="aggregation-1" width="531" height="171" loading="lazy"><figcaption>Figura 10: o diagrama de classes mostra um relacionamento de generalização</figcaption></figure><p><code>Student</code> (aluno) TEM UMA <code>ContactInfo</code> (informação de contato). <code>ContactInfo</code> pode ser usado em outros lugares – por exemplo, uma classe <code>Employee</code> (funcionário) de um companhia também poderia utilizar a classe <code>ContactInfo</code>. Assim, <code>Student</code> pode existir sem <code>ContactInfo</code> e <code>ContactInfo</code> pode existir sem <code>Student</code>. Este tipo de relacionamento é conhecido como agregação.</p><h4 id="b-composi-o"><strong><strong>b. </strong>Composição</strong></h4><p>Neste relacionamento, a classe B não pode existir sem uma classe A – mas a classe A <strong>pode</strong> existir sem a classe B.</p><p>Para dar uma ideia sobre composição, vamos ver esse exemplo da classe <code>Student</code> e a classe <code>StudentId</code>.</p><pre><code class="language-java">class StudentId {
    private String idNumber;//A-123456789
    private String bloodGroup;
    private String accountNumber;
}
public class Student {
    private String name;
    private int age;
    private int grade;
    private StudentId studentId;//Student TEM UM StudentId
    public void study() {
        System.out.println("Study");
    }
}</code></pre><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://www.freecodecamp.org/portuguese/news/content/images/2022/09/composition--1-.png" class="kg-image" alt="composition--1-" width="531" height="171" loading="lazy"><figcaption>Figura 11: diagrama de classes mostra o relacionamento de composição</figcaption></figure><p><code>Student</code> TEM UM <code>StudentId</code>. <code>Student</code> pode existir sem <code>StudentId</code>, mas <code>StudentId</code> não pode existir sem <code>Student</code>. Esse tipo de relacionamento é conhecido como composição.</p><p>Agora, vamos voltar para nosso exemplo da loja de discos que discutimos acima.</p><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://www.freecodecamp.org/portuguese/news/content/images/2022/09/classDiagramWithInheritance.png" class="kg-image" alt="classDiagramWithInheritance" srcset="https://www.freecodecamp.org/portuguese/news/content/images/size/w600/2022/09/classDiagramWithInheritance.png 600w, https://www.freecodecamp.org/portuguese/news/content/images/2022/09/classDiagramWithInheritance.png 861w" sizes="(min-width: 720px) 720px" width="861" height="761" loading="lazy"><figcaption>Figura 12: diagrama de classes com herança</figcaption></figure><p>Podemos implementar esse diagrama em Java para evitar duplicação de código.</p><h4 id="vantagens-de-se-usar-heran-a"><strong>Vantagens de se usar herança</strong></h4><ol><li>Reaproveitamento de código: as classes filhas herdam todos os membros de instância da classe pai.</li><li>Você tem mais flexibilidade de mudar o código: mudar o código em um lugar é o suficiente.</li><li>Você pode usar polimorfismo: a sobrescrita de métodos requer um relacionamento É UM.</li></ol><h2 id="abstra-o"><strong>Abstração</strong></h2><p><strong>Abstração é o processo de esconder os detalhes de implementação e exibir apenas as funcionalidades para o usuário<strong>.</strong></strong></p><p>Um exemplo comum de abstração é o acelerador do carro: pisando mais forte, você aumenta a velocidade. Os motoristas, no entanto, não sabem como essa ação altera a velocidade – eles não precisam saber.</p><p>Tecnicamente, abstrato significa algo incompleto ou a ser finalizado no futuro.</p><p>Em Java, podemos obter abstração de duas maneiras: classes abstratas (0% a 100%) e interfaces (100%).</p><p>A palavra-chave <code>abstract</code> pode ser aplicada à classes e métodos. <code>abstract</code> e <code>final</code> ou <code>static</code> nunca podem estar juntas.</p><h4 id="i-classes-abstratas"><strong><strong>I. </strong>Classes abstratas</strong></h4><p>Uma classe é abstrata quando ela contém a palavra reservada <code>abstract</code>.</p><p>Classes abstratas não podem ser instanciadas &nbsp;(não é possível criar objetos de classes abstratas). Elas podem ter construtores, métodos estáticos e métodos finais.</p><h4 id="ii-m-todos-abstratos"><strong><strong>II. </strong>Métodos abstratos</strong></h4><p>Um método é abstrato quando ele contém a palavra chave <code>abstract</code>.</p><p>Um método abstrato não possui implementação (não possui um corpo e termina com ponto e virgula). Métodos abstratos não devem ser marcados como <code>private</code>.</p><h4 id="iii-classes-abstratas-e-m-todos-abstratos"><strong><strong>III. </strong>Classes a<strong>bstra</strong>tas<strong> </strong>e métodos a<strong>bstra</strong>tos</strong></h4><ul><li>Se pelo menos um método for abstrato dentro de uma classe, então toda a classe deve ser abstrata.</li><li>É possível ter uma classe abstrata sem nenhum método abstrato.</li><li>Podemos ter qualquer quantidade de métodos abstratos e não abstratos ao mesmo tempo na mesma classe.</li><li>A primeira classe concreta que herde de uma classe abstrata deve prover implementação para <strong>todos</strong> os métodos abstratos.</li><li>Caso a subclasse não implemente os métodos abstratos da superclasse, ela deve também ser marcada como abstrata.</li></ul><p>Em um cenário real, a implementação vai ser feita por alguém desconhecido ao usuário final. Usuários não conhecem a classe de implementação nem os detalhes da implementação.</p><p>Vamos considerar um exemplo de uso do conceito de classes abstratas.</p><pre><code class="language-java">abstract class Shape {
    public abstract void draw();
}
class Circle extends Shape{
    public void draw() {
        System.out.println("Círculo!");
    }
}
public class Test {
    public static void main(String[] args) {
        Shape circle = new Circle();
        circle.draw();
    }
}</code></pre><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://www.freecodecamp.org/portuguese/news/content/images/2022/09/abstraction.png" class="kg-image" alt="abstraction" width="211" height="331" loading="lazy"><figcaption>Figura 13: diagrama de classes que mostra o relacionamento entre uma classe abstrata (Shape - ou forma em português) e uma classe concreta (Circle - ou círculo, em português)</figcaption></figure><h4 id="quando-vamos-querer-marcar-uma-classe-como-abstrata"><strong>Quando vamos querer marcar uma classe como abstrata?</strong></h4><ol><li>Para forçar subclasses a implementar métodos abstratos.</li><li>Para impedir que existam objetos daquela classe.</li><li>Para manter a referência à uma classe.</li><li>Para manter código comum.</li></ol><h3 id="interface"><strong><strong>Interface</strong></strong></h3><p><strong>Uma interface é um <em>template</em> (ou uma "planta" de construção) de uma <strong>class</strong>e<strong>.</strong></strong></p><p>Uma interface é 100 abstrata. Construtores não são permitidos aqui. A interface representa o relacionamento "É UM".</p><p><strong>Observação<strong>: </strong></strong>interfaces apenas definem quais os métodos necessários. Não podemos manter código comum.</p><p>Uma interface possui apenas métodos abstratos, não possui métodos concretos. Os métodos da interface são, por padrão, <code>public</code> e <code>abstract</code>. Então, dentro da interface, não precisamos especificar as palavras-chaves <code>public</code> e <code>abstract</code>.</p><p>Então, quando uma classe implementa um método da interface sem especificar os modificadores de acesso daquele método, o compilador vai lançar uma exceção dizendo <code>"Cannot reduce the visibility of the inherited method from interface"</code> (Não é possível reduzir a visibilidade de um método herdado de uma interface). Sendo assim, o modificador de acesso de um método implementado de uma interface deve ser <code>public</code>.</p><p>Por padrão, as variáveis de interface são <code>public</code>, <code>static</code> e <code>final</code>.</p><p>Por exemplo:</p><pre><code class="language-java">interface Runnable {
    int a = 10; //equivale a: public static final int a = 10;
    void run(); //equivale a: public abstract void run();
}
public class InterfaceChecker implements Runnable{
    public static void main(String[] args) {
        Runnable.a = 5;//o valor do campo final Runnable.a não pode ser reatribuido.
    }
}</code></pre><p>Vamos ver um exemplo que explica o conceito de interface:</p><pre><code class="language-java">interface Drawable {
    void draw();
}
class Circle implements Drawable{
    public void draw() {
        System.out.println("Círculo!");
    }
}
public class InterfaceChecker {
    public static void main(String[] args) {
        Drawable circle = new Circle();
        circle.draw();
    }
}</code></pre><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://www.freecodecamp.org/portuguese/news/content/images/2022/09/interface.png" class="kg-image" alt="interface" width="251" height="371" loading="lazy"><figcaption>Figura 14: diagrama de classes que mostra o relacionamento entre uma interface e uma classe concreta (Drawable - ou desenhável, em português e Circle - ou círculo, em português)</figcaption></figure><h4 id="m-todos-default-e-m-todos-est-ticos-nas-interfaces"><strong>Métodos default e métodos estáticos nas <strong>Interfaces</strong></strong></h4><p>Normalmente, implementamos os métodos de uma interface em classes separadas. Digamos que seja necessário adicionar um novo método à interface. Então, deveremos implementar esse método em todas as outras classes que implementam essa interface também.</p><p>Para evitar esse tipo de problema, a partir do Java, 8 foi introduzida a possibilidade de implementar métodos default e estáticos dentro de uma interface, além dos métodos abstratos.</p><ul><li><strong>Método default</strong></li></ul><pre><code class="language-java">public interface DefaultInterface {
    void sleep();
    default void run() {
        System.out.println("Estou correndo!");
    }
}
public class InterfaceCheckers implements DefaultInterface{
    public void sleep() {
        System.out.println("Dormindo...");
    }
    public static void main(String[] args) {
        InterfaceCheckers checker = new InterfaceCheckers();
        checker.run();
        checker.sleep();
    }
}
/*
Saída:
Estou correndo!
Dormindo...
 */</code></pre><ul><li><strong>Métodos estáticos</strong></li></ul><p>Assim como métodos estáticos de classes, nós podemos chamá-los usando o nome da interface.</p><pre><code class="language-java">public interface DefaultInterface {
    void sleep();
    static void run() {
        System.out.println("Estou correndo!");
    }
}
public class InterfaceCheckers implements DefaultInterface{
    public void sleep() {
        System.out.println("Dormindo...");
    }
    public static void main(String[] args) {
        InterfaceCheckers checker = new InterfaceCheckers();
        DefaultInterface.run();
        checker.sleep();
    }
}
/*
Saída:
Estou correndo!
Dormindo...
 */</code></pre><ul><li><strong>I<strong>nterface</strong> de marcação</strong></li></ul><p>São interfaces vazias. Por exemplo as interfaces <em>Serializable</em>, <em>Cloneable </em>e <em>Remote</em>.</p><pre><code class="language-java">public interface Serializable 
{
  //Sem campos ou métodos
}</code></pre><h3 id="vantagens-das-interfaces"><strong>Vantagens das interfaces</strong></h3><ul><li>Nos ajudam a utilizar herança múltipla no Java.</li><li>Elas fornecem abstração.</li><li>Elas fornecem baixo acoplamento: os objetos são independentes uns dos outros.</li></ul><h3 id="quando-vamos-querer-mudar-de-uma-classe-para-uma-interface"><strong>Quando vamos querer mudar de uma classe para uma interface?</strong></h3><ol><li>Para forçar subclasses a implementar métodos abstratos.</li><li>Para evitar a criação de objetos dessa classe.</li><li>Para manter a referência à uma classe.</li></ol><p><strong>Observação<strong>: </strong></strong>lembre-se de que não podemos manter código comum dentro de uma interface.</p><p>Caso você queira definir métodos que podem ser necessários e código comum, use uma <strong>classe abstrata</strong>.</p><p>Caso queira apenas definir métodos necessários, use uma <strong><strong>interface</strong></strong>.</p><h2 id="polimorfismo"><strong>Polimorfismo</strong></h2><p><strong>Polimorfismo é a habilidade de um objeto de assumir diversas formas<strong>.</strong></strong></p><p>Polimorfismo em POO acontece quando uma superclasse faz referência a um objeto de uma subclasse.</p><p>Todos os objetos do Java são considerados polimórficos já que eles compartilham mais de um relacionamento É UM (pelo menos, todos os objetos vão passar no teste É UM para seu próprio tipo e para a classe <em>Object</em>).</p><p>Podemos acessar um objeto através de uma variável de referência. Uma variável de referência pode ser apenas de um tipo. Após declarada, o tipo da variável de referência não pode ser alterado.</p><p>Uma variável de referência pode ter uma classe ou uma interface como tipo.</p><p>Um único objeto pode ser referenciado por variáveis de referência de diversos tipos (desde que esses tipos estejam na mesma hierarquia), sendo o objeto do mesmo tipo da variável de referência ou de uma superclasse.</p><h3 id="sobrecarga-de-m-todos"><strong>Sobrecarga de métodos</strong></h3><p><strong>Se uma classe possui vários métodos, que possuem o mesmo nome mas parâmetros diferentes, isso é conhecido como sobrecarga de métodos (<em>method overload</em>)<strong>.</strong></strong></p><p>Regras da sobrecarga de métodos:</p><ol><li>Precisa ter uma lista de parâmetros diferente.</li><li>Pode possuir tipos de retorno diferentes.</li><li>Pode possuir modificadores de acesso diferentes.</li><li>Pode lançar exceções diferentes.</li></ol><pre><code class="language-java">class JavaProgrammer{
    public void code() {
        System.out.println("Programando em C++");
    }
    public void code(String language) {
        System.out.println("Programando em " + language);
    }
}
public class MethodOverloader {
    public static void main(String[] args) {
        JavaProgrammer gosling = new JavaProgrammer();
        gosling.code();
        gosling.code("Java");
    }
}
/*
Saída:
Programando em C++
Programando em Java
 */</code></pre><p><strong>Observação<strong>: </strong></strong>métodos estáticos também podem sofrer sobrecarga.</p><pre><code class="language-java">class Addition {
    public static int add(int a,int b) {
        return a+b;
    }
    public static int add(int a,int b,int c) {
        return a+b+c;
    }
}
public class PolyTest {
    public static void main(String[] args) {
        System.out.println(Addition.add(5, 5));
        System.out.println(Addition.add(2, 4, 6));
    }
}</code></pre><p><strong>Observação<strong>: </strong></strong>podemos sobrecarregar o método <em>main</em>(), mas a JVM (<em>Java Virtual Machine</em>) vai chamar o método <em>main</em>() que recebe um <em>array </em>de <em>strings </em>como parâmetro.</p><pre><code class="language-java">public class PolyTest {
    public static void main() {
        System.out.println("main()");
    }
    public static void main(String args) {
        System.out.println("String args");
    }
    public static void main(String[] args) {
        System.out.println("String[] args");
    }
}
//Saída: String[] args</code></pre><h3 id="regras-a-seguir-para-o-polimorfismo"><strong>Regras a seguir para o polimorfismo</strong></h3><h4 id="regras-de-tempo-de-compila-o"><strong>Regras de tempo de compilação</strong></h4><ol><li>O compilador conhece apenas tipos de referência.</li><li>Ele só pode procurar métodos em tipos de referência.</li><li>Gera uma assinatura de método.</li></ol><h4 id="regras-de-tempo-de-execu-o"><strong>Regras de tempo de execução</strong></h4><ol><li>Em tempo de execução, a JVM segue o tipo de tempo de execução exato (<strong>tipo de objeto</strong>) para localizar o método.</li><li>Deve corresponder a assinatura do método de tempo de compilação ao método na classe real do objeto. </li></ol><h3 id="sobrescrita-de-m-todos"><strong>Sobrescrita de métodos</strong></h3><p><strong>Se uma subclasse tem o mesmo método que foi declarado na superclasse, isso é conhecido como sobrescrita de métodos (method <em>override</em>)<strong>.</strong></strong></p><p>Regras da sobrescrita de métodos:</p><ol><li>Deve possuir a mesma lista de parâmetros.</li><li>Deve possuir o mesmo tipo de retorno: embora um retorno covariante nos permita alterar o tipo de retorno do método sobrescrito.</li><li>Não pode possuir um modificador de acesso mais restritivo: deve possuir um modificador de acesso menos restritivo.</li><li>Não deve lançar uma exceção verificada (<em>checked exception</em>) nova ou mais ampla: pode lançar exceções verificadas mais restritas e pode lançar qualquer exceção não verificada.</li><li>Apenas métodos herdados podem ser sobrescritos (é necessário um relacionamento É UM).</li></ol><p>Exemplo de sobrescrita de método:</p><pre><code class="language-java">public class Programmer {
    public void code() {
        System.out.println("Programando em C++");
    }
}
public class JavaProgrammer extends Programmer{
    public void code() {
        System.out.println("Programando em Java");
    }
}
public class MethodOverridder {
    public static void main(String[] args) {
        Programmer ben = new JavaProgrammer();
        ben.code();
    }
}
/*
Saída:
Programando em Java
 */</code></pre><p><strong>Observação<strong>: </strong></strong>métodos estáticos não podem ser sobrescritos porque métodos são sobrescritos em tempo de execução (<em>runtime</em>). Métodos estáticos são associados com classes, enquanto métodos de instância são associados com objetos. Então, em Java, o método <code>main()</code> não pode ser sobrescrito.</p><p><strong>Observação<strong>:</strong></strong> construtores podem ser sobrecarregados mas não podem ser sobrescritos.</p><h3 id="tipos-de-objeto-e-tipos-de-refer-ncia"><strong>Tipos de objeto e tipos de referência</strong></h3><pre><code class="language-java">class Person{
    void eat() {
        System.out.println("A pessoa está comendo");
    }
}
class Student extends Person{
    void study() {
        System.out.println("O estudante está estudando");
    }
}
public class InheritanceChecker {
    public static void main(String[] args) {
        Person alex = new Person();//New Person "É UMA" Person
        alex.eat();
        Student jane = new Student();//New Student "É UM" Student
        jane.eat();
        jane.study();
        Person mary = new Student();//New Student "É UM" Person
        mary.eat();
        //Student chris = new Person(); //New Person não É UM Student.
    }
}</code></pre><p>Em <code>Person mary = new Student();</code> esse modo de criar o objeto está correto.</p><p><code>mary</code> é uma variável de referência do tipo <code>Person</code> e <code>new Student()</code> criará um novo objeto do tipo <code>Student</code>.</p><p><code>mary</code> não pode acessar <code>study()</code> em tempo de compilação porque o compilador conhece apenas o tipo de referência. Já que <code>study()</code> não existe na classe do tipo de referência, não é possível acessá-lo. Em tempo de execução, no entanto, <code>mary</code> será do tipo <code>Student</code> (tipo de tempo de execução/tipo de objeto).</p><p>Veja esse <a href="https://coderanch.com/t/394210/java/compile-time-runtime-type" rel="noopener">artigo</a> (texto em inglês) para entender melhor sobre tipos de tempo de execução.</p><p>Neste caso, podemos convencer o compilador dizendo "em tempo de execução, <code>mary</code> será do tipo <code>Student</code>, então permita-me chamar o método study()". Como podemos convencer o compilador a fazer isso? Aqui é onde usaremos o <em>casting</em>.</p><p>Podemos converter <code>mary</code> ao tipo <code>Student</code> em tempo de compilação e chamar <code>study()</code> se utilizarmos o <em>casting</em>.</p><pre><code class="language-java">((Student)mary).study();</code></pre><p>Aprenderemos sobre <em>casting </em>a seguir.</p><h3 id="casting-de-tipos-de-objeto"><strong><em>C<strong>asting</strong> </em>de tipos de objeto</strong></h3><p>O <em>casting </em>no Java é classificado em dois tipos:</p><ol><li><em>Casting </em>de ampliação (<em>widening casting</em>, implícito): conversão automática de tipos.</li><li><em>Casting </em>de restrição (<em>narrowing casting</em>, explícito): precisa de uma conversão explícita.</li></ol><p>Com primitivos, <code>long</code> é um tipo mais abrangente que <code>int</code>. Assim como ocorre com os objetos, a classe mãe é mais abrangente que a classe filha.</p><p>A variável de referência apenas faz referência a um objeto. Utilizar <em>casting </em>em uma variável de referência não muda o tipo do objeto em memória, mas rotula o mesmo objeto de uma outra maneira para se ter acesso aos membros de instância.</p><p><strong><strong>I. Widening casting</strong> (<em>casting </em>de ampliação)</strong></p><pre><code class="language-java">Superclass superRef = new Subclass();</code></pre><p><strong><strong>II. Narrowing casting</strong> (<em>casting </em>de restrição)</strong></p><pre><code class="language-java">Subclass ref = (Subclass) superRef;</code></pre><p>Temos que tomar cuidado quando utilizamos um <em>casting </em>restritivo. Quando utilizamos o <em>casting </em>restritivo, convencemos o compilador a compilar sem erros. Caso estejamos errados, receberemos um erro em tempo de execução (geralmente, <code>ClassCastException</code>).</p><p>Para executar um <em>casting </em>restritivo corretamente, usamos o operador <code>instanceof</code>. Com ele, podemos verificar se o relacionamento é do tipo É UM.</p><pre><code class="language-java">class A {
    public void display(){
        System.out.println("Class A");
    }
}

class B extends A{
    public void display(){
        System.out.println("Class B");
    }
}

public class Test {
    public static void main(String[] args) {
        A objA = new B();
        if(objA instanceof B){
            ((B)objA).display();
        }
    }
}
/**
 * Saída: Class B
 */
</code></pre><p>Como eu disse anteriormente, devemos sempre nos lembrar de uma coisa muito importante quando criamos um objeto utilizando a palavra-chave <code>new</code>: o tipo de referência deve ser <strong>do mesmo tipo </strong>ou de um <strong>supertipo</strong> do objeto sendo criado.</p><h2 id="conclus-o"><strong>Conclusão</strong></h2><p>Obrigado por ler este artigo. Espero que ele tenha ajudado.</p><p>Recomendo fortemente a leitura de mais artigos relacionados à POO.</p><p>Confira, também, a série original de artigos do autor no medium: <a href="https://medium.com/@mvthanoshan9/object-oriented-programming-principles-in-java-820919dced1a">Princípios de orientação a objetos em Java</a> (texto em inglês).</p><blockquote>Sonhos não são o que você vê quando está dormindo. Eles são o que não deixa você dormir.<br>― <strong><strong>A P J Abdul Kalam, </strong>Asas de fogo<strong>: </strong>autobiografia</strong></blockquote><p>Obrigado.</p><p><strong>Bons estudos<strong><strong><strong><strong><strong><strong><strong>!</strong></strong></strong></strong></strong></strong></strong></strong></p> ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ Os quatro pilares da Programação Orientada a Objetos - com JavaScript ]]>
                </title>
                <description>
                    <![CDATA[ O JavaScript é uma linguagem multiparadigma, ou seja, pode ser escrita seguindo diferentes paradigmas de programação. Um paradigma de programação é essencialmente um conjunto de regras que você segue ao escrever código, para ajudá-lo a resolver um problema específico. No caso da Programação Orientada a Objetos, temos quatro pilares. Eles ]]>
                </description>
                <link>https://www.freecodecamp.org/portuguese/news/os-quatro-pilares-da-programacao-orientada-a-objetos-com-javascript/</link>
                <guid isPermaLink="false">62d1d1d9fea2f10707d65670</guid>
                
                    <category>
                        <![CDATA[ Programação orientada a objetos ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Thiago Costa Barbosa ]]>
                </dc:creator>
                <pubDate>Sun, 07 Aug 2022 18:00:00 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/portuguese/news/content/images/2022/07/capa-1.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <p data-test-label="translation-intro">
        <strong>Artigo original:</strong> <a href="https://www.freecodecamp.org/news/four-pillars-of-object-oriented-programming/" target="_blank" rel="noopener noreferrer" data-test-label="original-article-link">The Four Pillars of Object-Oriented Programming</a>
      </p><p>O JavaScript é uma linguagem multiparadigma, ou seja, pode ser escrita seguindo diferentes paradigmas de programação. Um paradigma de programação é essencialmente um conjunto de regras que você segue ao escrever código, para ajudá-lo a resolver um problema específico.</p><p>No caso da Programação Orientada a Objetos, temos quatro pilares. Eles são princípios de design de software para ajudá-lo a escrever um código limpo e orientado a objetos.</p><p>Os quatro pilares da programação orientada a objetos são:</p><ul><li>Abstração</li><li>Encapsulamento</li><li>Herança</li><li>Polimorfismo</li></ul><p>Vamos dar uma olhada em cada um deles.</p><h1 id="abstra-o-na-programa-o-orientada-a-objetos"><strong>Abstração na Programação Orientada a Objetos</strong></h1><p>Abstrair algo significa esconder os detalhes da implementação dentro de algo – às vezes um protótipo, às vezes em uma função. Portanto, quando você chama a função, não precisa entender exatamente o que ela está fazendo.</p><p>Um exemplo claro do conceito de abstração seria o funcionamento de um carro. Quando acionamos ele para ligar, não precisamos saber quais passos ele faz para colocar o motor em funcionamento. Quando acionamos o freio, não precisamos saber todos os mecanismos que são acionados para fazer o carro frear. Apenas sabemos o que cada objeto ou função do carro produz como resultado.</p><p>Voltando para a codificação, se você tivesse que entender cada função em uma base de código grande, você nunca codificaria nada, pois, levaria meses para terminar de ler e entender a lógica de tudo isso.</p><p>Contudo, abstraindo certos detalhes, você é capaz de criar uma base de código reutilizável, simples de entender e facilmente alterável. Deixe-me lhe dar um exemplo:</p><figure class="kg-card kg-code-card"><pre><code class="language-javascript">function hitAPI(tipo){
	if (type instanceof CargaInicial) {
		// Exemplo de implementação
	} else if (type instanceof NavBar) {
		// Exemplo de implementação
	} else {
		// Exemplo de implementação
	}
}</code></pre><figcaption><font style="box-sizing: inherit; vertical-align: inherit;"><font style="box-sizing: inherit; vertical-align: inherit;">Isso não é abstração de forma alguma.</font></font></figcaption></figure><p>Você percebeu nesse exemplo que você precisa especificar todos os passos da implementação de cada caso de uso?</p><p>Para cada novo tipo que você precisar acessar nessa função, você precisará de um novo bloco <code>if</code> e de seu próprio código personalizado. Isso não é um código abstraído, pois você precisa se preocupar com o passo a passo de cada implementação. Ele também não é reutilizável, sendo um pesadelo na hora de fazer a manutenção desse código.</p><p>Bom, e que tal o código abaixo?</p><pre><code class="language-javascript">hitApi('www.kealanparr.com', HTTPMethod.Get)</code></pre><p>Desse modo, você simplesmente passou um URL para sua função e qual método HTTP deseja usar nela e está feito.</p><p>Você não precisa mais se preocupar com o funcionamento da função. Isso ajuda muito na reutilização de código, além de tornar seu código muito mais sustentável.</p><p>É disso que trata a <strong><strong>Abstração</strong></strong>. Encontrar coisas semelhantes em seu código e fornecer uma função ou objeto genérico e servir em vários lugares/com vários interesses.</p><p>Um bom exemplo para entender a <strong><strong>Abstração</strong></strong> é: imagine se você estivesse criando uma máquina para fazer café para seus usuários. Pode haver duas abordagens:</p><h2 id="como-cri-la-com-abstra-o"><strong>Como criá-la com abstração</strong></h2><ul><li>Ter um botão escrito "Fazer café"</li></ul><h2 id="como-cri-la-sem-abstra-o"><strong>Como criá-la sem abstração</strong></h2><ul><li>Ter um botão escrito "Adicionar água fria à chaleira"</li><li>Ter um botão escrito "Ferver a água"</li><li>Ter um botão escrito "Adicionar uma cápsula de café"</li><li>Ter um botão escrito "Passar a água pela cápsula de café"</li><li>Além de vários outros botões para completar o processo</li></ul><p>É um exemplo muito simples, mas a primeira abordagem <em><em>abstrai</em></em> toda a lógica da máquina. A segunda abordagem força o usuário a entender como fazer café e essencialmente fazer o seu próprio.</p><p>O próximo pilar é o de <strong><strong>Encapsulamento</strong></strong>. Mostrarei uma forma de aplicarmos a <strong><strong>Abstração</strong></strong>, usando-o<strong><strong>.</strong></strong></p><h1 id="encapsulamento-na-programa-o-orientada-a-objetos"><strong>Encapsulamento na Programação Orientada a Objetos</strong></h1><p>A definição de encapsulamento é "a ação de colocar algo dentro ou como se estivesse em uma cápsula". Remover o acesso a partes do seu código e tornar as coisas privadas é exatamente o que o <strong><strong>Encapsulamento</strong></strong> faz (muitas vezes, as pessoas se referem a ele como "ocultação de dados").</p><p>Encapsulamento significa que o código de cada objeto deve controlar apenas seu próprio estado. &nbsp;Se você não sabe o que é o estado de um objeto, vamos fazer a seguinte analogia:</p><p>Sabe aquele retrato de família, em que você era bebê ainda? Ele é um registro do estado "instantâneo" em que você estava naquele exato momento. De lá pra cá muita coisa mudou, e se hoje você tirar uma nova foto, seu estado já não é o mesmo que aquele. Aquilo que você fez durante o tempo com sua vida, transformou você. A mesma coisa ocorre com o objeto.</p><p>O estado é o "instantâneo" atual do objeto. Todas as chaves e métodos (funções) de um objeto são suas propriedades. Se você redefinir ou excluir uma chave, por exemplo, estará alterando o seu estado.</p><p>Por isso, é importante limitar o acesso de quais partes do código podem ser acessadas. Caso não sejam necessárias, torne as coisas mais inacessíveis para não possibilitar efeitos colaterais no estado do objeto.</p><p>Propriedades privadas são obtidas em JavaScript usando <em>closures</em>. Segue um exemplo abaixo:</p><pre><code class="language-javascript">var Cachorro = (function () {

	// Privado
	var executar = function () {
		// Implementação de executar
	};
    
	// Privado
	var raca = "Dálmata"
    
	// Público
	var nome = "Rex";

	// Público
	var fazerBarulho = function () {
 		return 'Au au!';
	};

 	return {
		fazerBarulho: fazerBarulho,
		nome: nome
 	};
})();

</code></pre><p>A primeira coisa que fizemos foi criar uma função que é chamada imediatamente (<strong><strong>Immediately Invoked Function Expression</strong></strong>, ou de forma abreviada, <strong>IIFE</strong>). Ela criou um objeto que qualquer um pode acessar, mas escondeu alguns detalhes dentro dela. Você não pode chamar o método <code>executar</code> e nem a chave <code>raca</code>, pois não o expomos no objeto final com o retorno.</p><p>Esse padrão específico acima é chamado de <strong><strong>Revealing Module Pattern (Padrão do Módulo de Revelação)</strong></strong>, mas é apenas um exemplo de como você pode obter o <strong><strong>encapsulamento.</strong></strong></p><p>Vamos, no entanto, focar mais na ideia de <strong><strong>Encapsulamento</strong></strong> (já que agora é mais importante entender o <strong><strong>Encapsulamento</strong></strong> como um todo, do que apenas aprender um padrão dele).</p><p>Concentre-se mais em como você pode tornar seus dados e código privados e separá-los. Modularizar e ter responsabilidades claras é a chave para a <strong><strong>Orientação a Objetos</strong></strong>.</p><p>Por que devemos preferir a privacidade? Por que não ter tudo acessível globalmente?</p><ul><li>Muitos bits de código não relacionados se tornarão dependentes/acoplados uns dos outros por meio de variáveis globais.</li><li>Você provavelmente substituirá as variáveis ​​se o nome delas forem reutilizados, o que pode levar a erros ou comportamentos imprevisíveis.</li><li>Você provavelmente terminará com um <strong>c<strong>ódigo </strong>espaguete </strong>– código que é difícil de raciocinar e entender o que está lendo e gravando suas variáveis​, ou onde muda o estado de cada uma.</li></ul><p>O encapsulamento pode ser aplicado separando longas linhas de código em funções menores e separadas. É recomendado também separar essas funções em módulos. O objetivo é sempre escondermos os dados em um lugar em que nada mais precise de acesso e expormos os dados de modo claro onde for necessário.</p><p>O <strong><strong>encapsulamento</strong></strong> metaforicamente seria uma casca de noz. Vinculando seus dados a algo, seja uma classe, objeto, módulo ou função, e fazendo o possível para mantê-lo o mais privado possível.</p><h1 id="heran-a-na-programa-o-orientada-a-objetos"><strong>Herança na Programação Orientada a Objetos</strong></h1><p>A herança permite que um objeto adquira as propriedades e métodos de outro objeto. Em JavaScript, isso é feito por <strong><strong>Prototypal Inheritance</strong> </strong>(ou herança prototípica, em português).</p><p>A reutilização é o principal benefício aqui. Sabemos que às vezes a mesma coisa precisa ser feita em vários lugares e sempre de forma igual, exceto em alguma pequena parte. Esse é um problema que a herança pode resolver.</p><p>Sempre que usamos herança, tentamos fazer com que o pai e o filho tenham <strong><strong>alta coesão. Coesão</strong></strong> é o quanto seu código está relacionado. Por exemplo, o tipo <code>Passaro</code> consegue ser estendido do tipo <code>MotorADiesel</code>? Não, certo?</p><p>Por isso, mantenha sua herança simples de entender e previsível. Não faça heranças completamente não relacionadas somente porque há um método ou uma propriedade de que você precisa. A herança não resolve bem esse problema específico.</p><p>Ao usar herança, ela precisa ter a maior parte das funcionalidades (você nem sempre precisa ter absolutamente tudo).</p><p>Nós, desenvolvedores, temos um princípio chamado de <strong>princípio de <strong>substituição de Liskov</strong></strong>. Ele afirma que, se conseguimos usar uma classe pai (vamos chamá-la de <code>TipoPai</code>) em qualquer lugar em que usamos uma classe filho (vamos chamá-la de <code>TipoFilho</code>) – e se <code>TipoFilho</code> é uma herança de <code>TipoPai</code>, então passamos no teste.</p><p>A principal razão pela qual se falha nesse teste é se <code>TipoFilho</code> estiver removendo coisas do pai. Se <code>TipoFilho</code> remove métodos herdados do pai, isso gera diversos <code>TypeError</code>, onde haverá coisas que estarão indefinidas e que estamos esperando que não sejam.</p><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://www.freecodecamp.org/portuguese/news/content/images/2022/07/fluxograma-1.png" class="kg-image" alt="fluxograma-1" width="400" height="881" loading="lazy"><figcaption>As flechas parecem estar indo na direção errada. Mas o Animal é a base - o pai.</figcaption></figure><p>A "cadeia de herança" é o termo usado para descrever esse fluxo de herança do protótipo do objeto base (aquele do qual todos os outros herdam) até o "final" da cadeia de herança (o último tipo que está herdando – <strong><strong>Cachorro</strong>,</strong> no exemplo acima).</p><p>Faça o seu melhor para manter suas cadeias de herança limpas e sensatas. Você pode facilmente acabar programando um antipadrão (<em><em>antiPattern</em></em>) ao usar <strong><strong>Herança </strong></strong>(chamado de <strong><strong>antipadrão de base frágil</strong></strong>). Isso acontece quando seus protótipos base são considerados "frágeis" – aqueles em que, se você faz uma alteração "segura" no objeto base, todos os seus filhos começam a quebrar.</p><h1 id="polimorfismo-na-programa-o-orientada-a-objetos"><strong>Polimorfismo na Programação Orientada a Objetos</strong></h1><p>Polimorfismo significa "a condição de ocorrer de várias formas diferentes". É exatamente com isso que o quarto e último pilar está preocupado – que tipos nas mesmas cadeias de herança sejam capazes de fazer coisas diferentes.</p><p>Se você usou a herança corretamente, agora pode usar tanto os pais de maneira confiável como seus filhos. Quando dois tipos compartilham uma cadeia de herança, eles podem ser usados ​​alternadamente sem erros ou declarações em seu código.</p><p>A partir do último diagrama, podemos ter um protótipo base chamado <code>Animal</code> que define <code>fazerBarulho</code>. Em seguida, cada tipo que se estende desse protótipo pode substituí-lo para fazer seu próprio trabalho personalizado. Algo assim:</p><pre><code class="language-javascript">// Vamos configurar um exemplo de Animal e Cachorro
function Animal(){}
function Cachorro(){}

Animal.prototype.fazerBarulho = function(){
	console.log("Barulho base");
};

// A maioria dos animais que programamos tem 4 pernas. Isso pode ser substituído se necessário
Animal.prototype.pernas = 4;

Cachorro.prototype = new Animal();

Cachorro.prototype.fazerBarulho = function(){	console.log("Au au");  
};

var animal = new Animal();
var cachorro = new Cachorro();

animal.fazerBarulho();     // Barulho base
cachorro.fazerBarulho();   // Au au - isso foi substituído
cachorro.pernas;           // 4! Isso foi herdado</code></pre><p>Aqui, a classe <code>Cachorro</code> estende <code>Animal</code> e pode fazer uso da propriedade padrão <code>pernas</code>. Porém, ela também é capaz de fazer sua própria implementação de fazer seu próprio barulho.</p><p>O verdadeiro poder do polimorfismo é poder compartilhar comportamentos e permitir substituições personalizadas.</p><h1 id="conclus-o"><strong>Conclusão</strong></h1><p>Espero que isso tenha explicado quais são os quatro pilares da programação orientada a objetos e como eles levam a um código mais limpo e robusto.</p><p>Se você gostou desse artigo e quiser ver mais, eu compartilho meus textos no <a href="https://twitter.com/kealanparr">Twitter</a>.</p> ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ Os princípios SOLID da Programação Orientada a Objetos explicados em bom português ]]>
                </title>
                <description>
                    <![CDATA[ Os princípios SOLID são cinco princípios do design de classes orientado a objetos. Eles são um conjunto de regras e práticas recomendadas a serem seguidas na criação de uma estrutura de classe. Esses cinco princípios nos ajudam a entender a necessidade de determinados padrões de projetos e arquitetura de software ]]>
                </description>
                <link>https://www.freecodecamp.org/portuguese/news/os-principios-solid-da-programacao-orientada-a-objetos-explicados-em-bom-portugues/</link>
                <guid isPermaLink="false">6284fec989eb8b0539f43564</guid>
                
                    <category>
                        <![CDATA[ Programação orientada a objetos ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Daniel Rosa ]]>
                </dc:creator>
                <pubDate>Wed, 18 May 2022 17:35:04 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/portuguese/news/content/images/2022/05/solid.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <p data-test-label="translation-intro">
        <strong>Artigo original:</strong> <a href="https://www.freecodecamp.org/news/solid-principles-explained-in-plain-english/" target="_blank" rel="noopener noreferrer" data-test-label="original-article-link">The SOLID Principles of Object-Oriented Programming Explained in Plain English</a>
      </p><p>Os princípios SOLID são cinco princípios do design de classes orientado a objetos. Eles são um conjunto de regras e práticas recomendadas a serem seguidas na criação de uma estrutura de classe.</p><p>Esses cinco princípios nos ajudam a entender a necessidade de determinados padrões de projetos e arquitetura de software em geral. Por isso, creio que seja um tópico que todo desenvolvedor deveria conhecer.</p><p>Este artigo ensinará a você tudo o que você precisa saber para aplicar os princípios SOLID aos seus projetos.</p><p>Vamos começar dando uma olhada na história desse termo. Em seguida, vamos nos aprofundar nos detalhes – os porquês e modos de usar cada princípio – criando um design de classe e melhorando-o passo a passo.</p><p>Pegue, então, uma xícara de café ou de chá e vamos nessa!</p><h2 id="hist-rico"><strong>Histórico</strong></h2><p>Os princípios SOLID foram apresentados pela primeira vez pelo famoso cientista da computação Robert J. Martin (também conhecido como Uncle Bob) em seu <a href="https://fi.ort.edu.uy/innovaportal/file/2032/1/design_principles.pdf">trabalho</a> (texto em inglês) lançado no ano 2000. A abreviação SOLID, no entanto, foi apresentada mais tarde, por Michael Feathers.</p><p>Uncle Bob também é o autor de dois livros muito conhecidos, <em><em>C</em>ódigo limpo</em> e <em>Arquitetura limpa</em>, e um dos participantes da "<a href="https://agilemanifesto.org/history.html">Aliança Agile</a>" (texto em inglês).</p><p>Portanto, não é de surpreender que todos esses conceitos sobre código limpo, arquitetura orientada a objetos e padrões de projetos estejam, de algum modo, conectados e complementem-se.</p><p>Todos eles servem ao mesmo propósito:</p><blockquote>"Criar código compreensível, legível e testável no qual diversos desenvolvedores possam trabalhar de modo colaborativo."</blockquote><p>Vamos examinar cada princípio, um por um. Seguindo a sequência da abreviação SOLID, temos:</p><ul><li>O <strong><strong>S</strong></strong>ingle Responsibility Principle (Princípio da responsabilidade única)</li><li>O <strong><strong>O</strong></strong>pen-Closed Principle (Princípio aberto/fechado)</li><li>O <strong><strong>L</strong></strong>iskov Substitution Principle (Princípio da substituição de Liskov)</li><li>O <strong><strong>I</strong></strong>nterface Segregation Principle (Princípio da segregação da interface)</li><li>O <strong><strong>D</strong></strong>ependency Inversion Principle (Princípio da inversão da dependência)</li></ul><h2 id="princ-pio-da-responsabilidade-nica"><strong>Princípio da responsabilidade única</strong></h2><p>O princípio da responsabilidade única declara que <strong>uma<strong> class</strong>e<strong> </strong>deve fazer apenas uma coisa<strong> </strong>e, portanto, deve ter apenas uma razão para ser modificada</strong>.</p><p>Vamos declarar esse princípio de um modo mais técnico: somente uma alteração em potencial (lógica do banco de dados, lógica de registro e assim por diante) na especificação do software pode ser capaz de alterar a especificação da classe.</p><p>Isso significa que, se uma classe for um contêiner de dados, como uma classe Livro ou uma classe Estudante, e se ela tiver campos relativos àquela entidade, ela deve ser alterada apenas quando alterarmos o modelo de dados.</p><p>Seguir o princípio da responsabilidade única é importante. Para começar, porque muitas equipes diferentes podem trabalhar no mesmo projeto e editar a mesma classe por motivos diferentes, o que poderia ocasionar incompatibilidade entre os módulos.</p><p>Em segundo lugar, isso torna mais fácil o controle de versão. Por exemplo, digamos que temos uma classe persistente que trata das operações do banco de dados, e vemos que ocorreu um commit no GitHub com uma mudança naquele arquivo. Seguindo o princípio, saberemos que essa mudança está relacionada com questões de armazenamento ou relacionadas ao banco de dados.</p><p>Conflitos de <em>merge</em> são um outro exemplo. Eles aparecem quando equipes diferentes alteram o mesmo arquivo. Se, no entanto, seguirmos o princípio da responsabilidade única, menos conflitos surgirão – os arquivos terão um único motivo para mudar e os conflitos que existirem serão muito mais fáceis de resolver.</p><h3 id="armadilhas-comuns-e-antipadr-es"><strong>Armadilhas comuns e antipadrões</strong></h3><p>Nesta seção, veremos alguns dos erros comuns que violam o princípio da responsabilidade única. Em seguida, falaremos sobre algumas formas de consertarmos esses erros.</p><p>Examinaremos o código de um programa simples de faturamento de uma livraria como exemplo. Vamos começar definindo a classe Livro, que será usada na fatura.</p><pre><code class="language-java">class Livro {
	String nome;
	String nomeAutor;
	int ano;
	int preco;
	String isbn;

	public Livro(String nome, String nomeAutor, int ano, int preco, String isbn) {
		this.nome = nome;
		this.nomeAutor = nomeAutor;
		this.ano = ano;
        this.preco = preco;
		this.isbn = isbn;
	}
}
</code></pre><p>Essa é uma classe Livro simples com alguns campos, nada demais. Não estou criando campos privados para que não precisemos lidar com <em>getters </em>e <em>setters </em>e possamos prestar atenção na lógica.</p><p>Agora, vamos criar a classe Fatura, que terá a lógica para o faturamento e o cálculo do preço total. Por agora, vamos considerar que nossa loja vende apenas livros.</p><pre><code class="language-java">public class Fatura {

	private Livro livro;
	private int quantidade;
	private double porcDesconto;
	private double porcImposto;
	private double total;

	public Fatura(Livro livro, int quantidade, double porcDesconto, double porcImposto) {
		this.livro = livro;
		this.quantidade = quantidade;
		this.porcDesconto = porcDesconto;
		this.porcImposto = porcImposto;
		this.total = this.calcularTotal();
	}

	public double calcularTotal() {
	        double preco = ((livro.preco - livro.preco * porcDesconto) * this.quantidade);

		double precoComImposto = preco * (1 + porcImposto);

		return precoComImposto;
	}

	public void imprimirFatura() {
            System.out.println(quantidade + "x " + livro.nome + " " +          livro.preco + "$");
            System.out.println("Porcentagem de desconto: " + porcDesconto);
            System.out.println("Procentagem de imposto: " + porcImposto);
            System.out.println("Total: " + total);
	}

        public void salvarParaArquivo(String nomeArquivo) {
	// Cria um arquivo com o nome especificado e salva a fatura
	}

}</code></pre><p>Essa é a nossa classe Fatura. Ela também contém alguns campos relativos ao faturamento e 3 métodos:</p><ul><li>Método <strong><strong>calcula</strong>r<strong>Total</strong></strong>, que calcula o preço total,</li><li>Método <strong>imprimirFatura</strong>, que imprime a fatura no console e</li><li>Método <strong>salvarParaArquivo</strong>, responsável por salvar a fatura em um arquivo.</li></ul><p>Dedique uns instantes a entender o que há de errado com o design dessa classe antes de ler o próximo parágrafo.</p><p>O que está acontecendo aqui? nossa classe viola o princípio da responsabilidade única de diversas maneiras.</p><p>A primeira violação está no método <strong>imprimirFatura</strong>, que tem nossa lógica de impressão. De acordo com o princípio da responsabilidade única, nossa classe deve ter apenas uma única razão para ser alterada. Essa razão deve ser uma mudança no cálculo da fatura para nossa classes.</p><p>Nessa arquitetura, no entanto, se quiséssemos mudar o formato de impressão, precisaríamos mudar a classe. É por isso que não devemos misturar a lógica de impressão com a lógica de negócios na mesma classe.</p><p>Temos um outro método que viola o princípio da responsabilidade única em nossa classe: o método <strong><strong>sa</strong>l<strong>v</strong>arParaArquivo</strong>. É um erro muito comum misturar a lógica da persistência com a lógica dos negócios.</p><p>Não pense em termos de salvar um arquivo – poderíamos estar falando em salvar em um banco de dados, fazer uma chamada à API ou alguma outra coisa relacionada à persistência.</p><p>Bem, como podemos, então, consertar esse problema?</p><p>Podemos criar novas classes para as lógicas de impressão e persistência, para não precisarmos mais modificar a classe Fatura para esses fins.</p><p>Criamos 2 classes, <strong>ImpressaoDeFatura<strong> </strong></strong>e <strong><strong>Persistenc</strong>iaDaFatura<strong>,</strong></strong> e movemos os métodos.</p><pre><code class="language-java">public class ImpressaoDeFatura {
    private Fatura fatura;

    public ImpressaoDeFatura(Fatura fatura) {
        this.fatura = fatura;
    }
    
    public void imprimir() {
            System.out.println(fatura.quantidade + "x " + fatura.livro.nome + " " + fatura.livro.preco + "$");
            System.out.println("Porcentagem de desconto: " + fatura.porcDesconto);
            System.out.println("Procentagem de imposto: " + fatura.porcImposto);
            System.out.println("Total: " + fatura.total);
	}
}</code></pre><pre><code class="language-java">public class PersistenciaDaFatura {
    Fatura fatura;

    public PersistenciaDaFatura(Fatura fatura) {
        this.fatura = fatura;
    }

    public void salvarParaArquivo(String nomeArquivo) {
		// Cria um arquivo com o nome especificado e salva a fatura
	}
}</code></pre><p>Agora, nossa estrutura de classe obedece ao princípio de responsabilidade única e cada classe é responsável por um aspecto de nossa aplicação. Ótimo!</p><h2 id="princ-pio-aberto-fechado"><strong>Princípio aberto/fechado</strong></h2><p>O princípio de aberto/fechado diz que as <strong><strong>classes </strong>devem estar abertas para extensão, mas fechadas para modificação</strong>.</p><p>Modificação significa alterar o código de uma classe existente, enquanto extensão significa adicionar novas funcionalidades.</p><p>O que esse princípio representa, portanto é que: devemos poder adicionar novas funcionalidades sem tocar no código existente para a classe. Isso se dá porque, sempre que modificamos o código existente, estamos nos arriscando a criar bugs em potencial. Assim, devemos evitar de tocar em código em produção testado e confiável (em grande parte), se possível.</p><p>No entanto, como podemos adicionar novas funcionalidades sem tocar na classe? Geralmente, isso é feito com o auxílio de interfaces e classes abstratas.</p><p>Agora que já tratamos do básico sobre o princípio, vamos aplicar isso ao nosso programa de faturamento.</p><p>Digamos que nosso chefe tenha nos dito que deseja que as faturas sejam salvas em um banco de dados onde possamos fazer pesquisas facilmente. Para nós, isso seria fácil, então pedimos pouco tempo!</p><p>Criamos o banco de dados, fazemos a conexão a ele e adicionamos um método de salvamento em nossa classe <strong><strong>Persistenc</strong>iaDaFatura</strong>:</p><pre><code class="language-java">public class PersistenciaDaFatura {
    Fatura fatura;

    public PersistenciaDaFatura(Fatura fatura) {
        this.fatura = fatura;
    }

    public void salvarParaArquivo(String nomeArquivo) {
		// Cria um arquivo com o nome especificado e salva a fatura
	}

    public void salvarParaBancoDeDados() {
        // Salva a fatura em um banco de dados
    }
}</code></pre><p>Infelizmente para nós, os desenvolvedores preguiçosos da livraria, não criamos as classes de modo que pudessem ser extensíveis no futuro. Assim, para adicionar esse recurso, modificamos a classe <strong><strong>Persistenc</strong>iaDaFatura</strong>.</p><p>Se nossa criação das classes tivesse obedecido o princípio de aberto/fechado, não precisaríamos alterar essa classe.</p><p>Então, por sermos os desenvolvedores preguiçosos, porém inteligentes, da livraria, percebemos o problema do design e decidimos refatorar o código para que possamos atender àquele princípio.</p><pre><code class="language-java">interface PersistenciaDaFatura {

    public void salvar(Fatura fatura);
}</code></pre><p>Mudamos o tipo de <strong><strong>Persistenc</strong>iaDaFatura<strong> </strong></strong>para Interface e adicionamos um método de salvamento. Cada classe de persistência implementará esse método.</p><pre><code class="language-java">public class PersistenciaEmBD implements PersistenciaDaFatura {

    @Override
    public void salvar(Fatura fatura) {
        // Salvar no BD
    }
}</code></pre><pre><code class="language-java">public class PersistenciaEmArquivo implements PersistenciaDaFatura {

    @Override
    public void salvar(Fatura fatura) {
        // Salvar em arquivo
    }
}</code></pre><p>Desse modo, nossa estrutura de classe terá essa aparência:</p><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://www.freecodecamp.org/portuguese/news/content/images/2022/05/SOLID-Tutorial-1-1024x554.jpeg" class="kg-image" alt="SOLID-Tutorial-1-1024x554" srcset="https://www.freecodecamp.org/portuguese/news/content/images/size/w600/2022/05/SOLID-Tutorial-1-1024x554.jpeg 600w, https://www.freecodecamp.org/portuguese/news/content/images/size/w1000/2022/05/SOLID-Tutorial-1-1024x554.jpeg 1000w, https://www.freecodecamp.org/portuguese/news/content/images/2022/05/SOLID-Tutorial-1-1024x554.jpeg 1024w" sizes="(min-width: 720px) 720px" width="1024" height="554" loading="lazy"><figcaption>De cima para baixo e da esquerda para a direita: Livro | ImpressaoDeFatura | Fatura | PersistenciaEmBD | interface PersistenciaDaFatura | PersistenciaEmArquivo</figcaption></figure><p>Agora, nossa lógica de persistência é facilmente extensível. Se nosso chefe nos pedir outro banco de dados e tiver dois tipos diferentes de BD, como o MySQL e o MongoDB, podemos fazer isso facilmente.</p><p>Você pode achar que simplesmente criaríamos diversas classes sem uma interface e adicionaríamos um método de salvamento a cada uma delas.</p><p>Digamos, porém, que tenhamos estendido nossa aplicação e que tenhamos diversas classes de persistência, como <strong><strong>Persistenc</strong>iaDaFatura</strong>, <strong><strong>Persistenc</strong>iaDeLivro </strong>e criamos uma classe <strong>GerenteDeP<strong>ersistenc</strong>ia<strong> </strong></strong>que gere todas as classes de persistência:</p><pre><code class="language-java">public class GerenteDePersistencia {
    PersistenciaDaFatura persistenciaDaFatura;
    PersistenciaDeLivro persistenciaDeLivro;
    
    public GerenteDePersistencia(PersistenciaDaFatura persistenciaDaFatura,
                               PersistenciaDeLivro persistenciaDeLivro) {
        this.persistenciaDaFatura = persistenciaDaFatura;
        this.persistenciaDeLivro = persistenciaDeLivro;
    }
}</code></pre><p>Agora, podemos passar qualquer classe que implemente a interface <strong><strong>Persistenc</strong>iaDaFatura<strong> </strong></strong>para essa classe com o auxílio do polimorfismo. Essa é a flexibilidade fornecida pelas interfaces.</p><h2 id="princ-pio-da-substitui-o-de-liskov"><strong>Princípio da substituição de Liskov</strong></h2><p>O princípio da substituição de Liskov declara que as subclasses devem ser substituíveis por suas classes de base.</p><p>Isso quer dizer que, se a classe B for uma subclasse da classe A, devemos poder passar um objeto da classe B para qualquer método que espere um objeto da classe A e o método não deverá produzir resultados estranhos, nesse caso.</p><p>Esse é o comportamento esperado, pois, quando usamos a herança, levamos em conta que a classe filha herda tudo o que a superclasse tem. A classe filha estende o comportamento, mas nunca o reduz.</p><p>Portanto, quando uma classe não obedece esse princípio, isso causa alguns bugs ruins e difíceis de detectar.</p><p>O princípio de Liskov é fácil de entender, mas difícil de detectar no código. Vamos dar uma olhada em um exemplo para entender melhor.</p><pre><code class="language-java">class Retangulo {
	protected int largura, altura;

	public Retangulo() {
	}

	public Retangulo(int largura, int altura) {
		this.largura = largura;
		this.altura = altura;
	}

	public int getLargura() {
		return largura;
	}

	public void setLargura(int largura) {
		this.largura = largura;
	}

	public int getAltura() {
		return altura;
	}

	public void setAltura(int altura) {
		this.altura = altura;
	}

	public int getArea() {
		return largura * altura;
	}
}</code></pre><p>Temos uma classe Retangulo simples, e uma função <strong><strong>getArea </strong></strong>que retorna a área do retângulo.</p><p>Agora, decidimos criar outra classe para os quadrados. Como você deve saber, um quadrado é apenas um tipo de retângulo onde a largura é igual à altura.</p><pre><code class="language-java">class Quadrado extends Retangulo {
	public Quadrado() {}

	public Quadrado(int tamanho) {
		largura = altura = tamanho;
	}

	@Override
	public void setLargura(int largura) {
		super.setLargura(largura);
		super.setAltura(largura);
	}

	@Override
	public void setAltura(int altura) {
		super.setAltura(altura);
		super.setLargura(altura);
	}
}</code></pre><p>Nossa classe Quadrado estende a classe Retangulo. Definimos que altura e largura têm o mesmo valor no construtor, mas não queremos que o usuário (aquele que usar nossa classe em seu código) altere altura e largura de maneira a poder violar a propriedade do quadrado.</p><p>Assim, sobrescrevemos os <em>setters</em> de ambas as propriedades sempre que uma delas é alterada. Ao fazer isso, no entanto, acabamos de violar o princípio da substituição de Liskov.</p><p>Vamos criar uma classe <em>main</em> para realizar testes na função <strong><strong>getArea</strong></strong>.</p><pre><code class="language-java">class Test {

   static void getAreaTeste(Retangulo r) {
      int largura = r.getLargura();
      r.setAltura(10);
      System.out.println("Área esperada de " + (largura * 10) + ", obteve " + r.getArea());
   }

   public static void main(String[] args) {
      Retangulo rc = new Retangulo(2, 3);
      getAreaTeste(rc);

      Retangulo sq = new Quadrado();
      sq.setLargura(5);
      getAreaTeste(sq);
   }
}</code></pre><p>O testador da equipe acaba de aparecer com a função de teste <strong><strong>getAreaTest</strong>e<strong> </strong></strong>e conta que a função <strong><strong>getArea </strong></strong>não passa no teste para objetos quadrados.</p><p>No primeiro teste, criamos um retângulo onde a largura é 2 e a altura é 3 e chamamos <strong><strong>getAreaTest</strong>e</strong>. O resultado é 20, como esperávamos, mas algo dá errado ao passar o quadrado. Isso ocorre por que chamamos a função <strong><strong>set</strong>Altura</strong> no teste e ela está definindo a largura também. Isso resulta em um retorno inesperado.</p><h2 id="princ-pio-da-segrega-o-da-interface"><strong>Princípio da segregação da interface</strong></h2><p>Segregação quer dizer manter as coisas separadas. O princípio da segregação da interface tem a ver com separar as interfaces.</p><p>O princípio declara que muitas interfaces específicas do cliente são melhores que uma interface de propósito geral. Os clientes não devem ser forçados a implementar uma função que não necessitam.</p><p>Esse é um princípio simples de entender e de aplicar. Vamos ver um exemplo.</p><pre><code class="language-java">public interface Estacionamento {

	void estacionarCarro();	// Diminuir contagem de vagas em 1
	void sairDaVagaComCarro(); // Aumentar contagem de vagas em 1
	void getCapacidade();	// Retornar capacidade de carros
	double calcularTaxa(Carro carro); // Retornar o preço com base no número de horas
	void pagar(Carro carro);
}

class Carro {

}</code></pre><p>Modelamos um estacionamento bem simplificado. É o tipo de estacionamento onde você paga um valor por hora. Imagine, agora, que queremos implementar um estacionamento gratuito.</p><pre><code class="language-java">public class EstacionamentoGratuito implements Estacionamento {

	@Override
	public void estacionarCarro() {
		
	}

	@Override
	public void sairDaVagaComCarro() {

	}

	@Override
	public void getCapacidade() {

	}

	@Override
	public double calcularTaxa(Carro carro) {
		return 0;
	}

	@Override
	public void pagar(Carro carro) {
		throw new Exception("Estacionamento gratuito");
	}
}</code></pre><p>Nossa interface de estacionamento era composta de 2 coisas: lógica relacionada ao estacionamento (estacionar, sair da vaga com o carro, obter a capacidade) e lógica relacionada ao pagamento.</p><p>O problema é ser muito específica. Por causa disso, nossa classe EstacionamentoGratuito foi forçada a implementar métodos relacionados ao pagamento que são irrelevantes. Vamos separar o segregar as interfaces.</p><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://www.freecodecamp.org/portuguese/news/content/images/2022/05/SOLID-Tutorial-1024x432.png" class="kg-image" alt="SOLID-Tutorial-1024x432" srcset="https://www.freecodecamp.org/portuguese/news/content/images/size/w600/2022/05/SOLID-Tutorial-1024x432.png 600w, https://www.freecodecamp.org/portuguese/news/content/images/size/w1000/2022/05/SOLID-Tutorial-1024x432.png 1000w, https://www.freecodecamp.org/portuguese/news/content/images/2022/05/SOLID-Tutorial-1024x432.png 1024w" sizes="(min-width: 720px) 720px" width="1024" height="432" loading="lazy"><figcaption>De cima para baixo e da esquerda para a direita: EstacionamentoPago | EstacionamentoPagoPorHora | Estacionamento | EstacionamentoDePagamentoConstante | EstacionamentoGratuito (todas elas são interfaces)</figcaption></figure><p>Você, agora, separou os estacionamentos. Com esse novo modelo, podemos até ir mais longe e dividir <strong>EstacionamentoPago<strong> </strong></strong>para dar suporte a tipos diferentes de pagamento.</p><p>Agora, nosso modelo é muito mais flexível, extensível e os clientes não precisam implementar lógica irrelevante, pois fornecemos somente funcionalidade relacionada ao estacionamento na interface de estacionamento.</p><h2 id="princ-pio-da-invers-o-da-depend-ncia"><strong>Princípio da inversão da dependência</strong></h2><p>O princípio da inversão da dependência declara que nossas classes devem depender de interfaces ou de classes abstratas em vez de classes concretas e de funções.</p><p>Neste <a href="https://fi.ort.edu.uy/innovaportal/file/2032/1/design_principles.pdf">artigo</a> (2000, texto em inglês), Uncle Bob resume esse princípio da seguinte maneira:</p><blockquote>"Se o princípio de aberto/fechado declara o objetivo da arquitetura orientada a objetos, o princípio de inversão da dependência declara seu mecanismo principal".</blockquote><p>Esses dois princípios, de fato, estão relacionados. Aplicamos esse padrão anteriormente enquanto discutíamos o princípio de aberto/fechado.</p><p>Queremos que nossas classes estejam abertas para extensão, por isso reorganizamos nossas dependências para que dependam de interfaces em vez de classes concretas. Nossa classe GerenteDePersistencia depende de PersistenciaDaFatura em vez de classes que implementam aquela interface.</p><h2 id="conclus-o"><strong>Conclusão</strong></h2><p>Neste artigo, começamos com a história dos princípios SOLID, depois tentamos chegar a um entendimento claro dos motivos e formas de implementar cada princípio. Nós, inclusive, refatoramos uma aplicação de faturamento simples para que ela obedecesse aos princípios SOLID.</p><p>Gostaria de agradecer a você pode usar de seu tempo para a leitura deste artigo na íntegra e espero que os conceitos apresentados tenham ficado claros.</p><p>Sugiro levar esses princípios em consideração sempre que criar, escrever e refatorar seu código, de modo que seu código seja muito mais limpo, extensível e testável.</p><p>Se estiver interessado em ler mais artigos a esse respeito, você pode assinar a lista de e-mails do <a href="https://erinc.io/">blog</a> do autor (textos em inglês) para ser notificado sempre que ele publicar um artigo novo.</p> ]]>
                </content:encoded>
            </item>
        
    </channel>
</rss>
