[Pesquisar este blog]

domingo, 11 de março de 2018

POO::Plena-19-Membros Estáticos

POO-P-18-Especificadores e Modificadores POO-P-20-Herança Simples
Os membros estáticos são aqueles declarados com o modificador static, de maneira que tanto atributos/campos como métodos/operações possam ser definidas desta forma. Desta maneira é preciso uma conceituação mais precisa das implicações de seu uso para possibilita seu emprego adequado.

Como visto, as linguagens Java e C# possuem vários especificadores e modificadores (como no post anterior Especificadores e Modificadores), dentre os quais existe um denominado static. O uso deste modificador altera o comportamento dos membros assim declarados, tornando membros de instância em membros de classe, como veremos a seguir.

Membros de instância

Uma classe pode declarar vários membros:
  • Variáveis-membro (campos ou atributos) e
  • Funções-membro (métodos ou operações).
Estes membros, naturalmente, só podem ser utilizados pelas instâncias da classes, ou seja:
  • Cada objeto instanciado tem cópias exclusivas das variáveis-membro para seu uso individual; e
  • As funções-membro, acionadas pelos objetos instanciados, utilizam apenas as variáveis-membro de suas respectivas instâncias.
Por isso, tais membros são denominados de membros de instância.

Consideremos a classe Point dada a seguir.

public class Point {
    public double x;
    public double y;

    public void reflectX() { y = - y; }
    public void reflectY() { x = - x; }
}

Objetos do tipo Point podem ser instanciados como no fragmento abaixo, que usa o construtor default suprido pelo compilador:

Point p1 = new Point();
Point p2 = new Point();

Depois de criados, os objetos podem ser acessados por meio de suas referências, no caso p1 e p2, o que permite acessar as variáveis-membro x e y que são públicas.

p1.x =  5.5;
p1.y = 3.0;

p2.x = -1.5;
p2.y = 6.7;

Cada instância armazena seus próprios valores, retendo, portanto, apenas o seu próprio estado e, assim, o uso de métodos só afeta a instância onde são acionados.

System.out.println("P1: " + p1.x + ","+ p1.y);
System.out.println("P2: " + p2.x + ","+ p2.y);

p1.reflectY();
p2.reflectX();

System.out.println("P1: " + p1.x + ","+ p1.y);
System.out.println("P2: " + p2.x + ","+ p2.y);

Com isso fica claro que operações executadas numa instância não afetam quaisquer outras instâncias (do mesmo tipo ou de outros).

Membros de classe

Quando um membro de uma classe (variável ou método) é declarado como static, ele é modificado de maneira que deixa de pertencer às instâncias da classe, passando a pertencer a própria classe.

Assim uma variável-membro ou campo declarado como static torna-se uma variável de classe, um membro de classe ou um campo estático. Da mesma maneira, um método de instância ou operação torna-se um método de classe ou método estático.

O uso do modificador static não afeta os especificadores de acesso, de modo que static pode ser combinado com public, protected ou private, conforme desejado pelo programador.

Por outro lado, os construtores não podem, em qualquer circunstância, ser declarados como estáticos.

Analise a classe Cruise dada a seguir. Observe a existência de um campo estático denominado MAX e de um método estático chamado maxRate(double).

public class Cruise {
    public static double MAX;
    public double velocity;

    public boolean overMax () {
        return velocity > MAX;
    }

    public static double maxRate(double v) {
        return v/MAX;
    }
}

Objetos do tipo Cruise podem ser instanciados normalmente, com uso do construtor default.

Cruise c1 = new Cruise();
Cruise c2 = new Cruise();

O uso dos membros não estáticos não é afetado pela presença dos elementos estáticos, ou seja, é possível fazer:

c1.velocity =  81.5;
c2.velocity = 105.7;

if (c1.overMax()) System.out.println(c1.velocity);
if (c2.overMax()) System.out.println(c2.velocity);
// se executado este trecho exibe as velocidades 81.5 e 105.7.

O campo estático MAX é um membro de classe, portanto comum a todas as instâncias. Seu uso deve ser feito por meio do nome da classe, como segue:

Cruise.MAX = 100;

O novo valor de MAX é conhecido por todas as instâncias da classe, que tem acesso ao seu novo conteúdo. Assim, se executado

if (c1.overMax()) System.out.println(c1.velocity);
if (c2.overMax()) System.out.println(c2.velocity);
// agora este trecho exibe apenas a velocidade 105.7!

O método overMax(), não estático, emprega internamente a variável de instância velocity, a qual é comparada a variável de classe MAX. Na primeira execução, velocity do objeto c1 tem valor 81.5, velocity do objeto c2 tem valor 105.7, enquanto MAX, não inicializada, tem valor 0; produzindo os resultados 81.5 e 105.7, ambos valores maiores que MAX.

Alterando o valor da variável de classe MAX para 100 e executando novamente o método overMax() para as duas instâncias, temos que velocity do objeto c1 ainda tem valor 81.5, velocity do objeto c2 ainda tem valor 105.7, mas MAX, com novo valor 100; produz o resultado 105.7, única velocidade maior que MAX.

O uso de campos e métodos estáticos, conforme a recomendação da plataforma, deve usar o nome qualificado da classe, tal como:

Cruise.MAX = 100;
Cruise.maxRate(120);

Apesar disso, o uso de elementos estáticos por meio de instâncias, como segue, produz, quando muito, avisos por parte do compilador, pois o que define o acesso é, de fato, o especificador de acesso empregado.

c1.MAX = 120;
c2.maxRate(40);

O modificador static altera o comportamento do membro, que deixa de pertencer a instância, passando para o domínio da classe, acarretando em um conjunto de implicações que determinam a forma com que pode ser explorado.

Usos comuns de membros static

O uso do modificador static possibilita usos como:
  • Compartilhamento de informação entre instâncias de uma mesma classe, diretamente por meio de variáveis estáticas; ou indiretamente por meio de métodos estáticos que podem oferecer operações baseadas em valores comuns existentes entre as instâncias de uma classe.
  • Criação simplificada de biblioteca de funções, quando não é necessária a retenção de estado de objetos (feito por variáveis de instância)
  • Definição de constantes, que podem preservar de maneira imutável valores (e até mesmo referências de instâncias) considerados importantes em um programa.

Compartilhamento de informação

Os membros estáticos pertencem à classe, ou seja, eles são únicos e não dependem da existência de instâncias da classe (i.e., objetos) para serem acessados, apenas respeitando os especificadores de acesso combinados, sem quaisquer restrições adicionais.

Externamente, o acesso dos membros estáticos passa a ser qualificado pela própria classe, conforme sua visibilidade. Internamente o acesso dos membros estáticos é como qualquer outro.

Assim, se existe a classe Estatica como dado a seguir:
public class Estatica {
    public static int sval = 10;
    private int ival = 0;

    public static void reset() {
       sval = 0;
    }

    public int getIVal() { return ival; }
    public void setIVal(int i) { ival = i; }
}

É possível usar seus membros estáticos desta maneira:

// Uso de campo:
Estatica.sval = 33;
// Uso de método:
Estatica.reset();

Mas o uso dos membros não estáticos requer instâncias válidas:

Estatica e1 = new Estatica();
e1.setIVal(10);
System.out.println(e1.getIVal());

Assim todas as instâncias tem acesso aos membros estáticos únicos associados às suas próprias classes. Desta maneira, torna-se possível compartilhar valores entre instâncias por meio de variáveis estáticas, pois é como se fossem variáveis "globais" de um tipo específico.

A classe Estatica2 utiliza um membro estático denominado N que mantém o número de objetos da própria classe, incrementando-o na instanciação e decrementando-o na destruição de objetos.

public class Estatica2 {
    private static int N = 0;

    public Estatica2 () {
        N++;
    }
    protected void finalize() {
        N--;
    }
    public static int instances() {
        return N;
    }
}

Esta classe pode ser usada como segue:

// Exibe 0
System.out.println(Estatica2.instances());

Estatica2 obj1 = new Estatica2();
// Exibe 1
System.out.println(Estatica2.instances());

Estatica2 obj2 = new Estatica2();
// Exibe 2
System.out.println(Estatica2.instances());

obj1 = null; // GC pode atuar!
// Exibe 1 ou 2, conforme atuação do GC
System.out.println(Estatica2.instances());

Biblioteca de funções

Como os métodos estáticos não utilizam campos mutáveis de suas classes, podem oferecer operações independentes, cujo resultado se baseia, estritamente, nos argumentos recebidos.

Um conjunto de métodos estáticos relacionados, ou seja, cujas operações pertençam a um mesmo domínio, podem ser agrupados em uma única classe, a qual se comporta como uma biblioteca de funções

Um exemplo desta aplicação, na própria API do Java é a classe java.lang.Math, que só contém métodos estáticos que oferecem funções matemáticas independentes.

A classe Conversão, que segue, também contém apenas métodos estáticos relacionados a conversão de temperaturas entre diferentes unidades.

public class Conversao {
// conversão C --> F
   public static double C2F (double c) {
      return 9*c/5 + 32;
   }
// conversão F --> C
   public static double F2C (double f) {
      return 5*(f-32)/9;
   }
}

O uso desta classe não requer instâncias, pois os seus métodos podem ser acionados diretamente:

double x = 100;
double y= Conversao.C2F(x);
System.out.println("C = " + x + " => F = " + y);

y = 32;
x = Conversao.F2C(y);
System.out.println("F = " + y + " => C = " + x);

System.out.println("C = 24" + " => F = " + Conversao.C2F(24));


Definição de constantes

A linguagem Java não contém um modificador próprio para definição de constantes (como const em linguagem C++). Mas tal efeito pode ser obtido pela combinação de dois modificadores na declaração de variáveis:
  • static, que indica que membro pertence à classe;
  • final, que indica que membro não pode ser alterado, nem mesmo em subclasses.
Exemplos de declaração de constantes são:
public static final double PI = 3.1415926;
public final static int MAX = 123;
static public final byte MASK = 0b01001001;

Observe que a inicialização é obrigatória na declaração de constantes. Além disso, a ordem com que os modificadores e especificadores são aplicados não altera o efeito produzido.

Outro aspecto importante, é que a convenção de código Java solicita que os nomes das constantes seja grafado exclusivamente com letras maiúsculas, eventualmente com  uso de _ (underline) para separação de palavras.

Restrições dos membros static

Campos e métodos estáticos só podem utilizar:
  • Constantes literais;
  • Outros elementos estáticos;
  • Objetos e membros não estáticos de objetos diretamente instanciados em seu escopo.
De maneira geral, um membro estático não pode utilizar um elemento não estático se não for garantida sua existência (instanciação) no mesmo escopo.

Importação estática

Introduzida na versão 5 do Java, esta característica permite o uso de constantes declaradas em classes externas sem necessidade de sua qualificação (indicação do nome da classe).

Por exemplo, a classe Math contém constantes usualmente empregadas (de forma qualificada) como Math.PI ou Math.E, como no exemplo que segue.

// SEM importação estática
import java.lang.*;
public class SemImportStatic {
   public static void main(String args[]) {
      double raio = Double.parseDouble(args[0]);
      // uso da constante qualificada
      double perim = 2 * Math.PI * raio;
      System.out.print("raio = " + raio); 
      System.out.println(", perim = " + perim);
   }
}

Com uso da importação estática, torna-se possível não qualificar tais constantes, usadas diretamente como PI ou E, como na versão modificada do exemplo acima com uso desta alternativa.

// COM importação estática
import static java.lang.Math.*;
public class ComImportStatic {
   public static void main(String args[]) {
      double raio = Double.parseDouble(args[0]);
      // uso da constante qualificada
      double perim = 2 * PI * raio;
      System.out.print("raio = " + raio); 
      System.out.println(", perim = " + perim);
   }
}

A importação estática não tem impacto expressivo no código e, por isso, não é usada com muita frequência.

Concluindo, o uso de membros estáticos, como visto, é bastante conveniente para criação de um mecanismo simples de compartilhamento entre instâncias de uma classe, além de permitir a criação simplificada de bibliotecas de funções. Por estas razões, os membros estáticos são empregados frequentemente no código.


POO-P-18-Especificadores e Modificadores POO-P-20-Herança Simples

Referências Bibliográficas

[1] JAMSA, K.; KLANDER, L.. Programando em C/C++: a bíblia. São Paulo: Makron Books, 1999.
[2] PAGE_JONES, M.. Fundamentos do Desenho Orientado a Objeto com UML. São Paulo: Makron Books, 2001.
[3] SOMMERVILLE, I.. Software Engineering. 6th. Ed. Harlow: Pearson, 2001.
[4] DEITEL, H.M.; DEITEL, P.J.. Java: como programar. 6a. Ed. São Paulo: Pearson Prentice-Hall, 2005.
[5] SAVITCH, W.. C++ Absoluto. São Paulo: Pearson Addison-Wesley, 2004.
[6] JANDL JR., P. Introdução ao C++. São Paulo: Futura, 2003.
[7] JANDL JR., P.. Java - guia do programador. 3a. ed. São Paulo: Novatec, 2015.
[8] RUMBAUGH, J.; BLAHA, M.; PREMERLANI, W.; EDDY, F.; LORENSEN, W.. Object-oriented modeling and design. Englewoods Cliffs: Prentice-Hall, 1991.
[9] STROUSTRUP, B.. The C++ Programming Language. 3rd Ed. Reading: Addison-Wesley, 1997.
[10] LANGSAM, Y.; AUGENSTEIN, M. J.; TENENBAUM, A. M.. Data structures using C and C++. 2nd Ed. Upper Saddle River: Prentice-Hall, 1996.
[11] WATSON, K.; NAGEL, C.; PEDERSEN, J.H.; REID, J.D.; SKINNER, M.; WHITE, E.. Beginning Microsoft Visual C# 2008. Indianapolis: Wiley Publishing, 2008.

quinta-feira, 8 de março de 2018

POO::Plena-18-Especificadores e Modificadores

POO-P-17-Associações-agregação POO-P-19-Membros estáticos
As linguagens de programação Java e C# possuem um conjunto especial de palavras reservadas cuja aplicação afeta como os membros de uma classe podem ser utilizados ou, até mesmo, como funcionam. São os especificadores e modificadores da linguagem.

Especificadores

Os especificadores existentes estabelecem a visibilidade do membro onde se aplicam, ou seja, determinam o seu acesso e, por isso, são conhecidos também como especificadores de acesso [2][4][5][6][7]. As linguagens de programação Java e C# possuem três especificadores de acesso: public, protected, private, visto no post sobre Encapsulamento

public

Determina o acesso público, no qual os membros de uma classe têm utilização interna e externa irrestrita. Como ficam expostos na interface das classes, podem ser usados livremente pelas suas instâncias de maneira que os atributos públicos têm seus conteúdos acessados e alterados sem qualquer restrição; e os métodos públicos podem ser acionados arbitrariamente.

private

Estabelece o acesso privado, ou seja, define que o método ou atributo de classe assim declarado tem apenas uso interno, não sendo acessível externamente. Provê a ocultação dos membros assim declarados, servindo usualmente para compor a infraestrutura de uma classe.

protected

Indicar que membros de uma classe que não podem ser utilizados por meio de suas instâncias, mas apenas na construção de novas classes. Os membros protegidos, compõem uma interface de programação da classe, ou seja, um conjunto de atributos e operações destinados exclusivamente aos programadores que usarão tal classe como base para criação de outras.

Como visto no post sobre Encapsulamento, existe um quarto nível de acessibilidade denominado pacote (package) que não possui uma palavra reservada própria [4][7]. É o acesso padrão (implícito), quando outro especificador não é indicado. Seu efeito é tornar o membro público para as demais classes e instâncias presente no mesmo pacote, mas private para quaisquer outras.

O quadro que segue mostra o efeito da aplicação dos especificadores de acesso aos membros de uma classe, considerando as situações de implementação (codificação) e instanciação (criação de objetos dentro de programas).


Modificadores

Os modificadores determinam o funcionamento do membro, isto é, seu comportamento durante a execução dos programas, assim afetam como acontece a geração do seu respectivo código. Existem vários modificadores nas linguagens Java e C#: abstract, final, native, static, strictfp, synchronized, transient e volatile.

O quadro abaixo resume os efeitos provocados pelo uso destes modificadores, assim como sua aplicação típica.

O modificador static, cujo uso é bastante comum, será tratado no próximo post, que aborda os membros estáticos.

Os modificadores abstract e final serão abordados nos posts envolvendo herança e classes abstratas.

Os modificadores synchronized e volatile, destinados a programação com threads; transient, para uso junto a serialização; strictfp, para indicação de regras mais estritas para processamento de cálculos com uso de números em ponto flutuante; assim como native, empregado com o Java Native Inteface (JNI); são muito específicos e não serão abordados nesta série.

Particularidades do Java

A linguagem de programação Java, em particular, não possui os modificadores signed e unsigned existentes em outras, assim todos os seus tipos primitivos numéricos (byte, short, int, long, float e double) sempre podem representar valores positivos e negativos.

A notação ... (elipse) funciona como um modificador especial para tornar variável a lista de argumentos fornecida para um método (ou varargs) [7]. Seu uso permite que um método receba um número variável e arbitrário de valores, de maneira mais flexível que a recepção de arrays, pois seu uso admite o uso do método sem argumentos, com qualquer número de argumentos separados por vírgula (como uma lista) ou também um array.

O método que segue é do tipo varargs, ou seja, pode receber qualquer número de argumentos do tipo int, somando-os e retornando o resultado da soma.
public int somar(int ... args) {
int total = 0;
for (int i=0; i<args.length; i++) { total += args[i]; }
return total;
}

Observe que, internamente, os argumentos variáveis são tratados como se fizessem parte de um array, para o qual o número de elementos é indicado por length. Segue alguns exemplos de uso deste método.
int t1 = somar(); // uso válido, que retorna zero
int t2 = somar(0, 12, 34, 56);
int array[] = { 1, 2, 3, 4 };
int t3 = somar(array);

Finalmente, os métodos podem receber outros parâmetros, desde que aquele modificado com ... seja o último de sua assinatura.

Particularidades do C#

A linguagem de programação C# possui alguns modificadores próprios, como ref, out e param.

Por padrão a passagem de parâmetros em C# ocorre por valor, ou seja, uma cópia do valor ou do objeto indicado como argumento do método é passada como valor de seus parâmetros, de modo que se tal parâmetro é alterado dentro do método, nada ocorre com o valor original passado como argumento.

O modificador ref indica que o parâmetro será passado por referência, ou seja, o método receberá o endereço do valor ou objeto, de modo que sua alteração no interior do método acarreta mudanças no argumento usado para acionar o método, pois na verdade se trata da mesma variável ou objeto.

O modificador out, semelhante a ref, faz com que o parâmetro seja passado por referência, mas não necessita ser inicializado, ou seja, é geralmente utilizado para carregar valores para fora do método, possibilitando a existência de múltiplos valores de retorno. Por outro lado, parâmetros out devem ser inicializados dentro dos métodos onde são declarados.

Também existe modificador params, o qual permite que um método receba um número variável e arbitrário de valores, de maneira mais flexível que a recepção de arrays, pois seu uso admite o uso do método sem argumentos, com qualquer número de argumentos separados por vírgula (como uma lista) ou também um array.

O método que segue tem sua lista de parâmetros modificada com params, permitindo que receba qualquer número de argumentos do tipo int, somando-os e retornando o resultado da soma.
public int somar(params int args) {
int total = 0;
foreach (int v in args) { total += v; }
return total;
}

Observe que, como em Java, os argumentos variáveis são tratados como se fizessem parte de um array, possibilitando o uso de foreach. Segue alguns exemplos de uso deste método.
int t1 = somar(); // uso válido, que retorna zero
int t2 = somar(0, 12, 34, 56);
int array[] = { 1, 2, 3, 4 };
int t3 = somar(array);

Finalmente, os métodos podem receber outros parâmetros, desde que aquele modificado com params seja o último de sua assinatura.

Uso combinado de especificadores e modificadores

Os modificadores podem ser usados junto dos especificadores de acesso [7], por exemplo:

private static int MAX;
public static final double AVO = 6.22E23;
public static void main(String[] args) { ... }

protected transient boolean state;
public volatile long count;
private native byte AX;
public strictfp double computeSerie(double[] data) { ... } 

public synchronized void turn() { ... }
public abstract Object[] toArray() { ... }

Desta forma, muitas possibilidades diferentes podem ser escolhidas pelo programador.

POO-P-17-Associações-agregação POO-P-19-Membros estáticos

Referências Bibliográficas

[1] JAMSA, K.; KLANDER, L.. Programando em C/C++: a bíblia. São Paulo: Makron Books, 1999.
[2] PAGE_JONES, M.. Fundamentos do Desenho Orientado a Objeto com UML. São Paulo: Makron Books, 2001.
[3] SOMMERVILLE, I.. Software Engineering. 6th. Ed. Harlow: Pearson, 2001.
[4] DEITEL, H.M.; DEITEL, P.J.. Java: como programar. 6a. Ed. São Paulo: Pearson Prentice-Hall, 2005.
[5] SAVITCH, W.. C++ Absoluto. São Paulo: Pearson Addison-Wesley, 2004.
[6] JANDL JR., P. Introdução ao C++. São Paulo: Futura, 2003.
[7] JANDL JR., P.. Java - guia do programador. 3a. ed. São Paulo: Novatec, 2015.
[8] RUMBAUGH, J.; BLAHA, M.; PREMERLANI, W.; EDDY, F.; LORENSEN, W.. Object-oriented modeling and design. Englewoods Cliffs: Prentice-Hall, 1991.
[9] STROUSTRUP, B.. The C++ Programming Language. 3rd Ed. Reading: Addison-Wesley, 1997.
[10] LANGSAM, Y.; AUGENSTEIN, M. J.; TENENBAUM, A. M.. Data structures using C and C++. 2nd Ed. Upper Saddle River: Prentice-Hall, 1996.
[11] WATSON, K.; NAGEL, C.; PEDERSEN, J.H.; REID, J.D.; SKINNER, M.; WHITE, E.. Beginning Microsoft Visual C# 2008. Indianapolis: Wiley Publishing, 2008.

segunda-feira, 5 de março de 2018

POO::Plena-17-Associações-agregação de objetos

POO-P-16-Associações-composição POO-P-18-Especificadores e Modificadores
A implementação de sistemas OO envolve o uso de vários objetos inter-relacionados, ou seja, múltiplas instâncias de tipos diferentes, cujas as relações requeridas, lógicas ou de negócios, são obtidas por meio de construções conhecidas como associações.
As associações ou vínculos podem existir entre objetos diferentes, de um mesmo tipo ou de tipos diferentes [2], permitindo a realização de serviços ou a execução de operações, materializando construções ou relacionamentos entre as entidades envolvidas.

Além das associações binárias, isto é, das associações diretas entre duas classes, vistas no post Associações, existem as associações todo/parte que são muito importantes devido a grande frequência de sua ocorrência.

As associações todo/parte permitem expressão a relação existente entre as partes de um todo. Um dos tipos comuns de associação todo/parte é a composição, vista no post anterior. O outro tipo comum é a agregação, tratado a seguir.

Agregações

Uma característica fundamental de uma agregação (agregate) é que o objeto agregado (o todo) pode, potencialmente, existir sem seus constituintes (as partes).

 Considere:
  • Um empresa sem funcionários.
  • Um banco sem correntistas.
  • Um clube sem sócios.
  • Um proprietário sem propriedades.
  • Um container vazio.
Embora possa parecer estranho, tais situações são tanto legalmente, como fisicamente possíveis. Isto torna as agregações bastante diferentes das composições, mesmo sendo um outro tipo de associação todo/parte.

Além disso, a qualquer instante de tempo, um objeto constituinte (parte) pode participar de qualquer número de agregados distintos. Observe que uma pessoa pode manter várias contas correntes, possuir diversas propriedades e bens, além de ser sócia de vários clubes.

O tempo de vida dos objetos constituintes (partes) é usualmente diferente do tempo de suas agregações, tanto maior, como menor. Isto significa que podemos ter agregados (todos) que duram mais que suas partes (membros), tais como agremiações esportivas seculares, que duram mais que seus membros. Também é possível a situação inversa, onde as partes duram mais que a agregação (todo); como um grupo de pessoas que realiza uma viagem ou empresas que duram menos do que seus proprietários ou funcionários.

As agregações tendem a ser homeômeras ou homomorfas, ou seja, as partes constituintes do agregado são, geralmente, do mesmo tipo. É frequente que as agregações sejam usadas para expressar relações entre entidades.

Nos diagramas de classes UML as associações todo/parte do tipo agregação usam diamantes abertos, posicionados do lado do objeto agregado. Tipicamente existe apenas um tipo associado devido a homomorfia, com multiplicidade 0..* ou 0..n. O figura que segue ilustra este tipo de associação.


As associações numa agregação, tal como ocorre na composição, também podem ser navegáveis. A escolha da navegabilidade unidirecional e seu sentido, ou da navegabilidade bidirecional entre o objeto agregado e seus objetos participantes deve levar em conta:
  • O quão frequentemente a agregação precisa ser navegada de parte a parte.
  • A necessidade de remoção de participantes específicos.
  • Que os objetos participantes podem ser reutilizados em outras agregações (situação onde se sugere que os participantes possam referencias o objeto agregado).
Outro aspecto bastante comum e similar às composições é que as mensagens enviadas ao objeto agregado se propaguem para todos os seus participantes.


Exemplo de Agregação

Considere a classe simples Java/C# que segue, a qual possui operações de acesso e mutação do atributo nome, que não pode ser vazio ou nulo; e um construtor que exige um nome.

public class Socio {
   private String nome;

   public Socio(String nome) { setNome(nome); }

   public String getNome() { return nome; }

   public void setNome(String nome) {
      if (nome == null || nome.length()==0) {
         throw new RuntimeException(
            "Nome nao pode ser nulo ou vazio.");
      }
      this.nome = nome;
   }
}

Esta classe Socio será usada em associação a uma classe Clube, cujo código Java é dado a seguir.

public class Clube {
   private ArrayList<Socio> sociedade;

   public Clube() {
      sociedade = new ArrayList<>();
   }

   public void addSocio(Socio socio) {
      if (socio == null) {
         throw new RuntimeException("Socio nao pode ser nulo.");
      }
      sociedade.add(socio);
   }
   public int numOfSocios() { return sociedade.size(); }
   public Socio getSocio(int n) { return sociedade.get(n); }
   public Socio removeSocio(int n) { return sociedade.remove(n); }
}

Um objeto do tipo Clube pode ser criado como segue:
Clube clube = new Clube():

Nesta situação, a instância clube criada não contém qualquer sócio, ou seja, é um agregado vazio. Isto pode ser verificado com:
System.out.println("Num. socios clube = " + clube.numOfSocios());

Novos sócios podem ser adicionados livremente com:
Socio s1 = new Socio("Peter");
Socio s2 = new Socio("César");
clube.addSocio(s1);
clube.addSocio(s2);
clube.addSocio(new Socio("Benedito"));

Isto mostra que os objetos Clube (todo) são agregações de Socio (participante), podendo conter zero ou mais instâncias de seus participantes.

Os participantes podem ser eventualmente removidos da agregação com:
Socio socioRemovido = clube.removeSocio(1);

Observe que o índice fornecido para o método removeSocio(int) é um inteiro entre [0, numOfSocios()).

Composição e Agregação

Tendo visto as duas formas mais comuns de associações todo/parte, é conveniente compará-las resumidamente:
  • Composições representam associações todo/parte, onde todas as partes (componentes), de tipos iguais ou diferentes, devem existir na quantidade adequada para que o todo possa ser considerado completo. Composições são adequadas para expressar o inter-relacionamento sistêmico entre elementos.
  • Agregações expressam associações todo/parte, onde as partes (participantes/constituintes/membros) são geralmente do mesmo tipo, mas que podem participar, simultaneamente, de várias agregações diferentes. As agregações podem estar vazias e, ainda assim, existirem, pois comumente expressam relações entre o todo e suas partes.

Considerações finais

É impossível construir sistemas nos quais não existam associações entre as classes identificadas. Cada tipo de associação permite estabelecer uma relação distinta entre suas partes.

As associações binárias permitem estabelecer vínculos entre classes, geralmente denotando uma relação de uso. Também podem existir associações ternárias ou de maior cardinalidade; e até mesmo classe modeladas com o papel de representar associações particulares.

Nas associações, cada classe envolvida possui um papel e uma multiplicidade, o que permite modelar as situações existentes no mundo real. Em particular, as construções todo/parte, ou seja, composições e agregações, representam situações especiais das associações.

As composições permitem representar sistemas de objetos, onde todos os componentes devem estar presentes para que seja válida. Já as agregações possibilitam representar relações entre objetos, podem estar vazias ou conter um número variável de participantes.

Conhecer e empregar corretamente as associações é fundamental na POO!

POO-P-16-Associações-composição POO-P-18-Especificadores e Modificadores

Referências Bibliográficas

[1] JAMSA, K.; KLANDER, L.. Programando em C/C++: a bíblia. São Paulo: Makron Books, 1999.
[2] PAGE_JONES, M.. Fundamentos do Desenho Orientado a Objeto com UML. São Paulo: Makron Books, 2001.
[3] SOMMERVILLE, I.. Software Engineering. 6th. Ed. Harlow: Pearson, 2001.
[4] DEITEL, H.M.; DEITEL, P.J.. Java: como programar. 6a. Ed. São Paulo: Pearson Prentice-Hall, 2005.
[5] SAVITCH, W.. C++ Absoluto. São Paulo: Pearson Addison-Wesley, 2004.
[6] JANDL JR., P. Introdução ao C++. São Paulo: Futura, 2003.
[7] JANDL JR., P.. Java - guia do programador. 3a. ed. São Paulo: Novatec, 2015.
[8] RUMBAUGH, J.; BLAHA, M.; PREMERLANI, W.; EDDY, F.; LORENSEN, W.. Object-oriented modeling and design. Englewoods Cliffs: Prentice-Hall, 1991.
[9] STROUSTRUP, B.. The C++ Programming Language. 3rd Ed. Reading: Addison-Wesley, 1997.
[10] LANGSAM, Y.; AUGENSTEIN, M. J.; TENENBAUM, A. M.. Data structures using C and C++. 2nd Ed. Upper Saddle River: Prentice-Hall, 1996.
[11] WATSON, K.; NAGEL, C.; PEDERSEN, J.H.; REID, J.D.; SKINNER, M.; WHITE, E.. Beginning Microsoft Visual C# 2008. Indianapolis: Wiley Publishing, 2008.

quinta-feira, 1 de março de 2018

POO::Plena-16-Associações-composição de objetos

POO-P-15-Associações POO-P-17-Associações:agregação
Um sistema OO contém vários objetos inter-relacionados, ou seja, instâncias de tipos diferentes associadas de uma maneira apropriada para produzir os resultados desejados. Assim, as diversas associações existentes entre os objetos de um sistema explicitam as relações lógicas ou de negócios que existem entre seus objetos e, exatamente por isso, devem ser adequadamente representadas.

As associações ou vínculos podem existir entre objetos diferentes, de um mesmo tipo ou de tipos diferentes [2]. Estes ligações constituem os relacionamentos específicos entre tais objetos, o que é muito importante, pois em geral efetivam um serviço ou materializam uma construção.

Por exemplo, uma biblioteca possui livros e usuários, que são entidades de tipos distintos. O empréstimo de um livro, que é o serviço prestado pela biblioteca, vincula um livro específico a um usuário particular, ou seja, cria uma associação livro-usuário.

De maneira semelhante, a construção de um avião corresponde a ligação de vários elementos, como fuselagem, asas, trens de pouso, motor, etc. Também existe uma associação necessária entre tais elementos para constituir uma aeronave.

No post anterior, que tratou das associações, foram vistas as situações gerais onde um objeto está associado a um ou mais objetos. A quantidade de objetos associados é dita cardinalidade ou multiplicidade da associação. Além disso, a maneira com que as associações são construídas permite a que navegação seja unidirecional ou bidirecional.

Também existem associações especiais, conhecidas como associações todo/parte, que relacionam as partes de um todo. Em função do tipo de relação existente entre o conjunto de todos os elementos e suas partes, existem dois tipos particulares de associações todo/parte que merecem um estudo mais detalhado porque ocorrem com muita frequência no desenvolvimento de sistemas OO. São as composições, assunto tratado a seguir; e as agregações, que serão abordadas no próximo post.

Composições

Numa composição (composite), o objeto composto não pode existir como um todo sem que todos os seus componentes estejam presentes, pois ele não estaria íntegro ou completo [2][6]. Considere, rapidamente, uma caneta esferográfica sem sua carga de tinta; uma bicicleta sem guidão; ou um telefone celular sem sua bateria; são exemplos de objetos incompletos que não podem ser utilizados, nem desempenhar seus papeis. Completando tais conjuntos, temos composições válidas.

Existe também outra questão envolvendo o tempo de vida do objeto composto (o todo) e dos objetos componentes (suas partes):
  • O tempo de vida de um objeto composto não pode ultrapassar o tempo de vida de seus componentes.
  • No entanto, o tempo de um, vários ou todos os objetos componentes (as partes) pode ser maior que a vida do objeto composto.
Considerando uma bicicleta, como um todo - completa, ela não pode existir sem uma ou duas de suas rodas, sem seu selim ou guidão. Mas as partes da bicicleta podem existir, mesmo que não montadas como uma bicicleta (ou seja, existem mesmo sem constituir um todo).

Além disso, a qualquer tempo, um objeto componente só pode fazer parte um objeto composto específico. O guidão, o selim e cada parte da bicicleta só podem estar em uma bicicleta em particular. Retirar a roda de uma bicicleta, faz que ela deixe de ser um todo; montando tal roda para completar outra bicicleta, surge outro objeto composto; mas a roda em questão é um objeto único, que só pode estar numa bicicleta ou nenhuma.

Também é muito comum que as composições sejam, geralmente, heterômeras ou heteromorfas, ou seja, objetos compostos cujas partes não são semelhantes, isto é, feitos de partes de tipos diferentes.

É comum que as composições sejam usadas para expressar o interrelacionamento sistêmico entre elementos que devem coexistir para funcionarem adequadamente como um sistema.

Num diagrama de classes UML adicionamos um diamante preenchido nas associações todo/parte do tipo composição, posicionando-o do lado do objeto composto. Por conta da própria heteromorfia, as multiplicidades de cada componente podem ser diferentes, como ilustrado a seguir.


As associações numa composição também podem ser navegáveis. Mas a escolha do desenho da navegabilidade entre o objeto composto e seus objetos componentes deve levar em conta:
  • O quão frequentemente a composição precisa ser navegada de parte a parte.
  • Se os objetos componentes serão reutilizados em outras composições (situação onde se recomenda que os componentes não façam referência ao objeto composto).
Outro aspecto bastante comum é que as mensagens enviadas ao objeto composto se propaguem para todos os seus componentes.

Exemplo de Composição

Considere as classes Java/C# que seguem, nas quais não foram incluídos quaisquer membros, exceto toString(), para simplificação do exemplo. Tais classes são os componentes de uma bicicleta.

public class Roda { 
   public String toString() {
      return getClass().getName();
   }
}
public class Quadro { 
   public String toString() {
      return getClass().getName();
   }
}
public class Selim { 
   public String toString() {
      return getClass().getName();
   }
}
public class Guidao { 
   public String toString() {
      return getClass().getName();
   }
}

A implementação da operação toString() de todos os tipos componentes da bicicleta é idêntica e produz uma String contendo o nome da classe.

Como uma bicicleta é um objeto composto, o qual só pode estar completo com a presença de todos os seus componentes, a classe Java/C# que segue representa uma possível implementação de Bicicleta.

public class Bicicleta {
   private Roda rodaDianteira, rodaTraseira;
   private Quadro quadro;
   private Selim selim;
   private Guidao guidao;

   public Bicicleta(Roda rd, Roda rt, Quadro q, Selim s, Guidao g) {
      if (rd == null || rt == null || rd == rt) {
         throw new RuntimeException("Bicicleta requer duas rodas.");
      }
      if (q == null) {
         throw new RuntimeException("Bicicleta requer um quadro.");
      }
      if (s == null) {
         throw new RuntimeException("Bicicleta requer um selim.");
      }
      if (g == null) {
         throw new RuntimeException("Bicicleta requer um guidao.");
      }
      rodaDianteira = rd; rodaTraseira = rt;
      quadro = q;
      selim = s;
      guidao = g;
   }

   public Roda getRodaDianteira() { return rodaDianteira; }
   public Roda getRodaTraseira() { return rodaTraseira; }
   public Quadro getQuadro() { return quadro; }
   public Selim getSelim() { return selim; }
   public Guidao getGuidao() { return guidao; }

   public String toString() {
      return
            String.format("%s:\n\t%s,\n\t%s,\n\t%s,\n\t%s,\n\t%s\n",
            getClass().getName(), rodaDianteira, rodaTraseira,
            quadro, selim, guidao);
   }  
}

Os membros privados rodaDianteira, rodaTraseira, quadro, selim e guidao são as associações requeridas pelo tipo composto Bicicleta. São declaradas privadas para garantir que não sejam substituídas por null, o que tornaria a composição inválida com a ausência de qualquer um de seus componentes.

O construtor toma como argumentos os componentes exigidos para a composição, validando e rejeitando componentes nulos. Apenas quando fornecidas duas instâncias distintas de Roda, uma instância de Quadro, de Selim e de Guidao, torna-se possível a instanciação de um objeto Bicicleta, como no fragmento que segue:
Bicicleta b = new Bicicleta(new Roda(), new Roda(),
      new Quadro(), new Selim(), new Guidao());
System.out.println(b);

Quando executado, este fragmento produz:
Bicicleta:
        Roda,
        Roda
        Quadro
        Selim
        Guidao

As operações de acesso getter permitem acessar e, portanto, navegar, unidirecionalmente, da instância de Bicicleta para as suas instâncias componentes.

O método toString() de Bicicleta produz uma String que concatena o nome da classe do tipo Bicicleta e, também, os nomes das classes de seus componentes, cujos métodos toString() são implicitamente acionados quando suas referências são usadas para suprir um argumento de tipo %s, que indica um tipo String. Este método mostra uma possível forma de propagação de mensagens entre o objeto composto e seus componentes.

Considerações Finais

As composições representam associações todo/parte, onde todas as partes (componentes), de tipos iguais ou diferentes, devem existir na quantidade adequada para que o todo possa ser considerado completo.

Composições são adequadas para expressar o inter-relacionamento sistêmico entre elementos, como mostrado no exemplo do tipo Bicicleta (composição) e seus componentes Roda, Quadro, Selim e Guidao.

É praticamente impossível construir sistemas onde não existam associações, sendo que as composições são frequentemente utilizadas.


POO-P-15-Associações POO-P-17-Associações:agregação

Referências Bibliográficas

[1] JAMSA, K.; KLANDER, L.. Programando em C/C++: a bíblia. São Paulo: Makron Books, 1999.
[2] PAGE_JONES, M.. Fundamentos do Desenho Orientado a Objeto com UML. São Paulo: Makron Books, 2001.
[3] SOMMERVILLE, I.. Software Engineering. 6th. Ed. Harlow: Pearson, 2001.
[4] DEITEL, H.M.; DEITEL, P.J.. Java: como programar. 6a. Ed. São Paulo: Pearson Prentice-Hall, 2005.
[5] SAVITCH, W.. C++ Absoluto. São Paulo: Pearson Addison-Wesley, 2004.
[6] JANDL JR., P. Introdução ao C++. São Paulo: Futura, 2003.
[7] JANDL JR., P.. Java - guia do programador. 3a. ed. São Paulo: Novatec, 2015.
[8] RUMBAUGH, J.; BLAHA, M.; PREMERLANI, W.; EDDY, F.; LORENSEN, W.. Object-oriented modeling and design. Englewoods Cliffs: Prentice-Hall, 1991.
[9] STROUSTRUP, B.. The C++ Programming Language. 3rd Ed. Reading: Addison-Wesley, 1997.
[10] LANGSAM, Y.; AUGENSTEIN, M. J.; TENENBAUM, A. M.. Data structures using C and C++. 2nd Ed. Upper Saddle River: Prentice-Hall, 1996.
[11] WATSON, K.; NAGEL, C.; PEDERSEN, J.H.; REID, J.D.; SKINNER, M.; WHITE, E.. Beginning Microsoft Visual C# 2008. Indianapolis: Wiley Publishing, 2008.

segunda-feira, 26 de fevereiro de 2018

POO::Plena-15-Associações

POO-P-14-Objetos que usam objetos POO-P-16-Associações:composições
No mundo real, os muitos tipos de objetos que existem aparecem tanto de maneira isolada, como elementos independentes, como associados a outros objetos. As técnicas de construção de sistemas por meio da Programação Orientada a Objetos (POO) contemplam maneiras para representar as diferentes associações que podem existir entre os objetos.

Associações

Uma associação representa um vínculo (ou ligação) possível entre instâncias de classes, ou seja, entre objetos que podem ser tanto de um mesmo tipo, como de tipos diferentes [2].

O vínculo existente entre instâncias representa um relacionamento de natureza específica, como:
  • Um aluno de um curso e as disciplinas ou módulos que cursou;
  • Um usuário de uma biblioteca e um livro por ele emprestado;
  • Uma propriedade imóvel e seu proprietário;
  • Um sócio ou um membro de um clube ou agremiação;
  • As rodas de um veículo ou partes de uma máquina.
Assim, as associações podem e, de fato, devem ser documentadas em qualquer projeto, pois representam os relacionamentos requeridos entre as entidades do seu modelo (de negócio, de dados, etc).

A Unified Modeling Language (UML) é uma linguagem gráfica que possui vários diagramas para representar as visões diferentes de um projeto de software [2][8]. O diagrama de classes UML, em particular, possibilita a representação gráfica de classes, seus atributos e suas operações; possuindo também todos os elementos necessários para expressar as associações existentes entre elas, como ilustrado na figura que segue.


O diagrama exibido contém duas classes, Pessoa e Veiculo, representados por retângulos com três divisões: uma para a identificação da classe (seu nome e, opcionalmente, seu pacote/namespace); uma para os atributos da classe; e outra para as operações da classes. Os atributos e operações são precedidos por um símbolo que indica sua visibilidade: '+' para elementos públicos, '#' para elementos protegidos e '-' para elementos privados; sendo que a ausência de símbolo denota visibilidade de nível pacote.

Também podem existir ligações entre classes, como mostra a figura abaixo, que destaca a ligação entre a classe Pessoa e a classe Veiculo


A associação (ligação) entre as classes Pessoa e Veiculo é denominada propriedade. Cada extremidade também é identificada, o que permite estabelecer como se dá o vínculo de propriedade especificamente para cada tipo (classe) envolvida:
  • Pessoa tem frota de 0..* (zero ou mais) veículos; e
  • Veículo tem 1 (um) proprietário.
A indicação numérica existente em cada extremo de uma associação é a cardinalidade ou multiplicidade da relação, que pode ser:
  • 0..1 -- zero ou um;
  • 0..* -- zero ou mais (qualquer número);
  • 1 -- (apenas) um;
  • 1..* -- um ou mais do que um; e
  • * -- qualquer número.
Assim, tal diagrama pode ser lido como:
  • Pessoas e veículos têm um vínculo denominado propriedade. Uma pessoa possui uma frota (de veículos), com zero até muitos veículos. Um veículo possui apenas um proprietário.

Importância das associações

Modelar as associações entre classes constitui a espinha dorsal da análise técnica que se denomina modelagem de informações. Assim, os diagramas de classes que contêm associações permitem obter informações sobre várias perspectivas da modelagem:
  • Uma associação ou relacionamento é nomeada por uma forma verbal: "propriedade" pode ser também "possuído por".
  • A multiplicidade de relações que é possível, incluindo a ausência de relação (0) quando permitida.
  • Os nomes das associações e dos papéis não são obrigatórios na UML, mas mostram-se muito úteis na etapa de implementação e na interpretação dos diagramas.

Associação básica ou binária

O diagrama que segue mostra associação básica ou binária entre (classes) Pessoa e Cachorro, a qual é denominada PosseDeCachorro:
  • Um Cachorro tem 0..1 (zero ou um) dono (Pessoa).
  • Uma Pessoa possui 0..* (qualquer número) de Cachorros. 

Associação representada por Classe

Uma associação entre classes, tal como a básica entre Pessoa e Cachorro, pode também ser representada por uma classe (dita de associação). Desta maneira, a relação PosseDeCachorro, entre Pessoa e Cachorro, poderia ser expressa assim.


Navegabilidade

É um conceito da UML reservado inteiramente para modelos de implementação orientados a objeto.

A navegabilidade é indicada por setas acrescentadas nas linhas que representam as associações. Ela mostra quando um objeto pode se referir ao outro associado, o que permite acessá-lo, ou seja, navegar até tal objeto. Com isso é possível executar operações relacionadas à associação em si.

A navegação pode ser unidirecional e bidirecional, assim entre duas classes existem três possibilidades de navegação, como mostra a figura que segue, onde se vê a navegação unidirecional de Pessoa para Cachorro, a navegação unidirecional de Cachorro para Pessoa, e também bidirecional entre Pessoa e Cachorro.



Associação, Navegabilidade e Código OO

Cada forma de associação e sua possível multiplicidade tem uma expressão própria em termos de código.

Para ilustrarmos como o código OO pode ser construído para representar as associações de navegação uni e bidirecional, com diferentes multiplicidades, considere a existência das classes A e B, como segue:
public class A {
   // atributos, operações e construtores
   :
}

public class B {
   // atributos, operações e construtores
   :
}

Neste momento, não é necessário conhecermos e considerarmos os eventuais atributos, operações e construtores pertencentes a estas classes.

Navegação unidirecional

Se for desejada uma associação denominada papel, unidirecional, de cardinalidade 0..1 (zero ou um), com navegação de A para B, devemos ter:
public class A {
   // associação de A para B, 0..1
   public B papel;
   // atributos, operações e construtores
   :
}

public class B {
   // atributos, operações e construtores
   :
}

Este código possibilita que:
  • Quando o atributo papel de uma instância da classe A é nulo, temos a situação de nenhum objeto do tipo B está associado ao primeiro (multiplicidade = 0).
  • Quando o atributo papel de uma instância da classe A contém uma referência válida, temos a situação de um objeto do tipo B associado ao primeiro (multiplicidade = 1).
  • Quando a instância de A contém um referência válida, é possível navegar do objeto  de tipo A para o objeto de tipo B. O contrário não é possível, assim temos uma navegação unidirecional.
Então, temos que este código permite que cada instância de A possa, livremente, ser associada a zero ou uma instância de B, permitindo a navegação de A para B apenas (é a classe que possui um campo para representar a associação que possibilita suas instâncias de acessar a - navegar para - instância associada).

Para inverter o sentido da navegação, bastaria colocar o atributo de navegação na outra classe, ou seja, para uma associação denominada papel, unidirecional, de cardinalidade 0..1 (zero ou um), com navegação de B para A, devemos ter:

public class A {
   // atributos, operações e construtores
   :
}

public class B {
   // associação de B para A, 0..1
   public A papel;
   // atributos, operações e construtores
   :
}

As características desta associação são as mesmas, apenas com a navegabilidade invertida.

Para navegação bidirecional, o campo de associação deve estar presente nas duas classes, como segue.

public class A {
   // associação de A para B, 0..1
   public B papel;
   // atributos, operações e construtores
   :
}

public class B {
   // associação de B para A, 0..1
   public A papel;
   // atributos, operações e construtores
   :
}

O exemplo acima permite a navegação bidirecional entre A e B, mantendo a multiplicidade 0..1 em cada extremidade da associação.

No entanto, esta estrutura de código não é robusta. Cabe ao programador garantir a consistência entre quaisquer associações construídas!

Considerações finais

Como um sistema OO contém vários objetos interrelacionados, é necessário representar adequadamente as diferentes associações que podem existir entre os objetos, isto é, os vínculos entre instâncias de tipos diferentes, pois tais associações explicitam as relações lógicas ou de negócios que existem entre tais objetos.

Assim é muito importante modelar as associações entre classes, atividade essencial na análise técnica que se denomina modelagem de informações, a qual culmina num projeto orientado a objetos.

As associações, com sua identificação, cardinalidade e possibilidade de navegação expressam o uso típico que os objetos fazem dos demais. Particularmente existem as associações todo/parte, dentre as quais a composição e a agregação merecem estudo mais cuidadoso, a ser visto nos próximos posts!

POO-P-14-Objetos que usam objetos POO-P-16-Associações:composições

Referências Bibliográficas

[1] JAMSA, K.; KLANDER, L.. Programando em C/C++: a bíblia. São Paulo: Makron Books, 1999.
[2] PAGE_JONES, M.. Fundamentos do Desenho Orientado a Objeto com UML. São Paulo: Makron Books, 2001.
[3] SOMMERVILLE, I.. Software Engineering. 6th. Ed. Harlow: Pearson, 2001.
[4] DEITEL, H.M.; DEITEL, P.J.. Java: como programar. 6a. Ed. São Paulo: Pearson Prentice-Hall, 2005.
[5] SAVITCH, W.. C++ Absoluto. São Paulo: Pearson Addison-Wesley, 2004.
[6] JANDL JR., P. Introdução ao C++. São Paulo: Futura, 2003.
[7] JANDL JR., P.. Java - guia do programador. 3a. ed. São Paulo: Novatec, 2015.
[8] RUMBAUGH, J.; BLAHA, M.; PREMERLANI, W.; EDDY, F.; LORENSEN, W.. Object-oriented modeling and design. Englewoods Cliffs: Prentice-Hall, 1991.
[9] STROUSTRUP, B.. The C++ Programming Language. 3rd Ed. Reading: Addison-Wesley, 1997.
[10] LANGSAM, Y.; AUGENSTEIN, M. J.; TENENBAUM, A. M.. Data structures using C and C++. 2nd Ed. Upper Saddle River: Prentice-Hall, 1996.
[11] WATSON, K.; NAGEL, C.; PEDERSEN, J.H.; REID, J.D.; SKINNER, M.; WHITE, E.. Beginning Microsoft Visual C# 2008. Indianapolis: Wiley Publishing, 2008.