Alura > Cursos de Programação > Cursos de Java > Conteúdos de Java > Primeiras aulas do curso Java: aplicando a Orientação a Objetos

Java: aplicando a Orientação a Objetos

Modelando o ScreenMatch - Apresentação

Paulo: Olá! Eu sou Paulo Silveira, CEO da Alura, e estamos no curso de Orientação a Objetos com Java. É um curso muito importante para quem vai trabalhar com Java, e vai permear tudo que envolve esse paradigma, como encapsulamento, classes, herança e interfaces, além de como essas coisas se conectam.

Após o curso, você vai perceber como a orientação a objetos está em todo lugar e em todas as bibliotecas.

Eu sou um homem branco de cabelo curto preto, barba e bigode. Uso um par de óculos de armação preta e uma camiseta preta da Alura. Hoje eu estou auxiliando a Jacqueline, a instrutora principal desse curso.

Jacqueline: Obrigada, Paulo. É um prazer estar aqui novamente para darmos mais esse passo, falar de orientação a objetos, que é um paradigma de programação muito importante que quem vai mergulhar no Java precisa entender e dominar.

Eu sou uma mulher branca de cabelos loiros longos e estou usando uma camiseta azul-marinho da Alura. É um prazer acompanhar você mais uma vez nessa jornada.

Paulo: Preste atenção, pois nesse momento da orientação a objetos as coisas começam a se conectar. Toda vez que você for trabalhar com bibliotecas, seja para se conectar a webservices, consumir JSON ou XML e assim por diante, os princípios de interface e encapsulamento estarão presentes para trabalhar melhor. Foco nos estudos!

Modelando o ScreenMatch - Um modelo para representar filmes

Regras de Negócio

Jacqueline: No curso anterior, estávamos falando sobre regras e condicionais. Na hora de montar o Screen Match, a nossa plataforma de streaming, começamos a implementar algumas regras - por exemplo, emitindo uma mensagem se um filme foi lançado a partir de determinada data, ou se está ou não incluído no plano, tudo isso com condicionais.

Mas isso não está muito adequado. E se precisarmos usar isso em outro momento? Teríamos que copiar e colar esse código? É um tipo de programação meio estruturada ou procedural, o que não é muito adequado para modificação. Ao espalhar regras pelo código, tornamos mais difícil fazer manutenção da aplicação ou mesmo entender o que nossa aplicação faz.

Paulo: Por exemplo, em vários lugares da aplicação precisamos saber se um filme está incluso no plano ou se ela precisa pagar algum valor adicional, como no catálogo, quando a pessoa dá "play" (para saber se ela não "hackeou" o sistema e está assistindo sem pagar), na listagem de todos os filmes inclusos no plano e assim por diante.

Nesses casos a gente usaria o que chamamos de "Regra de Negócio", um termo até meio antigo, que consiste na regra que foi decidida para o nosso produto. Por exemplo, se o filme for recente, é necessário pagar, a não ser que o usuário tenha o plano "plus".

Essa regra pode ser alterada, assim como a Netflix e a HBOMax já mudaram suas regras anteriormente, como que filmes estão inclusos, se é necessário pagar valores adicionais o não, compartilhamento de conta, entre outras. Em uma empresa essas regras são vivas, elas mudam.

Atualmente temos essa condicional verificando se o filme está incluso no plano, mas no futuro podem entrar novas regras envolvendo outros planos, se a pessoa é cliente antiga ou não, entre outras. Ou seja, essa condicional vai ser copiada e colada em diversos outros lugares.

Com uma mudança na regra de negócios, pode ser necessário alterá-la, sendo necessário buscar em que lugares da aplicação a condicional aparece - até mesmo com um "Ctrl + F", o que não é um bom sinal, pois indica que não sabemos onde o código está.

Isso mostra que a nossa lógica está espalhada, e não em um único lugar, de uma única cápsula - encapsulada. Quando temos uma regra em um único ponto, facilitamos sua manutenção e simplificamos o nosso código.

Esse é até um dos princípios de boas práticas em orientação a objetos, apesar do termo "encapsulamento" não envolver apenas objetos. Várias metodologias de boas práticas em desenvolvimento, como Clean Code, DDD (Domain-driven Design), Design Patters e SOLID, nascem basicamente desses problemas.

Não se esqueça de que temos formações, cursos e artigos sobre boas práticas aqui na Alura!

Estamos enxergando aqui um problema: se copiarmos essa condicional em outros lugares, vamos nos perder. Como podemos resolver isso? O Java popularizou no mercado a orientação a objetos, que vem resolver esse cenário.

Jacqueline: Exatamente, Paulo. Era muito comum esse tipo de problema. Por exemplo, às vezes clicar por um menu funcionava, mas por um botão não, porque existia código espalhado. Além disso, com o tempo as pessoas desenvolvedoras vão mudando, e nem sempre quem criou aquele código fará a manutenção.

Buscar ou copiar e colar código não são boas práticas em aplicações confiáveis e de grande porte. A orientação a objetos vem nos ajudar a centralizar em um único lugar o que a nossa entidade tem de característica, de comportamento, enxergando as coisas como objetos propriamente ditos.

Nesse caso, temos um "filme" com suas características, como nome, tipo de plano, se ele está incluído ou não. Além disso, temos comportamentos, como assistir, alugar ou exibir a ficha técnica.

A ideia é começarmos o projeto do Screen Match orientado a objetos para não precisarmos fazer as regras dessa forma. Vamos criar um método que nos informará se o filme é retrô, se é lançamento, centralizando isso em um único lugar.

Criando uma classe

Paulo: Vamos começar o projeto desse curso, obviamente usando essa temática dos filmes e melhorando essas regras. Como comentamos na introdução do curso, é comum que a pessoa entenda os conceitos, mas não fiquem claros os seus casos de uso. Quando usar uma classe? Quando criar um método? Será que a classe está grande demais, pequena demais ou muito acoplada?

São dúvidas completamente naturais que vamos abordar nas aulas e exercícios, mas é necessário tempo e experiência para internalizar essas boas práticas.

Jacqueline: Exatamente. No IntelliJ, acessaremos o menu "File -> New Project" para começar um novo projeto, que chamaremos de "screenmatch". Selecionaremos as mesmas opções do outro curso, "Java" como "Language" e "IntelliJ" como "Build System", e clicaremos em "Create".

Observe que dessa vez eu não pedi o código padrão, não começaremos criando a classe com main(), pois queremos pensar na orientação a objetos. A temática do nosso projeto é trabalhar com filmes, portanto queremos criar uma forma de explicar o que é um filme - ou seja, uma classe Filme.

Clicaremos com o botão direito na pasta "src" e então em "New -> Java Class". Na janela que se abrirá, adicionaremos o nome "Filme" e pressionaremos "Enter".

Paulo: Relembrando que no dia a dia de uma empresa, mesmo no Brasil, costuma-se usar o inglês para escrever código. Aqui estamos usando "Filme" como recurso didático.

Jacqueline: Exatamente.

Filme.java

public class Filme {

}

Criamos a classe filme, mas o que é uma classe? Uma classe especifica o conteúdo de um objeto, ou seja, o que um filme tem, qual é a nossa abstração ali - inclusive, um dos pilares da orientação a objetos é a abstração. A ideia é pensarmos que características são comuns a todos os filmes. Claro que cada empresa pode ter as suas características principais, mas podemos começar definindo, por exemplo, que um filme tem um "nome".

Sendo assim, vamos definir o atributo nome como uma String.

public class Filme {
    String nome;

}

Paulo: Vale lembrar que anteriormente estávamos declarando variáveis na main(), que é um método, algo que já vamos entender. Aqui temos um cenário diferente: tudo que declararmos na classe Filme será comum a todos os filmes. Em português, estamos dizendo que "todo filme tem um nome".

Tanto que aqui não podemos executar um System.out.println(). Estamos definindo uma classe, tudo o que ela tem e tudo que ela faz.

Jacqueline: Exatamente. Vamos incluir mais algumas informações, como o anoDeLancamento como int, incluidoNoPlano como boolean, seguindo a convenção de código que aprendemos no curso anterior.

public class Filme {
    String nome;
    int anoDeLancamento;
    boolean incluidoNoPlano;

}

Lembrando que essa é uma ideia de como achamos que é um filme, não é o filme propriamente dito, assim como a planta de uma casa não é uma casa.

Paulo: Isso, é um esqueleto, um protótipo. Existem várias analogias que podemos fazer.

Jacqueline: Vamos criar mais algumas características que vão compor o nosso filme: avaliacao como double, e totalDeAvaliacoes como int.

public class Filme {
    String nome;
    int anoDeLancamento;
    boolean incluidoNoPlano;
    double avaliacao;
    int totalDeAvaliacoes;
}

Paulo: Tudo que a Jaque está fazendo é o que ela sentiu ser importante para o sistema que está desenvolvendo. Às vezes essas características não são óbvias. Será que devemos guardar o totalDeAvaliacoes? Será que precisamos do anoDeLancamento ou essa informação não é relevante para nosso sistema?

Esse é um trabalho que envolve entender os usuários da usa plataforma, a chefia do seu trabalho ou, muitas vezes, algo que vai sendo incluído ao longo do tempo, conforme as necessidades vão aparecendo. Aqui nós já temos um projeto definido, mas é bem natural que existam mudanças até criar algo estruturado assim.

Jacqueline: Exatamente, e está tudo bem. Trabalhar com código é assim mesmo, nós estamos a todo tempo incluindo coisas novas ou removendo o que não é mais usado. Aqui nós inicialmente idealizamos o que vamos precisar em um filme, mas poderíamos ter também a duracaoEmMinutos, por exemplo.

public class Filme {
    String nome;
    int anoDeLancamento;
    boolean incluidoNoPlano;
    double avaliacao;
    int totalDeAvaliacoes;
    int duracaoEmMinutos;
}

Paulo: Temos até que tomar cuidado, pois essa abstração poderia ser infinita, incluindo atores principais, qual a produtora, quem é diretor ou diretora, se o filme é preto e branco ou colorido... É necessário ter um limite. Essas modelagens de classe também demandam certa experiência para ir melhorando e refinando.

Jacqueline: E geralmente é uma coisa que fazemos com base em uma conversa em equipe. Você sabe quais são os requisitos, o que é necessário implementar, e os atributos vão nascer conforme a necessidade. Aqui estamos somente criando um esboço.

Essa é a nossa classe, o modelo de como será um filme. A seguir, conversaremos sobre o conceito de objeto e qual a diferença entre classe e objeto.

Anteriormente, para termos um filme como "Top Gun" em nossa aplicação, criávamos uma variável e passávamos o nome. Mas e agora, como criaremos os filmes?

Paulo: Ótimo, porque aqui só criamos o modelo. Com isso aqui não é possível fazer nada, inclusive não conseguiremos rodar esse código - afinal, essa classe não tem um método main(). Continuaremos a partir daqui no próximo vídeo.

Modelando o ScreenMatch - Atribuindo valores ao nosso filme

Jacqueline: Está pronto o nosso modelo de classe e agora vamos de fato começar a utilizá-lo.

Quando criamos o projeto, foi criada uma classe Main com o método main() que anteriormente dissemos que não iríamos criar. Vamos renomeá-la clicando com o botão direito e em seguida em "Refactor -> Rename" (atalho "Shift + F6"). Chamaremos o arquivo de "Principal".

Paulo: Caso não tenha aparecido para você uma classe com esse método, você criar uma classe Principal e digitar psvm para autocompletar com o esqueleto da classe.

public class Principal {
    public static void main(String[] args) {
        System.out.println("Hello World!");
    }
}

Jacqueline: Vamos apagar o System.out.println(), que não usaremos agora. A ideia é de fato usarmos a nossa classe Filme. Anteriormente, quando queríamos criar uma variável, bastava informar o tipo - por exemplo, int - seguido do nome da variável e o valor que ela receberia.

int valor = 555;

Porém, ao criar uma classe Filme, nós também criamos um tipo propriamente nosso. Passaremos esse tipo como qualquer outro, seguido do nome da variável, nesse caso meuFilme.

Filme meuFilme = 

Paulo: Aqui é um nome de variável, pode ser qualquer um, como filmeLegal, filmeUm e assim por diante. Já a parte da esquerda, onde declaramos o tipo Filme, deve ter exatamente o nome da classe. Não poderia ser, por exemplo, filme com F minúsculo, pois a classe é chamada de Filme com F maiúsculo.

Jacqueline: Exatamente. Para criarmos efetivamente um novo objeto do tipo Filme, usaremos a instrução new Filme().

Filme meuFilme = new Filme();

Instanciação de objetos

Anteriormente nós estudados os chamados tipos primitivos. Aqui temos um tipo por referência, em algum lugar da memória da máquina foi criado um espaço reservado para um objeto chamado Filme.

Paulo: Isto é, um objeto chamado Filme que está na memória e possui um "espaço" para o nome, para o ano de lançamento e cada um daqueles itens que chamamos de atributos.

Jacqueline: E a minha variável meuFilme sabe o endereço desse objeto na memória.

Paulo: Essa é uma coisa que a gente nem precisa saber, no dia a dia acaba não aparecendo muito.

Jacqueline: Isso, não importa. Se a gente fizer um System.out.println(), conseguiremos imprimir o endereço, mas não é necessariamente algo que precisamos saber. Nós sabemos que o objeto e o seu espaço na memória existem, e conseguimos manipular esse objeto.

Paulo: Sempre aparece aquela dúvida: por que eu preciso repetir Filme na esquerda e na direita? Acho que precisamos de mais prática para entender, mas a parte na direita é onde criamos o espaço na memória, e na esquerda estamos informando a necessidade de uma variável que saiba referenciar um objeto do tipo Filme. São coisas bem distintas que estão acontecendo.

Jacqueline: E como vamos alimentar os atributos que um filme tem? Se chamarmos a variável meuFilme seguida de um ponto, serão exibidos os atributos ela: avaliacao, incluidoNoPlano, nome e assim por diante.

Podemos, então, passar valores para esses atributos. Começaremos com meuFilme.nome, que receberá o valor "O poderoso chefão".

Filme meuFilme = new Filme();
meuFilme.nome = "O poderoso chefão";

Podemos repetir o processo para cada um dos atributos.

Filme meuFilme = new Filme();
meuFilme.nome = "O poderoso chefão";
meuFilme.anoDeLancamento = 1970;
meuFilme.duracaoEmMinutos = 180;

Paulo: E essa sintaxe do ponto é comum em diversas linguagens quando queremos acessar algo de alguém. Já fizemos, por exemplo, o System.out e o leitor.nextLine() de modo a acessarmos alguns métodos.

Jacqueline: E o que acontece se fizermos a impressão do meuFilme usando o System.out.println()? Vamos testar.

public class Principal {
    public static void main(String[] args) {
        Filme meuFilme = new Filme();
        meuFilme.nome = "O poderoso chefão";
        meuFilme.anoDeLancamento = 1970;
        meuFilme.duracaoEmMinutos = 180;
        
        System.out.println(meuFilme);
    }
}

Filme@65ab7765

Temos esse resultado estranho, que tem um pouco de relação com aquilo que citamos. Ele está informando a classe principal e qual o endereço dessa referência, o que não é exatamente o que queríamos ver. Futuramente vamos entender com mais profundidade de onde vem esse resultado.

O que importa nesse momento é imprimirmos as informações desejadas - por exemplo, se queremos o nome do filme, usaremos meuFilme.nome.

public class Principal {
    public static void main(String[] args) {
        Filme meuFilme = new Filme();
        meuFilme.nome = "O poderoso chefão";
        meuFilme.anoDeLancamento = 1970;
        meuFilme.duracaoEmMinutos = 180;
        
        System.out.println(meuFilme.nome);
    }
}

Paulo: Eu acesso o atributo do objeto.

Jacqueline: Exatamente. Se quisermos o ano de lançamento, usaremos meuFilme.anoDeLancamento, e assim por diante.

public class Principal {
    public static void main(String[] args) {
        Filme meuFilme = new Filme();
        meuFilme.nome = "O poderoso chefão";
        meuFilme.anoDeLancamento = 1970;
        meuFilme.duracaoEmMinutos = 180;
        
        System.out.println(meuFilme.nome);
        System.out.println(meuFilme.anoDeLancamento);
    }
}

O poderoso chefão

1970

Ao fazermos a execução, temos como retorno os dados que foram efetivamente cadastrados. Essa é a forma com a qual começamos a instanciar objetos, criando uma nova referência a um objeto para trabalhar os seus dados.

Esse é o primeiro passo, criar os atributos, saber instanciar um objeto e passar os valores para seus atributos. No próximo vídeo vamos falar um pouco sobre métodos, como definir o que um objeto pode fazer.

Paulo: Posso tirar uma dúvida antes de irmos para a próxima aula? O que aconteceria se fizéssemos Filme.nome = "Top Gun", por exemplo?

Filme meuFilme = new Filme();
meuFilme.nome = "O poderoso chefão";
meuFilme.anoDeLancamento = 1970;
meuFilme.duracaoEmMinutos = 180;

System.out.println(meuFilme.nome);
System.out.println(meuFilme.anoDeLancamento);
Filme.nome = "Top Gun"

Jacqueline: Nessa situação o IntelliJ nos informa um erro:

Non-static field 'nome' cannot be referenced from a static context

Paulo: A gente até vai entender melhor esse erro depois, mas é justamente o que estávamos falando. A classe Filme é um modelo, uma especificação. Não podemos atribuir a ela um valor para a propriedade nome, afinal ela só especifica que um filme deve ter um nome.

É necessário criar um objeto desse tipo, um filme propriamente dito, e então conseguiremos alterar o seu nome. Acessar o atributo de um objeto pelo nome da classe não faz sentido.

Essa é a diferença entre classe e o modelo. A partir da classe, que é o modelo, podemos criar diversos filmes, o que inclusive faz parte dos exercícios.

Jacqueline: Exatamente. No próximo vídeo vamos falar sobre os métodos.

Sobre o curso Java: aplicando a Orientação a Objetos

O curso Java: aplicando a Orientação a Objetos possui 196 minutos de vídeos, em um total de 55 atividades. Gostou? Conheça nossos outros cursos de Java em Programação, ou leia nossos artigos de Programação.

Matricule-se e comece a estudar com a gente hoje! Conheça outros tópicos abordados durante o curso:

Aprenda Java acessando integralmente esse e outros cursos, comece hoje!

Conheça os Planos para Empresas