Desenvolvedores.Net - TechBlog

Herança (POO)

6
1 Estrela2 Estrelas3 Estrelas4 Estrelas5 Estrelas (6 votos, média: 4,83 de 5)
Loading...
29 de janeiro de 2011
Para um melhor entendimento deste Artigo veja o Índice (Programação Orientada a Objetos)

Herança

Iremos entrar agora em um tópico que teremos muito o que discutir. Tentarei ser o mais simples , claro e objetivo.
Mas antes de falarmos sobre herança, iremos falar sobre a hierarquia das classes.

Hierarquia

Quando vamos trabalhar com muitas classes, temos que ter em mente a hierarquia (ordem) que estas classes deverão seguir.

Por exemplo:

Não poderemos ter os filhos antes dos pais e antes dos avós. A hierarquia correta para este tipo de classe seria:

Avô -> Pai -> Filho



(quando ví esta imagem, não resisti. Serve perfeitamente para o exemplo de hierarquia)

Assim temos a hierarquia bem definida dentro de nossas classes.

Transformando isso em programação teríamos generalização e especialização.

Como foi visto, a classe mais ao topo da hierarquia é a generalização, enquanto a última classe é a mais especializada.
No diagrama de seqüencia abaixo, podemos ver que as classes mais a esquerda são as genéricas e as mais a direita são as especializadas.

Agora vamos tratar dos tipos de herança que podemos ter.

Herança de Implementação

A herança de implementação é aquela onde herdamos todo o código da classe Pai, não precisamos reescrever código para utilizá-lo, estamos falando de reutilização de código.

Caso desejamos subsitituir um método da classe pai devemos usar overriding, como foi discutido em Definição (Intermediário).

Creio que a herança de implementação é a mais usada, pois herda a assinatura e os métodos da classe pai.

Herança de Interface

Caso não conheçam Interface e Abstração leiam este tópico.

A herança de interface é útil quando precisamos:

  • agrupar as nossas classes dentro de um mesmo contexto;
  • Na programação genérica (veja: Tipos Genéricos (Generics) );
  • Outros que vocês irão descobrir com o tempo;

Na herança de interface apenas herdamos as assinaturas de métodos e propriedades ao contrário da herança de implementação que além de herdar  as assinaturas herdamos também seu código, logo, no caso da interface temos que escrever o código do método ou propriedade.

Agregação

A agregação define uma dependência fraca entre as classes, isto quer dizer que os outros objetos continuam existindo mesmo que o todo for removido.
Podemos dizer que uma classe agregada (o todo) é montada com um conjunto de componentes (as partes).

Como exemplo vamos usar um carro.
Em nosso carro (classe agregada, o todo) temos os componentes (as partes), rodas, portas, motor.
Se desmontarmos o carro, as partes (rodas, portas, motor) continuaram a existir e poderão ser usadas em outro carro.

Composição

A composição define uma dependência forte entre as classes, isto quer dizer que se o todo deixar de existir as suas partes também deixaram de existir.

Exemplo:
Uma revista em quadrinhos, ela é composta por suas páginas. Se o todo, a revista, deixar de existir, suas páginas não farão sentido.

Como outro exemplo podemos citar um pedido e seus itens. Esta ligação é forte, logo é uma composição. Os itens não fariam sentido sem o Pedido. Se excluirmos o pedido seus itens serão excluídos. (Isto não te lembra um relacionamento feito em definição de tabelas? 1 para n ON DELETE CASCADE).

Para finalizarmos vamos colocar um diagrama de classes e um código para reforçar a idéia.

Diagrama acima convertido em código:

Interface IPessoa

namespace Heranca
{
    /// <summary>
    /// esta é uma interface.
    /// Percebam que declaramos apenas os métodos,
    /// iremos usar neste caso a herança de interface
    /// </summary>
    interface IPessoa
    {
        void Dancar();
        DateTime DataNascimento { get; set; }
        void Envelhecer();
        void Falar();
        int Idade { get; }
        string Nome { get; set; }
        Sexo Sexo { get;  }
    }
}

Classe Pessoa

namespace Heranca
{
    public enum Sexo
    {
        NaoDefinido,
        Masculino,
        Feminino
    }

    /// <summary>
    /// esta classe é uma classe genérica pra todo tipo de pessoa.
    /// vejam que aqui iremos herdar a interface IPessoa,
    /// neste caso será uma herança de interface.
    /// Devemos escrever código para todo método e propriedade
    /// definido na interface.
    /// </summary>
    abstract class Pessoa : IPessoa
    {
        /// <summary>
        /// esta propriedade poderá ser sobreescrita
        /// nas classes filhas. mas não é obrigatória
        /// </summary>
        public virtual int Idade
        {
            get
            {
                int idade = DateTime.Now.Year - DataNascimento.Year;
                if (DateTime.Now.Month < DataNascimento.Month ||
                (DateTime.Now.Month == DataNascimento.Month &&
                DateTime.Now.Day < DataNascimento.Day))
                    idade--;
                return idade;
            }
        }

        public DateTime DataNascimento { get; set; }

        /// <summary>
        /// esta propriedade deverá obrigatoriamente ser declarada
        /// na classe pai
        /// </summary>
        public abstract Sexo Sexo { get; }

        public virtual String Nome { get; set; }

        public virtual void Envelhecer()
        {
            DataNascimento = DataNascimento.AddYears(1);
            Console.WriteLine("A pessoa envelheceu um ano.");
        }

        public virtual void Dancar()
        {
            Console.WriteLine("A pessoa está dançando");
        }

        public virtual void Falar()
        {
            Console.WriteLine(@"A pessoa disse: visitem
            http://desenvolvedores.net");
        }
    }
}

Classe Pai

namespace Heranca
{
    /// <summary>
    /// Aqui iremos herdar a classe pessoa.
    /// vejam que apenas escrevi a propriedade Sexo.
    /// Pois na classe pai (abstrata) estava definido
    /// que as filhas deveria escrever o código para sexo.
    /// Mas as outras propriedades e métodos serão herdados de pessoa
    /// </summary>
    class Pai : Pessoa
    {
        public override Sexo Sexo { get { return Sexo.Masculino; } }

        /// <summary>
        /// este método poderá ser sobreescrito nas classes filhas
        /// neste caso o pai está apenas brincando.
        /// Veremos ele sobreescrito na classe filha
        /// </summary>
        public virtual void Brincar()
        {
            Console.WriteLine("O pai está brincando");
        }
    }
}

Classe Filho

namespace Heranca
{
    /// <summary>
    /// aqui o filho herdou todas as características do pai
    /// </summary>
    class Filho : Pai
    {

        /// <summary>
        /// aqui iremos substituir o método Brincar
        /// </summary>
        public override void Brincar()
        {
            Console.WriteLine("O filho está brincando com seu pai.");
        }
    }
}

Classe Aluno

namespace Heranca
{
    /// <summary>
    /// mais um classe que herda de pessoa
    /// </summary>
    class Aluno : Pessoa
    {
        public override Sexo Sexo
        {
            get { return Sexo.Feminino; }
        }

        public int VerNota()
        {
            return new Random().Next(0, 10);
        }
    }
}

E finalmente o código escrito em uma aplicação do tipo console.
Atenção, prestem bastante atenção aos comentários, eles têm dicas importantes.

namespace Heranca
{
    class Program
    {
        static void Main(string[] args)
        {
            /*
             * aqui vai um dica útil.
             * Cuidado ao declarar o seu tipo de objeto
             * pois as propriedades e métodos que você
             * irá visualizar depende do tipo declarado
             *
             * Vejam aqui, vou declarar como um objeto Pessoa
             * mas vou instanciar como um Aluno
             */

            Pessoa pessoaAluno = new Aluno();

            pessoaAluno.Nome = "Marcelo";

            /*
             * reparem que o método VerNota() só existe
             * na classe Aluno, logo na linha 17,
             * mesmo o objeto sendo instanciado como
             * new Aluno() seus métodos só existirão
             * através do seu tipo definido Pessoa
             */

            Console.WriteLine(pessoaAluno.Nome);

            /*
             * Mas, e se precisarmos acessar
             * os dados de Aluno?
             * Simplesmente faça um cast (conversão)
             * de um objeto para outro
             * Vejam:
             */

            Aluno aluno = pessoaAluno as Aluno;

            Console.WriteLine(aluno.VerNota());

            /*
             * A dica acima é válida tambem para os tipos
             * interfaces
             */

            IPessoa pessoaFilho = new Filho();
            pessoaFilho.Falar();

            Filho filho = pessoaFilho as Filho;
            filho.Brincar();

            /*
             * Abaixo um exemplo do override em filho
             */

            Pai pai = new Pai();

            //aqui chamamos o método brincar de Pai
            pai.Brincar();

            //aqui chamamos o método brincar que foi substituido
            Filho meuFilho = new Filho();
            meuFilho.Brincar();

            /*
             * Legal. Mas posso chamar o método
             * Brincar da classe base?
             */

            pai = filho as Pai;
            pai.Brincar();

            /*
             * Não. Não podemos.
             * Apesar da instrução acima não dar erro
             * o método que será chamado é sempre
             * o método substituído.
             *
             * Mas a afirmação acima não é 100% correta.
             * Se em nossa classe Filho o método tivesse
             * sido declarado assim:
             * public new void Brincar()
             * O método chamado seria o da classe Pai,
             * pois neste caso não substituimos o método
             * e sim criamos um novo.
             *
             * Vejam as duas declarações juntas para comparar
             *
             * public new void Brincar()
             * public override void Brincar()
             */

            Console.ReadKey();

        }
    }
}

Ver Índice

É isso ai pessoal 🙂
Até o próximo
♦ Marcelo

Compartilhe!

About Marcelo

Nascido em Juruaia/MG em uma fazenda de criação de búfalos, e residindo na região Sul do Brasil. Trabalha com desenvolvimento de aplicações desde os 17 anos. Atualmente é Arquiteto Organizacional na Unimake Software. Para saber mais ... http://desenvolvedores.net/marcelo []'s

2 Comments for this entry

4 Trackbacks / Pingbacks for this entry

Deixe uma resposta

O seu endereço de e-mail não será publicado.

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong>

Previous Post
«
Next Post
»