Generalização Especialização Herança

Postado por Carlos Fernando Sylverio | Postado em Orientação a Objetos, Programação, UML | Postado em 29-01-2009

0

Olá pessoal, estive de férias e passei um bom tempo sem escrever, mas agora descançado, não há mais desculpas.

Fiz uma breve descrição sobre generalização, especialização e herança, devido a um pedido do último post e montei um pequena aplicação para exemplificar o assunto.

Conceito

Podemos dizer que generalização é o agrupamento de objetos ou elementos com características comuns em um modelo ou sistemas, é uma descrição mais geral sobre o objeto referente.

E a especialização é processo inverso, é a definição das particularidades de cada objeto ou elemento, são elementos mais consistentes que estendem o elemento genérico.

Dando continuidade ao exemplo citado no último post, casa, galpão, prédio, chamarei a generalização de “Habitação“.

(achei que não foi uma boa escolha esses elementos, prédio, galpão, etc… Para falar de generalização, mas vou utilizá-los para não confundir quem está começando a ver O.O., e manter um pouco de compatibilidade com o post anterior)

Ou seja, todos os elementos, são habitações, porém cada elemento guarda sua característica particular.

O que se ganha com isso?

A utilização de generalização tem dois propósitos:

  • Permitir que a classe base ou subclasse ser usada como variável. E regra é que uma instância da subclasse possa ser usada quando a superclasse é declarada. Com isso possibilitamos a realização de operações polimórficas.
  • Permitir a incrementar as características de um elemento pelas características comuns de seu antecessor. Esta é a chamada de herança.

Herança é a definição da implementação da generalização no código

Já li em alguns livros que o conceito de generalização pode ser utilizada para agrupar características comuns de cada objeto, passando os atributos comuns para o objeto mais genérico. Mas eu discordo desta opinião.

Não há nenhuma vantagem criar um modelo utilizando generalização e especialização se não for para se aproveitar de um dos benefícios comentados acima.

Na verdade estaremos adicionando mais complexidade ao modelo e tornando o código menos escalável.

Prática

Criei um exemplo simples em C#.NET para mostrar como aplicar os conceitos acima.

Para isso no Visual Studio vá em File->New->Project.

Em Templates, escolha Console Application.

Altere o Name para Generalizacao e clique em OK

Agora vá ao projeto (Generalizacao), clique com o botão direito vá em Add->New Item.

Em Templates, escolha Class.

Altere o Nome para Habitação.

Altere o código de para que fique da seguinte forma:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
using System;
 
namespace Generalizacao
{
    public abstract class Habitacao
    {
        /// <summary>
        /// Quantidade de tomadas da habitação
        /// </summary>
        private int qtdTomada;
 
        /// <summary>
        /// Obtem a quantidade de tomadas
        /// </summary>
        public int GetQtdTomada()
        {
            return qtdTomada;
        }
 
        /// <summary>
        /// Armazena a quantidade de tomada
        /// </summary>
        public void SetQtdTomada(int value)
        {
            qtdTomada = value;
        }
    }
}

Adiciona ao projeto as classes Casa, Predio e Galpao, e altere o código da seguinte forma:

Casa

1
2
3
4
5
6
7
8
9
10
11
using System;
 
 
 
 
namespace Generalizacao
{
    public class Casa : Habitacao
    {
    }
}

Observação:

Em C#, a sintaxe para herança é a utilização do comando: após o nome da classe seguindo do nome da classe a ser herdada.

Em Java, a sintaxe para herança é o comando extends após nome da classe seguindo do nome da classe a ser herdada.

Predio

1
2
3
4
5
6
7
8
using System;
 
namespace Generalizacao
{
    public class Predio : Habitacao
    {
    }
}

Galpao

1
2
3
4
5
6
7
8
using System;
 
namespace Generalizacao
{
    public class Galpao : Habitacao
    {
    }
}

Pronto. Criamos a estrutura modelada em UML acima.

Agora nossa Solution deve ter a seguinte aparência.

Na classe Program.cs, escreva o seguinte código:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
using System;
 
namespace Generalizacao
{
    public class Program
    {
        public static void Main(string[] args)
        {
            // Instâncias de casa
            Casa casa = new Casa();
            casa.SetQtdTomada(15);
 
            // Instâncias de prédio
            Predio predio = new Predio();
            predio.SetQtdTomada(300);
 
            // Instâncias de galpão
            Galpao galpao = new Galpao();
            galpao.SetQtdTomada(40);
 
            ImprimirValorDeTomada(casa, "Casa");
            ImprimirValorDeTomada(predio, "Predio");
            ImprimirValorDeTomada(galpao, "Galpao");
        }
 
        private static void ImprimirValorDeTomada(Habitacao habitacao,String tipo)
        {
            Console.WriteLine("{0} tem a seguinte quantidade de tomadas: {1}", tipo, habitacao.GetQtdTomada());
        }
    }
}

Como você deve ter observado, quando estava codificando, o seguinte acontecimento. O intellisense apresentar os métodos codificados na classe Habitação, para todas as subclasses.

Isso é possível devido às classes Casa, Predio e Galpao herdarem da classe Habitação, ou seja, toda a classe que herda de Habitação terá sua característica e comportamento.

Outra coisa que podemos observar nesse exemplo é o método ImprimirValorDeTomada que recebe como parâmetro Habitação, porém é passado Casa, Predio e Galpao.
Toda subclasse pode ser convertida no tipo da superclasse. Nesse método não importa qual é o tipo de habitação e sim se é do tipo habitação.

Observação

Toda subclasse pode ser convertida no tipo da superclasse, porém para o processo inverso é necessário a realização de cast.

Exemplo:

1
2
3
4
5
Casa casa1 = new Casa();
// conversão Implicit
Habitacao hab = casa1;
// conversão Explicit (Cast)
Casa casa2 = (Casa)hab;

Mas pra frente falarei mais sobre generalização.

Carlos Fernando