next up previous contents
Next: Funções em linha Up: Classes e Encapsulação Previous: Definição de classes   Sumário

Ocultamento da informação

A fim de entender realmente os benefícios associados com a encapsulação, iremos analisar a seguir um exemplo onde encapsulação não é utilizada, e possíveis problemas que podem ocorrer neste caso. Posteriormente, este problema será revisitado para analisar uma solução com encapsulação.

Neste problema, duas entidades são consideradas. A primeira delas é uma entidade do tipo retângulo, que tem uma altura e uma largura. A área do retângulo pode ser calculada como o produto destes dois valores. A segunda entidade é uma entidade do tipo mastro, que tem um comprimento e uma profundidade (o quanto o mastro foi enterrado); o comprimento total do mastro é a soma destes dois valores.

A solução usando ANSI-C seria representar cada uma das entidades como uma estrutura. Esta solução é apresentada a seguir.

indentation

#include $<$iostream.h$>$

int area(int rec_height, int rec_width);

struct rectangle {
int height;
int width;
};

struct pole {
int length;
int depth;
};

int area(int rec_height, int rec_width) //Area of a rectangle
{
return rec_height $\ast$ rec_width;
}


main()
{
rectangle box, square;
pole flag_pole;

box.height = 12;
box.width = 10;
square.height = square.width = 8;

flag_pole.length = 50;
flag_pole.depth = 6;

cout $\ll$ "The area of the box is " $\ll$
area(box.height, box.width) $\ll$ begintex2html_wrap_inline$$n";
cout $\ll$ "The area of the square is " $\ll$
area(square.height, square.width) $\ll$ begintex2html_wrap_inline$$n";
cout $\ll$ "The funny area is " $\ll$
area(square.height, box.width) $\ll$ begintex2html_wrap_inline$$n";
cout $\ll$ "The bad area is " $\ll$
area(square.height, flag_pole.depth) $\ll$ begintex2html_wrap_inline$$n";
}

Não há nada errado com esta forma de resolver o problema -- o perigo está nas coisas tolas que podem ser feitas com estes dados. Por exemplo, para calcular uma das áreas está se multiplicando a altura de um quadrado com o comprimento de de uma caixa diferente. Em outro caso, ainda pior: calcula-se o produto da altura do quadrado com a profundidade de um mastro, seja lá o que isto quer dizer. Os resultados da execução do programa, no entanto, parecem perfeitamente válidos:
    The area of the box is 120
    The area of the square is 64
    The funny area is 80
    The bad area is 48

Embora esta situação possa parecer tola quando observada neste pequeno exemplo, ela pode ocorrer com frequência em sistemas de porte maior. Não há modos de prevenir que isto aconteça em ANSI-C. A solução real para este problema está na encapsulação.

O exemplo a seguir ilustra a utilização de classes para modelar o mesmo problema. Retângulo é agora modelado como uma classe. Neste caso torna-se evidente que o cálculo de área é algo que só faz sentido (neste caso) para retângulos, pois o método correspondente é uma função membro desta classe. Mastro ainda é modelado como uma estrutura apenas para ilustrar que os dois tipos de construções podem coexistir sem problemas em um programa.

indentation

#include $<$iostream.h$>$

class rectangle { // A simple class
int height;
int width;
public:
int area(void); // with two methods
void initialize(int, int);
};

int rectangle::area(void) //Area of a rectangle
{
return height $\ast$ width;
}

void rectangle::initialize(int init_height, int init_width)
{
height = init_height;
width = init_width;
}

struct pole {
int length;
int depth;
};


main()
{
rectangle box, square;
pole flag_pole;

box.initialize(12, 10);
square.initialize(8, 8);

flag_pole.length = 50;
flag_pole.depth = 6;

cout $\ll$ "The area of the box is " $\ll$
box.area() $\ll$ begintex2html_wrap_inline$$n";
cout $\ll$ "The area of the square is " $\ll$
square.area() $\ll$ begintex2html_wrap_inline$$n";
}
O resultado da execução deste programa é
    The area of the box is 120
    The area of the square is 64

Observe que não há modo, neste caso, de cometer os enganos que ocorriam no exemplo anterior -- simplesmente é impossível acessar diretamente os dados de objetos individuais da classe retângulo e, consequentemente, é impossível misturar a informação que eles carregam.

Esta técnica não é exatamente inédita. Sistemas operacionais usualmente adotam o conceito de kernel, um conjunto de serviços que pode apenas ser acessado através de rotinas pré-estabelecidas (system calls). A manipulação de arquivos é um exemplo de um destes serviços. A fim de manipular arquivos, o sistema operacional mantém um grande conjunto de dados. Entretanto, o usuário nem sabe da existência destes dados -- tudo o que ele pode fazer é requisitar os serviços através do system call adequado. Isto evita que o usuário, inadvertidamente, corrompa o sistema de arquivos.

A definição de classes permite que o programador use este mesmo mecanismo na implementação de uma aplicação. No exemplo anterior, a definição da classe retângulo e de seus métodos poderia ter sido desenvolvida à parte, de forma totalmente isolada do programa que a utiliza. Uma vez que esta classe esteja desenvolvida e ``aprovada'', ela pode tornar-se disponível para ser utilizada na aplicação. Observe como a utilização de classes promove de modo natural a técnica de dividir para conquistar. Em grandes projetos, esta abordagem é repetidamente utilizada, sendo que algumas classes podem ser extremamente complexas internamente -- mas para o usuário da classe esta complexidade é totalmente abstraída.


next up previous contents
Next: Funções em linha Up: Classes e Encapsulação Previous: Definição de classes   Sumário
Ivan Luiz Marques Ricarte 2001-06-01