quarta-feira, 19 de fevereiro de 2014

Encapsulamento, Polimorfismo, Herança – Parte 01



O paradigma da Orientação a Objetos traz um ganho significativo na qualidade da produção de software, porém grandes benefícios são alcançados quando as técnicas de programação OO são colocadas em prática com o uso de uma tecnologia que nos permita usar todas as características da OO; além de agregar à programação o uso de boas práticas de programação e padrões de projeto, design patterns. Um objeto é uma entidade do mundo real que tem uma identidade. Objetos podem representar entidades concretas, um arquivo no meu computador, uma bicicleta ou entidades conceituais, uma estratégia de jogo, uma política de escalonamento em um sistema operacional. Cada objeto ter sua identidade significa que, dois objetos são distintos mesmo que eles apresentem exatamente as mesmas características.

Objetos são instâncias de classes, que determinam qual informação um objeto contém e como ele pode manipulá-la. Um programa desenvolvido com uma linguagem de programação orientada a objetos manipula estruturas de dados através dos objetos da mesma forma que um programa em linguagem tradicional utiliza variáveis.

Em orientação a objeto, uma classe é uma estrutura que abstrai um conjunto de objetos com características similares. Uma classe define o comportamento de seus objetos através de métodos e os estados possíveis destes objetos através de atributos. Em outros termos, uma classe descreve os serviços providos por seus objetos e quais informações eles podem armazenar. Classes não são diretamente suportadas em todas as linguagens, e são necessárias para que uma linguagem seja orientada a objetos. A programação orientada a objeto tem três pilares, Encapsulamento, herança e polimorfismo, mas antes de tratarmos destes assuntos se faz necessário o entendimento de alguns conceitos iniciais para que tudo possa ficar claro à medida que a aula for dando andamento.

Uma interface nada mais é do que um bloco de código definindo um tipo e os métodos e atributos que esse tipo deve possuir. Na prática o que acontece é que qualquer classe que quiser ser do tipo definido pela interface deve implementar os métodos dessa interface. A interface não contém nenhum código de implementação, apenas assinaturas de métodos e/ou atributos que devem ter seu código implementado nas classes que implementarem essa interface. A Interface define um padrão para especificação do comportamento de classes. Porém, os métodos de uma interface são implementados de maneira particular a cada classe; ou seja, permitem expressar comportamento sem se preocupar com a implementação. Uma interface não possui atributos. Uma classe pode implementar várias interfaces, mas pode ter apenas uma superclasse.
1.            public class TV {
2.            private int tamanho;
3.            private int canal;
4.            private int volume;
5.            private boolean ligada;
6.            public TV(int tamanho) {
7.            this.tamanho = tamanho;
8.            this.canal = 0;
9.            this.volume = 0;
10.         this.ligada = false;
11.         }
12.         // abaixo vem todos os métodos construtores get e set...
13.         // Encapsulamento
14.         }

1.            public interface ControleRemoto {
2.            void mudarCanal(int canal);
3.            void aumentarVolume (int taxa);
4.            void diminuirVolume (int taxa);
5.            boolean ligar();
6.            boolean desligar();
7.            }

Agora temos nossa interface e a definição do que é a TV, vamos desenvolver duas TVs diferentes, imaginando que fossem duas marcas completamente distintas e que uma não tem nenhuma relação com a outra. Como ambas as TVs irão implementar a interface ControleRemoto, então, no corpo das duas classes devem conter todos os métodos da interface. No exemplo usado abaixo, apenas implementaremos os métodos ligar e desligar.

A TV modelo 001 é uma TV simples, sem muitos recursos que quando acionarmos o comando desligar irá simplesmente desligar.
1.            public class ModeloTV001 extends TV implements ControleRemoto {
2.            public final String MODELO = "TV001";
public ModeloTV001(int tamanho) {

3.            super(tamanho);
4.            }
5.            public void desligar() {
6.            super.setLigada(false);
7.            }
8.            public void ligar() {
9.            super.setLigada(true);
10.         }
11.         public void aumentarVolume(int taxa) { }
12.         public void diminuirVolume(int taxa) { }
13.         public void mudarCanal(int canal) { }
14.         }
O modelo X é uma TV mais moderna, que quando acionarmos o comando desligar irá apresentar uma mensagem dizendo "tchau!".
1.            public class ModeloX extends TV implements ControleRemoto {
2.            public final String MODELO = "TV-X";
3.            public ModeloSDX(int tamanho) {
4.            super(tamanho);
5.            }
6.            public void desligar() {
7.            System.out.println("Obrigado por Utilizar a Televisão!");
8.            super.setLigada(false);
9.            }
10.         public void ligar() {
11.         super.setLigada(true);
12.         }
13.         public void aumentarVolume(int taxa) { }
14.         public void diminuirVolume(int taxa) { }
15.         public void mudarCanal(int canal) { }
16.         }
Como pode ser visto, ambos possuem a mesma ação que é desligar, porém cada um executa de forma diferente.
1.            public class ExemploInterfaceamento {
2.            public static void main(String[] args) {
3.            ModeloTV001 tv1 = new ModeloTV001(21);
4.            ModeloSDX tv2 = new ModeloX (42);
5.            tv1.ligar();
6.            tv2.ligar();
7.            System.out.print("TV1 - modelo " + tv1.MODELO + " está ");
8.            System.out.println(tv1.isLigada() ? "ligada" : "desligada");
9.            System.out.print("TV2 - modelo " + tv2.MODELO + " está ");
10.         System.out.println(tv1.isLigada() ? "ligada" : "desligada");
11.         // ambas as TVs estão ligadas e vamos desligá-las
12.         System.out.println("Desligando modelo " + tv1.MODELO);
13.         tv1.desligar();
14.         System.out.println("Desligando modelo " + tv2.MODELO);
15.         tv2.desligar();
16.         }
17.         }

Uma classe abstrata nada mais é do que uma especificação conceitual para outras classes. Isso que dizer que nunca iremos instanciá-la. Ela apenas fornece um modelo para geração de outras classes. Esta nunca está completa, ou seja, servirá apenas para criação de funcionalidades genéricas de casses filhas. Podemos também chamar as classes abstratas de super classe. Por exemplo, é sabido que Pessoa Física e Pessoa Jurídica possuem o atributo nome como uma informação em comum. Dentre dezenas de informações, a mais comentada que gera uma grande diferença entre as duas são CPF para Física e CNPJ para Jurídica. Este é um bom motivo para que se defina uma classe abstrata. Ao invés de definir o atributo nome para as duas classes, o que gera redundância, cria-se uma classe abstrata e insere um atributo nome dentro dela. Feito isso, haverá a herança das propriedades para as classes filhas, Física e Jurídica, desta maneira ficam definidas dentro de Física o atributo CPF e para Jurídica o CNPJ. O atributo nome vem automaticamente pela super classe.
1.            public abstract class Pessoa{
2.            protected String xNome;
3.            protected Pessoa(){
4.            xNome = "Sem nome";
5.            }
6.            protected Pessoa(String nome){
7.            xNome = nome;
8.            }
9.            public String getNome(){
10.         return xNome;
11.         }
12.         }
13.         public class Fisica extends Pessoa{
14.         private String xCPF;
15.         public Fisica(){
16.         super();
17.         }
18.         public Fisica(String nome){
19.         super(nome);
20.         }
21.         public String getCPF(){
22.         return  xCPF;
23.         }
24.         }
25.         public class Juridica extends Pessoa{
26.         private String xCNPJ;
27.         public Juridica(){
28.         super();
29.         }
30.         public Juridica(String nome){
31.         super(nome);
32.         }
33.         public String getCNPJ(){
34.         return  xCNPJ;
35.         }
36.         public String getNome(){
37.         return super.getNome();
38.         }
39.         }
40.         class Principal{
41.         public static void main(String[] args){
42.         Fisica pessoa1 = new Fisica("Daniel");
43.         System.out.println (pessoa1.getNome());
44.         System.out.println (pessoa1.getCPF());
45.         Juridica pessoa2 = new Juridica();
46.         System.out.println (pessoa2.getNome());
47.         System.out.println (pessoa2.getCNPJ());
48.         }
49.         }
Em programação orientada a objetos, modificador de acesso, é a palavra-chave que define como um atributo, método, ou classe será visto no contexto que estiver inserido.
Geralmente, utilizam-se modificadores de acesso para privar os atributos do acesso direto, tornando-os privados, e implementa-se métodos públicos que acessam e alteram os atributos. Métodos privados geralmente são usados apenas por outros métodos que são públicos, e que podem ser chamados a partir de outro objeto da mesma classe a fim de não repetir código em mais de um método.
Para utilizar estes modificadores de acesso, basta que o escreva antes do nome do atributo, método ou classe.
·                Public: O modificador public deixará visível a classe ou membro para todas as outras classes, subclasses e pacotes do projeto Java.
·                Protected: O modificador protected deixará visível o atributo para todas as outras classes e subclasses que pertencem ao mesmo pacote. A principal diferença é que apenas as classes do mesmo pacote têm acesso ao membro. O pacote da subclasse não tem acesso ao membro.
·                Private: O modificador private deixará visível o atributo apenas para a classe em que este atributo se encontra.
Package-Private: é o modificador padrão quando outro não é definido. Isto torna acessível na própria classe, nas classes e subclasses do mesmo pacote. Ele geralmente é utilizado para construtores e métodos que só dever ser invocados pelas classes e subclasses do pacote, constantes estáticas que são úteis apenas dentro do pacote em que estive inserido.
Exemplo:
1.         public class MinhaClasse { //classe public
2.         private int inteiro; //atributo inteiro private
3.         protected float decimal; //atributo float protected
4.         boolean ativado; //atributo booleano package-private
5.         }
Por padrão, a linguagem Java permite acesso aos membros apenas ao pacote em que ele se encontra. De forma ilustrativa, abaixo está uma tabela demonstrando todas estas características.





Um dos grandes diferenciais da programação orientada a objetos em relação a outros paradigmas de programação que também permitem a definição de estruturas e operações sobre essas estruturas estão no conceito de herança, mecanismo através do quais definições existentes podem ser facilmente estendidas. Juntamente com a herança deve ser enfatizada a importância do polimorfismo, que permite selecionar funcionalidades que um programa irá utilizar de forma dinâmica, durante sua execução.


Nenhum comentário:

Postar um comentário

O que achou dessa postagem?