6.4. Ainda a abstração procedimental

Ao longo deste capítulo reforçámos a ideia de que a abstração procedimental é extremamente útil na programação:

 

6.4.1. Retângulos de carateres

Usando de novo a abstração procedimental, vamos desenvolver um programa para imprimir um retângulo de carateres. O retângulo da figura abaixo é composto por 6 linhas com 15 asteriscos cada uma:

Vamos começar por construir um método que imprime uma linha com 15 asteriscos:

A última instrução é para provocar a mudança de linha.

Agora é preciso invocar este método seis vezes para obter o retângulo desejado. O seguinte programa obtém o efeito pretendido:

E se quisermos imprimir o seguinte retângulo, com 7 asteriscos em cada linha?

Ou ainda este, com 25 asteriscos em cada linha?

Na verdade, o método imprimeAsteriscos não serve para muita coisa… Teríamos que ter vários métodos quase iguais a este para podermos imprimir os dois retângulos acima, pois o número de carateres em cada linha é diferente.

O ideal era ter um método que permitisse imprimir um asterisco um qualquer número de vezes. Como podemos fazer isso?

Usando abstração de parâmetro – adicionamos um parâmetro que representa o número de asteriscos a imprimir.

Sempre que o método é invocado, um valor específico deve ser indicado para esse parâmetro. Assim obtemos um método mais geral e, portanto, mais útil, pois pode ser usado em várias circunstâncias.

O seguinte programa imprime os três retângulos pretendidos:

 

E se quisermos imprimir o seguinte retângulo?

Ou ainda este?

O ideal era ter um método que permitisse imprimir um qualquer caráter um qualquer número de vezes.

Usando outra vez abstração de parâmetro, adicionamos um segundo parâmetro que representa o caráter a escrever.

Quando o método é invocado, indicamos um valor específico para cada um desses parâmetros. Alteramos também o nome do método para ficar mais de acordo com a sua funcionalidade.

O seguinte programa imprime vários dos retângulos pretendidos:

Se observarmos melhor o método main, vemos que a instrução for que permite repetir a invocação do método imprimeCarateres é praticamente igual nos três casos. As diferenças são:

Além disso, cada um desses ciclos tem como objetivo a escrita de um retângulo no standard output.

Justifica-se então a criação de um método cujo objetivo é o de escrever no standard output um retângulo formado por um dado número de linhas, em que cada linha será formada por um dado número de um qualquer caráter.

O seguinte método faz o que pretendemos:

O programa EscreveRetangulos fica então simplificado e com maior legibilidade:

 

Na verdade, o método imprimeRetangulo poderia ter sido implementado da seguinte forma:

Repare que nesta versão tivemos que substituir a variável de progresso do ciclo interno para j de modo a ficar diferente de i, pois não podemos ter dois ciclos encaixados declarando variáveis de progresso com nomes iguais.

Qual das duas versões é a melhor?

 

Agora imagine que queremos um triângulo retângulo de asteriscos em que a base contém n asteriscos. Se n for 6, queremos:

Como fazer? Repare que queremos escrever n linhas, cada uma com um número de asteriscos que varia conforme a linha. Ou seja, reaproveitando o método imprimeAsteriscos queremos algo parecido com:

Coloca-se então a questão: o que devemos escrever em vez dos ???? Depende.

Na verdade queremos escrever tantos carateres quantos o valor de i!

Então, a nossa função deve ser:

Se optarmos por outra versão sem a invocação do método imprimeCarateres (à semelhança do que fizemos acima com o retângulo), teremos:

 

Descubra como imprimir um triângulo retângulo invertido (com a base em cima e o vértice em baixo).

 

E se agora quisermos imprimir n x m números sucessivos, organizados em n linhas com m números cada? Por exemplo, se n for 3 e m for 4 queremos isto:

Raciocinemos de forma semelhante ao que já fizemos: vamos imprimir uma linha de m números sucessivos, n vezes.

Então vamos ter dois ciclos for encaixados:

O que deverá estar no lugar dos ???? Depende do número de vezes que cada ciclo já foi executado.

Como queremos imprimir um número que, começando em 1, resulta do anterior somando-lhe um, podemos utilizar uma variável para memorizar o número que deve ser impresso a seguir.

Então, é o valor dessa variável que deve ser impresso no corpo do ciclo interno. Essa variável deve ser inicializada com o valor 1, que é o primeiro número que queremos imprimir, e, para que o seu valor progrida, devemos incrementá-la de cada vez que executamos a instrução System.out.print.

Um pequeno exercício – o que imprimiria a seguinte versão?

 


Anterior: 6.3. Ciclos for encaixados

Seguinte: 6.5. Ainda o âmbito das variáveis