Executando verificação de segurança...
6

[ Conteúdo ] Programação orientado a objetos ( javaScript )

Introdução:

Hoje trago a vocês um pouco sobre o que é e como funciona Programação orientada a objetos (OOP). Os exemplos que eu vou utilizar não vão ser necessariamente em javaScript e sim pseudocodigo, o mesmo da documentação do MDN. Mas sempre tendo em mente que o foco é javaScript.

O que é programação orientada a objetos?

O que é exatamente, imagino que a descussão se extenda bastante... O que posso afirmar com toda a certeza é que programação orientada a objetos é um paradigma fundamental em diversas linguagens incluindo C++ e Java. Não vou me aprofundar muito sobre tudo que envolve orientação a objeto, que é muito extenso. A ideia é uma visão geral da coisa.

Podemos dividir OOP em 4 partes: Classes, Instância, herança e encapsulação. Vou descrever todos esses conceitos de forma geral logo adiante.

OOP em javaScript é diferente do modelo mais clássico. Segundo a documentação é mais fléxivel e poderoso... Comentem

Classes e Instâncias

Quando vamos modelar um problema em termos de orientação a objeto, devemos abstrair as definições em diversos pedaços e ir montando o nosso sistema. Podemos representar ele de diversos tipos que queremos em nosso nosso sistema.

Vamos supor que estamos em uma escola, e queremos representa-la utilizando o paradigma de OOP. Então, em uma escola temos professores, que podem avaliar alunos e também tem um nome. Além disso ele pode se apresentar e obviamente ele é professor de alguma matéria, então teria que adicionar mais uma propriedade. Representado em pseudocodigo ficaria assim:

class Professor
    properties
        name
        teaches
    methods
        grade(paper)
        introduceSelf()

Onde temos name e teaches como uma propriedade, e temos dois métodos que são grade() e introduceSelf()

A classe por si só não faz nada sozinha. Se faz necessário um construtor e instância-la para podemos fazer algo com esta classe desta forma:

class Professor
    properties
        name
        teaches
    constructor
        Professor(name, teaches)
    methods
        grade(paper)
        introduceSelf(

Geralmente o nome do construtor é o mesmo da classe. O construtor leva dois parâmetro, ambos são propriedades, pois queremos que vá mudando para cada professor. Os métodos são funções que vão fazer algo com base nas propriedades (geralmente), portanto quase nunca mexe-mos nisso.

Vamos instânciar o construtor:

walsh = new Professor("Walsh", "Psychology");
lillian = new Professor("Lillian", "Poetry");

walsh.teaches; // 'Psychology'
walsh.introduceSelf(); // 'My name is Professor Walsh and I will be your Psychology professor.'

lillian.teaches; // 'Poetry'
lillian.introduceSelf(); // 'My name is Professor Lillian and I will be your Poetry professor.'

É importante notar que se você utiliza javaScript, já deve ter ouvido falar de prototype... É um mecanismo que vou explicar em uma página diferente, mas esteja ciente que essa é uma diferença fundamental do javaScript para outros linguagens baseadas em OOP.

No código acima, estamos criando duas instâncias da classe professor

Herança

Em uma escola não tem somente professores, mas tem alunos também. E poderiamos criar uma outro classe dessa forma para estudantes:

class Student
    properties
        name
        year
    constructor
        Student(name, year)
    methods
        introduceSelf

Mas, alguma desses propriedades são as mesmas que tem na classe professor, vamos repeti-las...? A resposta é: definitavamente não! É gasto de memória atoa. Podemos fazer que uma classe herde propriedades de outra classe para evitar essa repetição.

Se abstrairmos ainda mais o conceito de escola, professores e alunos são pessoas, então podemos criar uma clase chamada Person e passar propriedades que são comuns para Studant e Professor.

class Person
    properties
        name
    constructor
        Person(name)
    methods
        introduceSelf()

class Professor : extends Person
    properties
        teaches
    constructor
        Professor(name, teaches)
    methods
        grade(paper)
        introduceSelf()

class Student : extends Person
    properties
        year
    constructor
        Student(name, year)
    methods
        introduceSelf()

Note que Professor e Studant estão herdando a propriedade name de Person. Pense em Person como um pai e que Professor e Studant são filhos de Person

Assim, declaramos name apenas uma vez evitando repetir uma mesma propriedade que faz a mesma coisa.

Note que os métodos são repetidos. Isso é porque os três querem se apresentar, mas de maneiras diferentes.

walsh = new Professor("Walsh", "Psychology");
walsh.introduceSelf(); // 'My name is Professor Walsh and I will be your Psychology professor.'

summers = new Student("Summers", 1);
summers.introduceSelf(); // 'My name is Summers and I'm in the first year.'

Podemos implementar um valor padrão para Person

pratt = new Person("Pratt");
pratt.introduceSelf(); // 'My name is Pratt.'

Está característica de um mesmo método ter o mesmo nome, mas diferentes implementações, se chama polimorfismo.

Encapsulação:

Encapsulação é uma característica muito útil para controlar o que é disponível para outros códigos ou não. Objetos prover uma interface para outros código que querem usar, eles, mas mantendo seu próprio estado interno. O objeto tem um estado interno mantido privado, o que quer dizer que nenhum outro objeto pode acessar seus métodos.

Isso é útil quando queremos alterar uma implementação interna sem ter que procurar e atualizar todas as propriedade em código. É como um firewall entre objetos para o resto do sistema.

Vamos supor que queremos filtrar os alunos, queremos que apenas alunos que esteja estejam acima do primeiro ano do ensino médio, poderiamos fazer algo assim:

if (student.year > 1) {
  // allow the student into the class
}

O problema aqui é que se quisermos mudar isso depois? E se quisermos adicionar mais condições a longo prazo? Ou se quiser tomar várias outras ações com base nisso? Teríamos que alterar tudo manualmente para cada condição que utilize esse trecho de código.

Para contornar isso podemos utilizar um método que implementa uma lógica para isso:

class Student : extends Person
    properties
       year
    constructor
       Student(name, year)
    methods
       introduceSelf()
       canStudyArchery() { return this.year > 1 }
if (student.canStudyArchery()) {
  // allow the student into the class
}

Agora se quisermos mudar, apenas mudamos a lógica do método, que vai impactar em todas as condionais que utilizam essa lógica, alías, vai impactar tudo que utilize essa mesma lógica!

Isso é uma das possíbilidades de encapsulação, mas não é a única. Aqui vou mostrar que em algumas linguagens é permitido deixar propriedades privadas impedindo outros objetos utilizarem essa propriedade.

class Student : extends Person
    properties
       private year
    constructor
        Student(name, year)
    methods
       introduceSelf()
       canStudyArchery() { return this.year > 1 }

student = new Student('Weber', 1)
student.year // error: 'year' is a private property of Student

Conclusão

ISso foi o básico do básico por trás de OOP. Se cometi algum eventual erro, por favor, me corrijam!.

Carregando publicação patrocinada...
7

Sei que a ideia do post é ser um guia básico, mas de qualquer forma é uma ótima oportunidade pra esclarecer novamente uma coisa muito importante:

Não existe uma definição única, canônica, universal e livre de controvérsias sobre Orientação a Objetos. A definição dada acima é uma das existentes, mas na realidade o buraco é mais embaixo.

Já respondi sobre isso aqui, e sugiro ler e seguir todos os links do texto para se aprofundar no tema.

Mas só pra resumir:

Existem várias vertentes (ou "escolas", se preferir) de Orientação a Objetos, e a mencionada no texto é apenas uma delas - provavelmente a mais popular, e talvez por isso muita gente acredita que é a única. As definições mais conhecidas são a de Alan Kay e Bjarne Stroustrup (respectivamente, à esquerda e direita na imagem abaixo):

Alan Kay e Bjarne Stroustrup, cada um com sua definição de OO

Alan Kay é o cara que cunhou o termo "Orientação a Objetos", mas ironicamente a definição dele é diferente da que está no texto. Ele definiu, entre outras coisas, que "tudo é um objeto" (o que excluiria Java como linguagem orientada a objeto, só pra ficar em um exemplo), e que eles se comunicam via troca de mensagens.

Ou seja, nada de herança e encapsulamento (e faltou mencionar polimorfismo, que é outra que sempre aparece nesses "guias básicos"). Essas características se aproximam muito mais da definição de Bjarne Stroustrup, que basicamente pegou o mesmo termo e "ressignificou". No fim, acabou virando a definição mais conhecida.

Isso não quer dizer que o post está errado. Mas é importante mencionar que orientação a objetos é bem mais complexo que isso, e mesmo a sua definição exata é controversa. Por exemplo, não é obrigatório ter classes, tanto que dá pra fazer POO em C. A classe é apenas um mecanismo que facilita.

Vale lembrar que a rigor, JavaScript não tem classes. Apesar de ter a palavra chave class, ela é apenas um syntax sugar, pois por baixo dos panos continua tendo protótipos e funções construtoras.

3

Para complementar além disso, que é fundamental postar aqui, conforme colocado na postagem original, OOP não é fundamental em C++, e embora popular, muitos códigos são feitos sem nada disso. Alguns ambientes é proibido o uso de OOP, até porque a metaprogramação de C++ é tão poderosa que permite obter quase o mesmo sem os mecanismos tradicionais de OO.

Até em Java ele tem papel menor do que alguns acreditam. E em C# está tgendo cada vez menos, assim como Java tem diminuído a importância, ainda que mais lentamente e com menos barulho. As linguagens mais novas têm abandonado de vez. Não que isso seja o mais certo a fazer, mas faz algum sentido.

Manter algo privado não é encapsulamento. Isto é information hidden. Encapsulamento é manter tudo o que é necessário em um mesmo invólucro, em geral, a classe, então estado e comportamento está lá sem precisar de nada extra.

Quase todos exemplos básicos de herança monstram o mecanismo e não como a herança deve ser aplicada no mundo real. Hoje se fala mais em composição do que herança, de tanto que é usada errada. O exemplo mostrado é visto muito em livros, não é de uso real. Por isso falo que as pessoas deveriam evitar um pouco OOP, pelo menos até entenderem certo. QUando treina o erro, é ele que fará para sempre. E passará para frente.

Geralmemente quando se fala em herança se fala em polimorfismo, até porque sem ele a herança fica muito limitada e começa nem fazer sentido.

OOP pode ser usada sem classes, e JS é uma das linguagens que permitem isso. Embora instância seja necessário, não é um pilar de OO. Inclusive existem instâncias em 100% de qualquer outra coisa de programação que não seja OO.

E para terminar de complementar algo que não tem nessa imagem e que o Alan Kay batia na tecla, era o uso do early binding, que geralmente apenas linguagens de script possuem. C++, Java, C#, Deplhi, Kotlin, Swift, D, F#, Scala, etc., só por isso já não podem ser OO de acordo com o biólogo, apesar de algumas permiterem de forma heterodoxa.

Observou? Faz sentido para você?

Espero ter ajudado. Em geral estou à disposição na plataforma (sem abusos :D)


Farei algo que muitos pedem para aprender a programar corretamente, gratuitamente. Para saber quando, me segue nas suas plataformas preferidas. Quase não as uso, não terá infindas notificações (links aqui).

2

Um erro do ensino de OOP, gerou grandes problemas mais tarde.
Pessoas acham que OOP é só uma coisa e de um jeito.

Sempre que posso faço o mesmo que você, mostro esse artigo e falo que existem mais definições de OOP!

0
-4

Falar de OOP em JS sem falar e mostrar como funciona OOP prototipica é um erro grave!
É sempre preciso falar da OOP prototipica como ela funciona e comparar com a OOP classica que JS implementa!