Laboratório 07 – Modularização
Para a resolução deste trabalho, lembre-se organizar seu código seguindo os critérios:
Modularização
Quando desenvolvemos um programa, devemos tomar o cuidado de organizá-lo em atividades simples e bem
definidas. Os comentários nos ajuda a identificar e registrar essas atividades desde a fase de projeto do
algoritmo. É fácil notar que certas atividades devem ser realizadas diversas vezes ao longo do programa para
valores e em situações diferentes. Isso pode fazer com que o trabalho de desenvolvimento se torne um
processo tedioso.
Uma solução para este problema é agrupar um conjunto de códigos responsável por uma determinada
atividade em um módulo, também chamado de método. Podemos definir um módulo da seguinte forma:
Conjunto de instruções para cumprir uma tarefa bem definida agrupadas em uma
unidade com um nome para referenciá-la.
• Reduz o tamanho e a complexidade do programa principal: soluções menores e mais simples são
combinadas para resolver um problema maior;
• Facilita a compreensão e manutenção: a leitura passa a ser pela definição das atividades e não por
códigos;
• Permite e facilita reutilização de soluções já existentes: métodos podem ser utilizados em programas
e soluções diferentes;
• Diminui, e muito, erros nos programas: por serem simples, os módulos são facilmente testados e, ao
reutilizá-los, temos mais garantia de utilizar um código correto.
Um bom desenvolvedor não é aquele que resolve problemas com soluções complexas, mas sim aquele que
resolve um problema complexo de forma simples. A modularização é um dos principais artifícios para
alcançar o sucesso em soluções de algoritmos. Tenha sempre em mente, os problemas devem ser resolvidos
em partes, de preferência mais simples.
Exemplo
Considere o seguinte problema: dado três números inteiros, quero saber se o maior deles é maior que a soma
dos menores. Podemos modelar este problema nas seguintes atividades:
1. Lês os números.
O seguinte programa em C# resolve este problema. Note que o código é organizado conforme as atividades e
elas são registradas pelos comentários.
using System;
namespace ATPLab {
class Program {
static void Main(string[] args) {
int num1 = 0;
int num2 = 0;
int num3 = 0;
int maior = 0;
int soma = 0;
// Le os numeros
Console.Write("\n Digite o primeiro número: ");
num1 = int.Parse(Console.ReadLine());
Console.Write("\n Digite o segundo número: ");
num2 = int.Parse(Console.ReadLine());
Console.Write("\n Digite o terceiro número: ");
num3 = int.Parse(Console.ReadLine());
Console.ReadLine();
}
}
}
Embora o programa esteja bem escrito seguindo as normas de variáveis legíveis, comentários e organização
do código por atividades, podemos ainda melhorá-lo aplicando os conceitos de modularização. Vamos então
entender como métodos podem ser criados em C#.
Em C# os métodos devem ser definidos dentro da classe do programa class Program e fora do método
principal static void Main(string[] args). Para que possamos trabalhar com as variáveis dentro dos
métodos, elas também devem ser declardas fora do método principal. O trecho de código a seguir ilustra onde
métodos e variáveis devem ser declarados:
using System;
namespace ATPLab {
class Program {
Primeiro devemos definir um nome para o método, que deve deixar claro sua atividade. Sua definição deve
ser acompanhada de um comentário que explique a atividade realizada. Como podemos notar o métodos
principal static void Main também é um método, de nome Main. Porém, este método é especial, pois é a
partir dele que o programa começa sua execução. Iremos tomar sua definição como exemplo para criar os
métodos que precisamos para resolver o problema citado anteriormente. Assim, as palavras static void
serão utilizadas para definir um método, e iremos entender para que servem em breve.
Dessa forma, podemos começar a criação dos nossos métodos da seguinte forma:
using System;
namespace ATPLab {
class Program {
Console.ReadLine();
}
}
}
Dessa forma, definimos 4 métodos, um para cada atividade identificada na modelagem do algoritmo. Note que
nosso programa principal agora, método Main, está definido de forma bem simples e é fácil entender o que ele
faz apensa lendo os métodos.
O passo seguinte é definir o corpo, ou o conjunto de códigos, dos métodos. No nosso exemplo, podemos fazer
isso de forma bem simples, basta copiar o que foi feito antes em cada atividade para dentro das definições dos
métodos correspondente, deixando o programa da seguinte forma:
using System;
namespace ATPLab {
class Program {
Console.ReadLine();
}
}
}
Dessa forma, conseguimos separar nosso programas em atividades. Note que cada método criado possui menos
código e é mais fácil de entendê-lo se lido separado dos demais. O método principal contem apenas as chamadas
aos métodos criados, de forma que podemos entender o funcionamento do programa por suas atividades,
expressadas pelos nomes dos métodos.
Para realizar a chamada a um método, basta referenciar seu nome, incluindo os parênteses e finalizando com
ponto-e-vírgula. Uma chamada a um método pode ser entendida como um comando que corresponde a execução
dos comandos definidos dentro do método chamado. Seria equivalente a trocar a chamada do método pelo
conjunto de código correspondente. Devemos lembrar que um método pode ser chamado quantas vezes forem
necessárias para solucionar o programa.
Observe que as variáveis utilizadas dentro dos métodos são aquelas declaradas fora do Main. Se elas estivessem
dentro do Main, como antes, elas não seriam visíveis dentro dos métodos e não poderíamos utilizá-las dessa
forma.
Bom, agora já entendemos como funciona um método e podemos ter uma idéia dos benefícios que a
modularização. Então, vamos entender o que significa o qualificador static antes do nome do método. Sem
entrar em muitos detalhes, como regra de C#, o método principal Main deve obrigatoriamente ser qualificado
como static. Assim, ele só pode realizar chamadas a métodos qualificados como static. Por isso nosso
métodos são todos static.
Outra regra de C# diz que variáveis declaradas fora dos métodos, como no nosso caso, se forem utilizadas dentro
de métodos static também devem ser declaradas com o qualificador static. Não há necessidade de
aprofundarmos neste assunto por enquanto, basta seguir essas regras para utilização de variáveis definidas fora
dos métodos qualificados como static.
Procedimentos e Funções
Todos os nossos métodos foram criados precedidos da palavra void. Isso significa que o métodos não retorna
nenhum valor para quem o chamou. Os métodos podem ser classificados de duas formas:
1. Procedimentos: métodos que não retornam nenhum valor para quem o chamou;
Assim, nossos métodos foram todos criados como procedimentos, já que não retornam nenhum valor e as
operações são realizadas nas variáveis definidas fora dos métodos. Dessa forma, sua execução se equivale a
troca da chamada pelo conjunto de códigos que definem o procedimento.
Para criarmos uma função, basta definir um tipo para o método. Assim como variáveis, um método pode ser
de um determinado tipo, como int, float, double, string etc. Então podemos retornar um determinado
valor para o ponto da chamada da função. Para isso, utilizamos o comando return. Nessa situação,
precisamos armazenar esse valor retornado em alguma variável.
Por exemplo, se alterarmos nosso procedimento somaMenores para retornar a soma, poderíamos fazer da
seguinte forma:
// Soma os numeros menores
static int somaMenores() {
int sm = 0;
sm = num1 + num2 + num3 - maior;
return sm;
}
Assim, somaMenores passa a ser uma função que retorna a soma dos menores números dentre os três criados.
Note que uma variável sm é definida dentro da função. Dentro de qualquer tipo de método podemos declarar
variáveis que sejam necessárias para a solução daquele problema e ela apenas existirá dentro do método.
Assim, sm não é acessível fora do método somaMenores. Quando isso ocorre, dizemos que a variável sm
somente é visível dentro do método somaMenores.
Com isso, o método principal deve ser alterado para receber o valor retornado pela função da seguinte forma:
static void Main(string[] args) {
leNumeros();
encontraMaior();
soma = somaMenores(); // variavel soma recebe retorno da funcao somaMenores
comparaMaior();
Console.ReadLine();
}
Passagem de parâmetros
Procedimentos e funções podem receber parâmetros em sua chamada. Isso significa que podemos passar
valores de qualquer tipo na chamada do método. Este recurso auxilia no isolamento do método
proporcionando maior independência e reusabilidade. A definição dos parâmetros de um método é
semelhante à declaração de variáveis sem valores iniciais. Os parâmetros são definidos entre os parênteses
que seguem o nome do método. Podemos definir quantos parâmetros forem necessários, separados por
vírgula, e cada um deles pode ser de qualquer tipo.
Por exemplo, poderíamos transformar encontraMaior em uma função que recebe três números inteiro e
retorne o maior dentre eles.
// Encontra o maior dentre 3 numeros
static int encontraMaior(int n1, int n2, int n3) {
int m = num1;
if (n2 > m) {
m = n2;
}
if (n3 > m) {
m = n3;
}
return m;
}
Note que dessa forma podemos aproveitar este método em qualquer problema que precisamos encontrar o
maior elementos dentre três números inteiros. Como a função agora não depende de variáveis declaradas
externamente, a reusalbilidade é garantida.
Console.ReadLine();
}
Na chamada da função encontraMaior os valores de num1, num2 e num3 são copiados para os parâmetros n1, n2
e n3. Então, quando utilizamos n1, n2 e n3 dentro de encontraMaior, estamos acessando os valores copiados
de num1, num2 e num3, que estão fora da função. Vale lembrar que a alteração do valor de n1 dentro da função
não altera o valor de num1.
Exercícios
Para praticar os conceitos de modularizção, resolva os seguintes exercícios. Evite a declaração de variáveis
for a dos métodos. Prefira declarações dentro dos métodos e utilize de parâmetros e funções para trocar
valores entre o método principal e seus procedimentos e funções criados.
1. Construa uma função, denominada EhPar(...), que seja capaz de verificar se um inteiro qualquer é par ou
ímpar. A função deverá ter como argumento o inteiro a ser testado.
2. Diz-se que um inteiro é primo se for divisível apenas por 1 e por si mesmo. Por exemplo, 2, 3, 5, 7 são
primos, mas 4,6,8,9 não são. Escreva uma função que determine se um número é primo. Faça um programa
que utilize esta função para determinar e imprimir todos os números primos entre 1 e 1000.
3. Uma disciplina em um curso possui 20 pontos de trabalho, duas avaliações parciais de 25 pontos e uma
avaliação global 30 pontos. Escreva um programa que leia as notas parciais, trabalho e prova final dos alunos
de uma turma e retorne a nota final total e o conceito, dado pela tabela abaixo:
• Uma função que recebe os valores das 4 notas e retorne, simultaneamente, a nota final e o conceito
utilizando passagem de valores por referência.
• Uma função que recebe os valores das 4 notas e retorne, simultaneamente, a nota final e o conceito
utilizando passagem de valores por saída.