JavaRush /Blogue Java /Random-PT /Princípios OOP

Princípios OOP

Publicado no grupo Random-PT
Java é uma linguagem orientada a objetos. Isso significa que você precisa escrever programas Java usando um estilo orientado a objetos. E esse estilo é baseado no uso de objetos e classes no programa.

Princípios básicos de OOP:

Princípios de OOP - 1Vamos tentar, com a ajuda de exemplos, entender o que são classes e objetos, bem como aplicar na prática os princípios básicos da OOP: abstração, herança, polimorfismo e encapsulamento.

O que é um objeto?

O mundo em que vivemos consiste em objetos. Se olharmos em volta, veremos que estamos rodeados de casas, árvores, carros, móveis, louças, computadores. Todos esses itens são objetos, e cada um deles possui um conjunto de características, comportamento e finalidade específicos. Estamos acostumados com objetos e sempre os utilizamos para fins muito específicos. Por exemplo, se precisamos ir para o trabalho, usamos o carro, se queremos comer, usamos a louça e se precisamos relaxar, precisamos de um sofá confortável. A pessoa está acostumada a pensar objetivamente para resolver problemas da vida cotidiana. Essa foi uma das razões para o uso de objetos na programação, e essa abordagem de criação de programas foi chamada de orientada a objetos. Vamos dar um exemplo. Imagine que você desenvolveu um novo modelo de telefone e deseja lançar sua produção em massa. Como designer de telefone, você sabe para que serve, como funcionará e em que partes será composto (caixa, microfone, alto-falante, fios, botões, etc.). Porém, só você sabe como conectar essas peças. Porém, você não planeja produzir telefones pessoalmente, para isso conta com toda uma equipe de funcionários. Para que você não precise explicar sempre como conectar as peças do telefone, e para que todos os telefones em produção fiquem iguais, antes de começar a produzi-los, você precisará fazer um desenho em forma de um descrição da estrutura do telefone. Em OOP, tal descrição, desenho, diagrama ou modelo é chamado de classe, a partir da qual um objeto é criado quando o programa é executado. Uma classe é uma descrição de um objeto que ainda não foi criado, como um modelo geral que consiste em campos, métodos e um construtor, e um objeto é uma instância de uma classe criada com base nesta descrição.

Abstração OOP

Vamos agora pensar em como podemos passar de um objeto no mundo real para um objeto em um programa, usando o telefone como exemplo. A história deste meio de comunicação ultrapassa os 100 anos e o telefone moderno, ao contrário do seu antecessor do século XIX, é um aparelho muito mais complexo. Quando usamos um telefone, não pensamos em sua estrutura e nos processos que ocorrem dentro dele. Simplesmente usamos as funções fornecidas pelos desenvolvedores do telefone – botões ou tela sensível ao toque para selecionar um número e fazer chamadas. Uma das primeiras interfaces telefônicas era um botão que você girava para fazer uma chamada. Claro, isso não era muito conveniente. No entanto, a alça desempenhou sua função corretamente. Se você olhar para o telefone mais moderno e pioneiro, poderá identificar imediatamente os detalhes mais importantes que são importantes tanto para um aparelho do final do século 19 quanto para um smartphone ultramoderno. Isso é fazer uma chamada (discar um número) e receber uma chamada. Essencialmente, é isso que faz de um telefone um telefone e não outra coisa. Agora aplicamos o princípio da POO - destacando as características e informações mais importantes sobre um objeto. Este princípio de OOP é chamado de abstração. A abstração em OOP também pode ser definida como uma forma de representar elementos de um problema do mundo real como objetos em um programa. A abstração está sempre associada à generalização de algumas informações sobre as propriedades de objetos ou objetos, portanto o principal é separar informações significativas de informações insignificantes no contexto do problema que está sendo resolvido. Neste caso, pode haver vários níveis de abstração. Vamos tentar aplicar o princípio da abstração aos nossos telefones. Primeiramente, vamos destacar os tipos de telefones mais comuns desde os primeiros até os dias atuais. Por exemplo, eles podem ser representados na forma de um diagrama mostrado na Figura 1. Princípios de OOP - 2Agora, com a ajuda da abstração, podemos destacar informações gerais nesta hierarquia de objetos: um tipo abstrato comum de objetos - telefone, uma característica geral de o telefone - o ano de sua criação e uma interface comum - todos os telefones são capazes de receber e enviar chamadas. Aqui está o que parece em Java:
public abstract class AbstractPhone {
    private int year;

    public AbstractPhone(int year) {
        this.year = year;
    }
    public abstract void call(int outputNumber);
    public abstract void ring (int inputNumber);
}
Com base nesta classe abstrata, seremos capazes de criar novos tipos de telefones no programa usando outros princípios básicos de Java OOP, que consideraremos a seguir.

Encapsulamento

Com a ajuda da abstração destacamos o que é comum a todos os objetos. No entanto, cada modelo de telefone é individual e um pouco diferente dos outros. Como podemos traçar limites no programa e designar essa individualidade? Como podemos ter certeza de que nenhum dos usuários quebrará nosso telefone acidental ou intencionalmente ou tentará converter um modelo em outro? Para o mundo dos objetos reais, a resposta é óbvia: você precisa colocar todas as peças no corpo do telefone. Afinal, se não fizermos isso e deixarmos todo o interior do telefone e os fios que os conectam do lado de fora, com certeza haverá um experimentador curioso que desejará “melhorar” o funcionamento do nosso telefone. Para evitar tal interferência no design e operação de um objeto, a OOP usa o princípio do encapsulamento - outro princípio básico da OOP, no qual os atributos e o comportamento de um objeto são combinados em uma classe, a implementação interna do objeto fica oculta de o usuário, e uma interface aberta é fornecida para trabalhar com o objeto. O trabalho do programador é determinar quais atributos e métodos serão acessíveis publicamente e quais são implementações internas do objeto e não devem ser modificados.

Encapsulamento e Controle de Acesso

Digamos que durante a produção, informações sobre ele estejam gravadas na parte traseira do telefone: o ano de fabricação ou o logotipo da empresa do fabricante. Esta informação caracteriza este modelo de forma bastante específica - o seu estado. Podemos dizer que o desenvolvedor do telefone cuidou da imutabilidade dessa informação - dificilmente alguém pensaria em retirar a gravação. No mundo Java, o estado dos objetos futuros é descrito em uma classe usando campos, e seu comportamento é descrito usando métodos. A capacidade de alterar estado e comportamento é realizada usando modificadores de acesso a campos e métodos - private, protected, publice default(acesso padrão). Por exemplo, decidimos que o ano de criação, o nome do fabricante do telefone e um dos métodos pertencem à implementação interna da classe e não podem ser alterados por outros objetos do programa. Usando código, a classe pode ser descrita da seguinte forma:
public class SomePhone {

    private int year;
    private String company;
    public SomePhone(int year, String company) {
        this.year = year;
        this.company = company;
    }
private void openConnection(){
    //findComutator
    //openNewConnection...
}
public void call() {
    openConnection();
    System.out.println("I'm calling a number");
}

public void ring() {
    System.out.println("Дзынь-дзынь");
}

 }
Um modificador privatedisponibiliza os campos e métodos de uma classe apenas dentro dessa classe. Isso significa que privateos campos não podem ser acessados ​​de fora, nem privateos métodos podem ser chamados. Ocultar o acesso a um método openConnectiontambém nos dá a oportunidade de alterar livremente a implementação interna deste método, uma vez que é garantido que este método não será utilizado por outros objetos e não interromperá seu funcionamento. Para trabalhar com nosso objeto, deixamos os métodos abertos callutilizando ringo modificador public. Fornecer métodos públicos para trabalhar com um objeto também faz parte do mecanismo de encapsulamento, pois se o acesso a um objeto for totalmente negado, ele se tornará inútil.

Herança

Vejamos a tabela telefônica novamente. Você pode perceber que representa uma hierarquia em que o modelo localizado abaixo possui todas as características dos modelos localizados mais acima na filial, além das suas próprias. Por exemplo, um smartphone utiliza uma rede celular para comunicação (tem as propriedades de um telefone celular), é sem fio e portátil (tem as propriedades de um telefone sem fio) e pode receber e fazer chamadas (tem as propriedades de um telefone). Neste caso, podemos falar sobre herança de propriedades de objetos. Na programação, herança é o uso de classes existentes para definir novas. Vejamos um exemplo de criação de uma classe de smartphone usando herança. Todos os telefones sem fio são alimentados por baterias recarregáveis, que têm uma certa vida útil em horas. Então, vamos adicionar esta propriedade à classe de telefones sem fio:
public abstract class WirelessPhone extends AbstractPhone {

    private int hour;

    public WirelessPhone(int year, int hour) {
        super(year);
        this.hour = hour;
    }
    }
callOs telefones celulares herdam as propriedades de um telefone sem fio, também adicionamos uma implementação dos métodos e a esta classe ring:
public class CellPhone extends WirelessPhone {
    public CellPhone(int year, int hour) {
        super(year, hour);
    }

    @Override
    public void call(int outputNumber) {
        System.out.println("Calling a number" + outputNumber);
    }

    @Override
    public void ring(int inputNumber) {
        System.out.println("A subscriber is calling you" + inputNumber);
    }
}
E, por fim, a classe dos smartphones, que, diferentemente dos celulares clássicos, possui um sistema operacional completo. Você pode adicionar novos programas suportados por este sistema operacional ao seu smartphone, ampliando assim sua funcionalidade. Usando código, a classe pode ser descrita da seguinte forma:
public class Smartphone extends CellPhone {

    private String operationSystem;

    public Smartphone(int year, int hour, String operationSystem) {
        super(year, hour);
        this.operationSystem = operationSystem;
    }
public void install(String program){
    System.out.println("Installing" + program + "For" + operationSystem);
}

}
Como você pode ver, Smartphonecriamos muito pouco código novo para descrever a classe, mas obtivemos uma nova classe com novas funcionalidades. Usar o princípio de herança OOP pode reduzir significativamente a quantidade de código e, portanto, facilitar o trabalho do programador.

Polimorfismo

Se olharmos para todos os modelos de telefone, então, apesar das diferenças na aparência e design dos modelos, podemos identificar alguns comportamentos comuns neles - todos eles podem receber e fazer chamadas e possuem um conjunto bastante claro e simples de botões de controle. Aplicando um dos princípios básicos da OOP, que já conhecemos, abstração em termos de programação, podemos dizer que o objeto telefone possui uma interface comum. Portanto, os usuários de telefones podem utilizar diferentes modelos com bastante conforto usando os mesmos botões de controle (mecânicos ou de toque), sem entrar nos detalhes técnicos do dispositivo. Assim, você usa constantemente um telefone celular e pode facilmente fazer uma ligação do telefone fixo. O princípio em OOP quando um programa pode usar objetos com a mesma interface sem informações sobre a estrutura interna do objeto é chamado de polimorfismo . Vamos imaginar que em nosso programa precisamos descrever um usuário que pode usar qualquer modelo de telefone para ligar para outro usuário. Veja como fazer isso:
public class User {
    private String name;

    public User(String name) {
        this.name = name;
            }

    public void callAnotherUser(int number, AbstractPhone phone){
// here it is polymorphism - using the abstract type AbstractPhone phone in the code!
        phone.call(number);
    }
}
 }
Agora vamos descrever os diferentes modelos de telefone. Um dos primeiros modelos de telefone:
public class ThomasEdisonPhone extends AbstractPhone {

public ThomasEdisonPhone(int year) {
    super(year);
}
    @Override
    public void call(int outputNumber) {
        System.out.println("Turn the Handle");
        System.out.println("Give me the phone number, sir");
    }

    @Override
    public void ring(int inputNumber) {
        System.out.println("Phone calls");
    }
}
Telefone fixo normal:
public class Phone extends AbstractPhone {

    public Phone(int year) {
        super(year);
    }

    @Override
    public void call(int outputNumber) {
        System.out.println("I'm calling a number" + outputNumber);
    }

    @Override
    public void ring(int inputNumber) {
        System.out.println("Phone calls");
    }
}
E finalmente, um videofone legal:
public class VideoPhone extends AbstractPhone {

    public VideoPhone(int year) {
        super(year);
    }
    @Override
    public void call(int outputNumber) {
        System.out.println("I connect a video channel for the subscriber" + outputNumber );
    }
    @Override
    public void ring(int inputNumber) {
        System.out.println("You have an incoming video call..." + inputNumber);
    }
  }
Vamos criar objetos no método main()e testar o método callAnotherUser:
AbstractPhone firstPhone = new ThomasEdisonPhone(1879);
AbstractPhone phone = new Phone(1984);
AbstractPhone videoPhone=new VideoPhone(2018);
User user = new User("Andrey");
user.callAnotherUser(224466,firstPhone);
// Rotate the knob
// Tell me the number of the subscriber, sir
user.callAnotherUser(224466,phone);
//Call number 224466
user.callAnotherUser(224466,videoPhone);
//I connect the video channel for subscriber 224466
Chamando o mesmo método no objeto user, obtivemos resultados diferentes. A seleção de uma implementação específica de método calldentro de um método callAnotherUserfoi feita dinamicamente com base no tipo específico do objeto chamador durante a execução do programa. Esta é a principal vantagem do polimorfismo - a escolha da implementação durante a execução do programa. Nos exemplos de classe phone acima, usamos a substituição de método, uma técnica que altera a implementação do método definido na classe base sem alterar a assinatura do método. Isto é essencialmente uma substituição de método e é o novo método definido na subclasse que é chamado quando o programa é executado. Normalmente, ao substituir um método, é usada a anotação @Override, que informa ao compilador para verificar as assinaturas dos métodos substituídos e substituídos. Como resultado , para garantir que o estilo do seu programa esteja de acordo com o conceito de OOP e os princípios de OOP java, siga estas dicas:
  • destacar as principais características do objeto;
  • destacar propriedades e comportamentos comuns e usar herança ao criar objetos;
  • use tipos abstratos para descrever objetos;
  • Procure sempre ocultar métodos e campos relacionados à implementação interna da classe.
Comentários
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION