Baixe o app para aproveitar ainda mais
Prévia do material em texto
53 PROGRAMAÇÃO ORIENTADA A OBJETOS II Unidade III 5 PADRÕES DE PROJETO O desenvolvimento de programas de computadores é uma atividade bastante complexa, que frequentemente envolve a solução de diversos tipos de problema. Mesmo em um projeto absolutamente novo, existe uma série de problemas que aparecem de forma recorrente e com algum grau de variabilidade. Para auxiliar no projeto e no desenvolvimento de programas, arquitetos de software, programadores e pesquisadores da área catalogaram um conjunto de situações e suas possíveis soluções. Esses são os chamados padrões de projeto da área de software. Existem diversos livros que funcionam como verdadeiros compêndios de padrões de projeto, mas dois são dignos de nota. • O livro de Gamma et al. (2000), um dos clássicos da área, contém grande variedade de padrões catalogados. • O livro de Larman (2007) apresenta uma boa introdução aos conceitos das metodologias de desenvolvimento (especialmente as metodologias ágeis) e do uso da UML. No livro de Gamma et al. (2000), os padrões de projeto são divididos de acordo com escopos e propósitos. Com relação aos propósitos, três tipos são identificados: • padrões de criação; • padrões estruturais; • padrões comportamentais. Os padrões de criação estão vinculados à geração dos objetos. Os padrões estruturais estão ligados à maneira como as diversas classes de um projeto se relacionam e aos objetos que funcionam como a estrutura do programa. Os padrões comportamentais estão relacionados aos aspectos dinâmicos, ou seja, à interação entre os objetos (GAMMA et al., 2000). Nas próximas seções, vamos explorar brevemente cada uma dessas categorias, buscando ilustrar o uso dos padrões de projeto. 5.1 Padrões de criação Todos os padrões de criação trabalham com o problema de geração de objetos. À primeira vista, pode parecer estranho termos toda uma categoria de padrões de projeto apenas para essa finalidade, uma vez 54 Unidade III que, na maioria das linguagens orientadas a objetos, a criação de um objeto é feita a partir do operador new. Contudo, devemos ser cautelosos e entender a motivação da existência desses padrões. Cada vez que instanciamos (ou seja, criamos) um objeto de uma classe utilizando o operador new, geramos uma espécie de acoplamento no código. Esse acoplamento vem do fato de que estamos escolhendo, naquele ponto de desenvolvimento do código, a classe específica e concreta que será utilizada para criar determinado objeto. Para ilustrar essa situação, suponha que uma empresa tenha uma loja virtual que vende produtos de limpeza. Durante muito tempo, esses foram os únicos produtos vendidos. Mas, agora, a empresa está vendendo também produtos para escritório, como canetas e papel. No projeto do sistema, foi observado que tais produtos apresentam uma mesma interface, ou seja, podem ser manipulados da mesma forma. Contudo, nesse exemplo hipotético, vamos imaginar que os dois tipos de produto têm comportamento diferente e, portanto, devem ter implementação diferente. Essa situação é ilustrada na figura 28, que representa um esboço de diagrama de classes para o problema (nem todas as classes e nem todos os métodos estão mostrados). ProdutoLimpeza ProdutoEscritório <<Interface>> Produto Figura 28 – Esboço de diagrama de classes Agora nos preocupamos em como são criados os objetos das classes ProdutoLimpeza e ProdutoEscritório. Como dissemos anteriormente, poderíamos utilizar uma estratégia direta, mas há também outra abordagem: instituir uma classe cujos objetivos são justamente criar os objetos e devolver referências para os objetos criados. Observe, na solução apresentada na figura 29, a classe abstrata chamada de CriadorProduto. Nessa classe, devemos declarar um método virtual chamado de factoryMethod(), que deve ser implementado pelas classes CriadorProdutoEscritório e CriadorProdutoLimpeza. Cada uma dessas classes (que são classes concretas) tem o objetivo de designar uma instância de um ProdutoEscritório e um ProdutoLimpeza. Essa estratégia de solução é a utilizada pelo padrão de projeto Factory Method, também chamado de construtor virtual. 55 PROGRAMAÇÃO ORIENTADA A OBJETOS II ProdutoLimpeza ProdutoEscritório <<Interface>> Produto CriadorProdutoEscritório + factoryMethod(): Produto CriadorProduto + factoryMethod(): Produto + outroMetodo() CriadorProdutoLimpeza + factoryMethod(): Produto Figura 29 – Diagrama de classes do padrão de projeto Factory Method Existem outros padrões de projeto de criação, como o Abstract Factory, o Builder, o Prototype e o Singleton, que apresentam escopo voltado ao objeto. O Factory Method apresenta escopo voltado às classes (GAMMA et al., 2000). 5.2 Padrões estruturais Vamos explorar alguns padrões de projeto estruturais. O Adapter, por exemplo, é um padrão estrutural com o escopo voltado às classes. O motivo da sua existência é o problema que ocorre quando temos de trabalhar com várias interfaces que não foram originalmente projetadas para operar em conjunto. O propósito é funcionar como um adaptador – daí o seu nome (outro nome encontrado é invólucro). Vamos observar um exemplo muito simples de uso desse padrão, mostrado na figura 30. Suponha que na loja de produtos de limpeza é vendido um limpador de vidros por volume, ou seja, o comprador especifica a quantidade, em litros, de produto que ele quer comprar. O sistema deve verificar o valor do produto e selecionar a embalagem adequada para armazenar a quantidade especificada pelo cliente. <<Interface>> LimpadorVidroComprador LimpadorVidroImportado AdaptadorLimpadorVidro + compraVolume(litro: double) + compraVolume(usgallon: double) + compraVolume(litro: double) Figura 30 – Diagrama de classes do padrão do adaptador 56 Unidade III A loja tem várias opções de limpador de vidro, algumas delas importadas. No caso do produto importado, o custo por volume é dado em unidades diferentes do sistema métrico utilizado no Brasil. Nesse caso, em vez de utilizar litros, o sistema usa gallons, unidade típica dos Estados Unidos. Existem classes diferentes para a representação de cada um dos produtos: LimpadorVidroNacional (que não está mostrada no diagrama) e LimpadorVidroImportado. Observamos que ambas as classes apresentam um método compraVolume(), mas recebem os argumentos em unidades diferentes. Vemos que há uma classe Comprador, que utiliza a interface LimpadorVidro. Nesse exemplo, não queremos que a classe Comprador tenha de fazer cálculos de conversão entre unidades: queremos que ela empregue a mesma interface LimpadorVidro e que a conversão seja feita de forma automática. Isso é realizado pela classe AdaptadorLimpadorVidro, que faz as conversões e usa, internamente, a classe LimpadorVidroImportado. É importante termos em mente que estamos pensando em um exemplo simplificado, visto que o cliente real sabe a origem do produto (nacional ou importado). A questão é que, internamente, não queremos que o código fique “poluído” com conversões entre interfaces. Além disso, para organizarmos melhor a conversão entre diferentes interfaces, utilizamos um adaptador, que é a ideia básica do padrão Adapter. Outro padrão estrutural importante é o Composite. Ele é útil quando precisamos representar uma hierarquia de objetos e tratar essa hierarquia de maneira uniforme. Para ilustrarmos o seu uso, podemos observar a figura 31. Produto + obtemPreço(): double + aplicaDesconto(valor: double) + adicionaProduto(p: Produto) + removeProduto(cod: int) + obtemProduto(cod: int): Produto Vassoura + obtemPreço(): double + aplicaDesconto(valor: double) Sabão + obtemPreço(): double + aplicaDesconto(valor: double) LimpadorVidro + obtemPreço(): double + aplicaDesconto(valor: double) PacoteProdutos + obtemPreço(): double + aplicaDesconto(valor: double) + adicionaProduto(p: Produto) + removeProduto(cod: int) + obtemProduto(cod: int): Produto Figura 31 – Diagrama de classes do padrão Composite Ainda no contexto da loja de produtos de limpeza,suponha que esse estabelecimento venda produtos diferentes: limpadores de vidro, vassouras e sabão. A loja também comercializa um pacote de produtos, que corresponde a uma assinatura mensal na qual o cliente recebe determinada quantidade 57 PROGRAMAÇÃO ORIENTADA A OBJETOS II de todos esses produtos mensalmente. Esses não são os únicos produtos da loja, e é possível que existam pacotes compostos de outros pacotes, o que forma uma árvore de produtos. Para trabalharmos com essa árvore de maneira uniforme, podemos utilizar o padrão Composite. Observamos, na figura 31, que existe uma classe para cada um dos produtos: LimpadorVidro, Vassoura e Sabão. Existe outra classe chamada de PacoteProdutos, que representa o pacote mensal. Finalmente, há uma classe abstrata (que provavelmente será uma interface na implementação) chamada de Produto. Ao fazermos com que as demais classes (inclusive PacoteProdutos) sejam subclasses de Produto, criamos uma forma homogênea de trabalhar com a hierarquia: podemos saber o preço pelo método obtemPreço() ou podemos aplicar descontos por meio de aplicaDesconto(), independentemente de estarmos tratando de um produto individual ou de um pacote de produtos. Outro padrão estrutural bastante útil é o Decorator. O objetivo desse padrão é permitir que adicionemos comportamentos (ou responsabilidades) a um objeto de forma dinâmica (FREEMAN et al., 2014). Um aspecto importante desse padrão é que as funcionalidades são adicionadas sem que mudemos a classe do objeto original, ou seja, sem que modifiquemos o código. Adicionalmente, o objeto original não deve saber quais são essas novas funcionalidades a serem adicionadas. 5.3 Padrões comportamentais Finalmente, analisaremos alguns exemplos de padrões comportamentais, aqueles ligados à forma como os objetos interagem (GAMMA et al., 2000). Vamos começar com o exemplo do padrão Observer. Ele é utilizado em situações nas quais um objeto muda de estado e nos casos em que devemos notificar vários outros objetos que foram previamente registrados (FREEMAN et al., 2014). Para criarmos esse padrão, devemos inicialmente definir uma interface Subject, também chamada de Publisher. Nela, há métodos para registrar, remover e notificar observadores (Observers). Podemos criar várias classes concretas que implementem essa interface. Além disso, os observadores devem implementar a interface Observer, que, em geral, apresenta um único método: update(). Assim, a dinâmica desse padrão é a seguinte. • Os objetos são registrados no Subject por meio de um método como registerObserver(). • A classe concreta que implementa a interface chama, no momento adequado, os métodos update() de cada um dos objetos registrados e atualiza, simultaneamente, o estado de um grupo de objetos. É por isso que dizemos que esse padrão estabelece uma relação de dependência de “um-para-muitos” entre um conjunto de objetos (FREEMAN et al., 2014). Outra situação na qual estamos focados em relação ao comportamento de objetos refere-se à utilização de diversos algoritmos. Muitas vezes, queremos ter flexibilidade para usar diversos tipos de 58 Unidade III algoritmo, sem necessariamente precisarmos alterar o código-fonte em diversos pontos. Desejamos simplesmente escolher um algoritmo e encaixá-lo em um ponto do programa. Um caso de utilização desse padrão no exemplo da loja de produtos está nas possibilidades de pagamento: clientes diferentes poderiam ter formas e condições de pagamento diferenciadas. Poderíamos ter uma forma de pagamento para clientes regulares, outra para clientes especiais e outra para clientes de grandes quantidades. Nesse exemplo, como a estrutura geral do pagamento continua a mesma e apenas os algoritmos empregados para calcularmos as parcelas de uma venda são diferentes, podemos utilizar um padrão de projeto chamado de Strategy, como ilustrado na figura 32. Pagamento + calculaParcelas(): Parcela[] LimpadorVidroImportado <<Interface>> Parcelamento + calculaParcelas(): Parcela[] LimpadorVidroImportadoParcelamentoClienteNormal + calculaParcelas(): Parcela[] LimpadorVidroImportadoParcelamentoClienteEspecial + calculaParcelas(): Parcela[] LimpadorVidroImportadoParcelamentoClienteGrandeVolume + calculaParcelas(): Parcela[] Figura 32 – Diagrama de classes do padrão Strategy Observamos que a classe Pagamento apresenta um método chamado de calculaParcelas() e que a classe Pagamento conhece apenas a interface Parcelamento. Cada uma das classes, PacelamentoClienteNormal, ParcelamentoClienteEspecial e ParcelamentoClienteGrandeVolume, deve implementar a interface Parcelamento e calcular as parcelas de acordo com um algoritmo especial. Agora, basta a classe Pagamento escolher a forma de parcelamento desejada e encaixar o algoritmo desejado de modo transparente (por causa da interface Parcelamento e do uso do padrão Strategy). 5.4 Padrão MVC (Model-View-Controller) O padrão MVC (Model-View-Controller) foi idealizado para resolver o problema da construção de interfaces com o usuário. Ele é considerado, por alguns autores, um padrão arquitetural, e não apenas um padrão de projeto. Na prática, ele faz uso de outros três padrões: Composite, Observer e Strategy. A ideia é identificar três tipos de objeto: Model (modelo), View (visualização) e Controller (controle), como mostra a figura 33. 59 PROGRAMAÇÃO ORIENTADA A OBJETOS II Model View Controller Notifica Notifica Atualiza Atualiza tela Dados entrados pelo usuário Figura 33 – Diagrama de classes do padrão MVC Vale notar que o diagrama da figura 33 não é um diagrama UML; é apenas um pequeno diagrama esquemático para entendermos a ideia geral do padrão MVC. O Model deve conter as informações do domínio, visto que se trata do modelo do domínio, de modo completamente independente da apresentação, ou seja, da interface do usuário. O oposto ocorre em relação à View: ela não deve conter nenhuma regra de negócio e deve centrar-se apenas no desenho da interface. Finalmente, é necessário um terceiro elemento, o Controller, que estabelece a conexão entre a View e o Model. Assim, as solicitações vindas da View (devido às interações do usuário com a interface – por exemplo, clicando em algum ícone) são recebidas pelo Controller, que atualiza o Model. Devido a essas atualizações, pode haver a necessidade de alterarmos elementos da tela, com notificação à View, como mostra a figura 33. Pode acontecer, em outras situações, que o Controller tenha de atualizar a View. A popularização do padrão MVC fez com que várias empresas criassem produtos cujas estratégias estão essencialmente baseadas nesse padrão. Esse é o caso do ASP.NET MVC, por exemplo. Para termos uma ideia do seu funcionamento, podemos iniciar o Microsoft Visual Studio e criar um novo projeto ASP.NET MVC (ASP.NET Web Application) ou montar uma estrutura de projetos para trabalhos em WindowsForms. Existem outros padrões de design relacionados ao MVC, como o MVVM (Model-View-View Model) e o MVP (Model View Presenter). O MVP é um padrão para a interface do usuário que fica entre o Model e a View e formata os dados para a View. No MVVM, devido à abstração da View, é possível uma espécie de ligação bidirecional entre o Model e a View, o que torna possível que as atualizações no Model sejam apresentadas diretamente na View e que as atualizações na View sejam enviadas diretamente ao Model. O MVVM foi criado para o Windows Presentation Foundation da Microsoft. 60 Unidade III 5.5 Arquiteturas em camadas Um padrão arquitetural muito importante na computação é aquele no qual um sistema é estruturado em camadas. Buschmann et al. (1996) atentam para o fato de que cada camada é composta por um conjunto de subtarefas que podem ser agrupadas em níveis de abstração. Coulouris et al. (2012) complementam dizendo que a ideia é a de que determinada camada utilize os serviços providos pela camada inferior, sem conhecer os detalhes de implementação. Isso está esquematizado na figura 34.Conjuntos de subtarefas agrupadas em níveis de abstração Utiliza serviços providos pela camada inferior Camada Figura 34 – Características da camada O número de camadas varia em função da complexidade da arquitetura. Uma típica arquitetura cliente-servidor é composta por apenas duas camadas. Outra abordagem envolve três camadas: uma camada de apresentação, uma camada de aplicação (também chamada de camada de negócio) e uma camada de dados (COULOURIS et al., 2012). A camada de apresentação é a primeira camada: ela é tipicamente aquela em que o usuário interage, é composta pela interface gráfica e pode estar na máquina do cliente. A camada de aplicação é a segunda camada: ela apresenta a lógica do negócio e, normalmente, está localizada no servidor de aplicação. A camada de dados é a terceira camada: ela provê um mecanismo de armazenamento de longo prazo para a aplicação. Não existe limitação teórica para o número de camadas, de forma que podemos ter sistemas com N camadas, como normalmente referido na literatura. Na área de redes, há diversos exemplos de utilização de arquiteturas em camadas. O modelo TCP/IP, por exemplo, é composto por cinco camadas: camada de aplicação, camada de transporte, camada de rede, camada de enlace e camada física (KUROSE; ROSS, 2013). Quando desenvolvemos um website, não devemos nos preocupar com os detalhes da comunicação dos dados ou da eletrônica. Isso é feito naturalmente por uma pilha de protocolos TCP/IP. No próximo capítulo, vamos explorar o desenvolvimento de programas escritos na linguagem C#. 6 CRIAÇÃO DA CAMADA DE APRESENTAÇÃO E APLICAÇÕES EM LINGUAGEM C# Para criarmos a interface relativa à camada de apresentação, vamos, inicialmente, abrir a IDE de programação Microsoft Visual Studio 2019, como mostra a figura 35. Nessa tela, devemos selecionar a opção Criar um projeto. 61 PROGRAMAÇÃO ORIENTADA A OBJETOS II Figura 35 – Microsoft Visual Studio 2019 Após selecionarmos a opção Criar um projeto, obtemos uma tela com uma série de opções, como mostra a figura 36. Nessa tela, devemos selecionar a opção Aplicativo do Windows Forms (.NET Framework). Figura 36 – Criando um projeto WindowsFormsApplication 62 Unidade III Agora, configuramos as opções do projeto. Inicialmente, selecionamos um nome para o projeto e um nome para a solução e escolhemos um local adequado para manter o projeto, como ilustrado na figura 37. O MS Visual Studio já costuma atribuir um nome padrão – no caso, WindowsFormsApp1 –, mas podemos escolher outro nome, como AplicacaoTeste. Depois de escolhermos o nome e preenchermos os campos necessários, selecionamos o botão Criar. Figura 37 – Definindo o nome de um projeto WindowsFormsApplication Feito isso, visualizamos uma tela como a mostrada na figura 38. Observamos que, no centro da tela, temos uma janela de aplicação do Microsoft Windows completamente vazia. É nessa janela que iremos trabalhar a construção da interface. Figura 38 – Projeto WindowsFormsApplication 63 PROGRAMAÇÃO ORIENTADA A OBJETOS II Na lateral esquerda, temos a Caixa de Ferramentas, mostrada na figura 39, na qual encontramos os diversos controles e elementos que devemos utilizar para criar a interface gráfica da aplicação. Figura 39 – Caixa de Ferramentas Na lateral direita da tela, vemos uma aba chamada de Gerenciador de Soluções (ou Solution Explorer, se estivermos utilizando a versão do Microsoft Visual Studio em inglês). Essa aba, mostrada na figura 40, tem informações sobre a estrutura da aplicação, como propriedades e informações a respeito das classes utilizadas. Figura 40 – Gerenciador de Soluções Suponha que, no processo de criação do projeto, resolvamos criar uma aplicação com o nome AplicacaoTeste. Vamos explorar os itens do gerenciador para entendermos quais informações são sumarizadas nesse caso. Na árvore de informações do Gerenciador de Soluções, encontraremos itens como os indicados a seguir. 64 Unidade III • AplicacaoTeste. Trata-se do nome da aplicação definida no momento da criação do projeto, conforme mostra a figura 41. Figura 41 – AplicacaoTeste: nome da aplicação • Properties (propriedades). Trata-se das propriedades do projeto. Nesse item, podemos visualizar cada label utilizado no projeto e as configurações realizadas para o funcionamento da aplicação, conforme mostra a figura 42. Figura 42 – Properties (propriedades) • References (referências). Trata-se do local onde são listadas todas as referências utilizadas na execução da aplicação, conforme mostra a figura 43. Figura 43 – References (referências) • App.config. Trata-se de um arquivo de configuração da aplicação automaticamente criado pelo ambiente de desenvolvimento, conforme mostrado na figura 44. Esse item pode conter, por 65 PROGRAMAÇÃO ORIENTADA A OBJETOS II exemplo, a configuração de conexão ao banco de dados. Observe que o arquivo está no formato xml e pode ser editado diretamente, conforme mostra a figura 45. Figura 44 – App.config Figura 45 – Classe App.config Saiba mais Para saber mais sobre arquivos de configuração dentro do ambiente .NET, consulte a documentação oficial disponível no link indicado a seguir. MICROSOFT. Configuring apps by using configuration files. In: MICROSOFT DOCS. 30 Mar. 2017. Disponível em: https://docs.microsoft. com/en-us/dotnet/framework/configure-apps/. Acesso em: 7 jul. 2020. • Form1. Trata-se de um ícone que representa o formulário da aplicação na árvore do gerenciador de soluções, conforme mostrado na figura 46. O formulário em que vamos dispor os componentes está mostrado na figura 47. Figura 46 – Form1.cs 66 Unidade III Figura 47 – Form1 • Program. Trata-se do arquivo Program.cs, que contém um método importante para a aplicação, o método Main(). Esse método é o primeiro a ser executado quando a aplicação é rodada (DOYLE, 2014). Observe, na figura 48, que o arquivo aparece no topo da hierarquia, com as classes nele definidas mostradas nos níveis mais internos. Note que a classe estática Program apresenta o método Main. Vale destacar que uma classe é estática quando não pode ser instanciada – por exemplo, por meio de um operador new (TROELSEN; JAPIKSE, 2017). Na figura 49, temos o código-fonte armazenado no arquivo Program.cs. Vemos, na linha 19, o momento no qual o Form1 é criado. Figura 48 – Program.cs 67 PROGRAMAÇÃO ORIENTADA A OBJETOS II Figura 49 – Editando o arquivo Program.cs Muitas vezes, precisamos adicionar mais formulários a uma aplicação em virtude da sua complexidade e de outras questões, como a usabilidade. Assim, vamos estudar como podemos adicionar um formulário à aplicação. Na aba do Gerenciador de Soluções, clicamos com o botão direito do mouse no item com o nome da nossa solução – no caso, AplicacaoTeste. Com isso, temos acesso a um menu como o ilustrado na figura 50. Figura 50 – Menu com itens a serem selecionados 68 Unidade III Selecionamos a opção Formulário (Windows Forms)…, como aparece na figura 51. Isso leva à tela de adição de novos itens, como mostra a figura 52. Figura 51 – Adicionar, Formulário (Windows Forms)… Figura 52 – Tela para adicionar um novo item ao projeto AplicacaoTeste 69 PROGRAMAÇÃO ORIENTADA A OBJETOS II Nessa tela, vemos que podemos adicionar diversos itens ao projeto, como os mostrados na figura 53 e indicados a seguir. • Classes. • Formulários. • Classes de componentes. • Arquivos Bitmap. Figura 53 – Templates que podem ser adicionados ao projeto AplicacaoTeste Devemos selecionar Formulário, como indicado na figura 53. Após adicionarmos o novo formulário, o Gerenciador de Soluções é automaticamente atualizado e exibe o novo formulário adicionado, conforme mostra a figura 54. Figura 54 – Form2 adicionado à Solution Explorer 70 Unidade III Um problema que podemos observar refere-se ao fato de que os nomes dados automaticamente pelo Microsoft Visual Studio não são muito descritivos. No caso, os formulários foram numerados sequencialmente (Form1, Form2 etc).Vamos alterar o nome dos formulários para tornar o nosso código mais legível. Observação É importante termos um critério para a nomeação de variáveis, formulários etc. Isso aumenta bastante a legibilidade do código. Para renomearmos o formulário Form2, devemos clicar com o botão direito em cima do nome do formulário no Gerenciador de Soluções e acionar a ação Renomear (ou Rename, caso estejamos utilizando a versão do programa em inglês), conforme mostra a figura 55. Figura 55 – Renomeando Form2 no Solution Explorer Quando selecionamos a opção para renomear o formulário, o Microsoft Visual Studio permite que façamos a edição direta no nome na própria árvore da solução, como mostra a figura 56. 71 PROGRAMAÇÃO ORIENTADA A OBJETOS II Figura 56 – frmMensagem: nome do novo formulário No caso, vamos renomear o formulário de Form2 para frmMensagem. Para tanto, pressionamos a tecla Enter após terminarmos a edição. Como isso implica uma mudança no código-fonte do programa, gerado automaticamente, seremos perguntados se queremos que a mudança se propague para todas as referências, como mostra a figura 57. Selecionamos a opção Sim, visto que queremos que a alteração seja feita (ou teríamos erros e problemas ao trabalharmos com o código). Figura 57 – Alteração de nome de Form2 Devemos observar que o procedimento anterior não mudou o nome que aparece na barra de título do programa. Isso acontece porque o texto na barra de título vem de outra propriedade, que pode ser mudada de forma independente do nome do arquivo do formulário. Para alterarmos o texto da barra de título, primeiramente selecionamos o formulário que queremos modificar (no caso, frmMensagem). Depois, clicamos com o botão direito do mouse em uma área vazia do formulário, como mostra a figura 58. Observamos o menu contextual que aparece e selecionamos a opção Propriedades. 72 Unidade III Figura 58 – Propriedades (Properties) do formulário Form2 Agora, apresentamos, no lado direito da tela, uma aba de propriedades, relacionadas ao formulário frmMensagem, conforme mostra a figura 59. Selecionamos a opção Text e alteramos o texto para outro nome. No caso, apenas para fins didáticos, vamos chamar o texto também de frmMensagem. Figura 59 – Propriedades do formulário 73 PROGRAMAÇÃO ORIENTADA A OBJETOS II É interessante verificarmos as propriedades listadas. Existem diversas características que podem ser alteradas, como: • nome do título; • cor de fundo; • tamanho do formulário; • fonte; • controles do formulário. Vemos, pela figura 60, que, ao alterarmos a propriedade Text de Form2 para frmMensagem, o texto no topo do formulário também é automaticamente alterado. Figura 60 – Propriedade Text alterada para frmMensagem Se executarmos o programa nesse momento, visualizamos uma tela como a mostrada na figura 61. Figura 61 – Formulário em modo de execução 74 Unidade III A fase de levantamento de requisitos envolve, entre outras tarefas, a construção dos protótipos de tela. Eles são “desenhos” que estabelecem como devem ser as telas da aplicação, normalmente validados pelo cliente, e que orientam o desenvolvedor na construção do programa. Na figura 62, temos um exemplo de protótipo de tela simples. Figura 62 – Exemplo de protótipo de tela Vamos utilizar o protótipo de tela da figura 62 como base para construirmos uma pequena aplicação. Para isso, usaremos alguns componentes padrão do Microsoft Visual Studio, expostos a seguir. • Label. Responsável por alocarmos um rótulo na camada de apresentação (figura 63). • TextBox. Responsável por adicionarmos dados de entrada e de saída na camada de apresentação (figura 64). • Button. Responsável por executarmos uma ação (figura 65). Figura 63 – Componente Label Figura 64 – Componente TextBox 75 PROGRAMAÇÃO ORIENTADA A OBJETOS II Figura 65 – Componente Button Esses componentes podem ser encontrados na Caixa de Ferramentas (ou Toolbox, na versão em inglês), conforme mostra a figura 66. Figura 66 – Controles comuns contidos na aba Caixa de Ferramentas Vamos, inicialmente, adicionar o texto “Digite uma mensagem”. Para isso, incluímos um componente Label. Para introduzirmos o componente, clicamos na opção Label da Caixa de Ferramentas e arrastamos o componente para o formulário. Observe que esse componente também apresenta propriedades como cor, tamanho e posicionamento. Com os procedimentos descritos, obtemos como resultado a imagem mostrada na figura 67. 76 Unidade III Figura 67 – Formulário com o Label adicionado Precisamos adicionar o texto que deve ser mostrado na tela pela alteração da propriedade Nome do Label. Para fazermos isso, devemos clicar com o botão direito do mouse sobre o Label. Desse modo, vemos um menu como o mostrado na figura 68. Figura 68 – Menu de ações do label1 77 PROGRAMAÇÃO ORIENTADA A OBJETOS II Selecionamos a opção Propriedades e observamos todas as propriedades desse componente, conforme mostrado na figura 69. Figura 69 – Propriedades do componente label1 Selecionamos a opção Text e digitamos o texto que queremos que seja mostrado na tela. No caso, escrevemos “Digite uma mensagem:”, como ilustra a figura 70. Figura 70 – Propriedade Text do componente label1 78 Unidade III Vamos renomear o Label para lblDigiteMensagem. Assim, se for necessário manipular esse objeto no código, teremos um nome mais significativo do que apenas Label. Para isso, selecionamos a opção Name e fazemos a mudança desejada, conforme mostra a figura 71. Figura 71 – Propriedade Name do componente Label É comum que times de desenvolvimento adotem uma padronização para nomes de variáveis e componentes. No quadro 2, temos uma sugestão de esquema de nomeação dos diversos componentes do programa. Quadro 2 – Componentes, seus nomes e texto Componente Propriedade Name Propriedade Text Label lblDigiteMensagem Digite uma mensagem: TextBox txtDigiteMensagem N/A Button btnOk Ok Observamos que, para cada componente, as primeiras letras da propriedade Name remetem à identificação do tipo de componente. Por exemplo, em lblDigiteMensagem, as letras lbl são uma abreviação de Label. No caso do Botão, o nome btnDigiteMensagem começa com as letras btn, que são uma abreviação de Button. 79 PROGRAMAÇÃO ORIENTADA A OBJETOS II Observação Ainda que a utilização de um esquema de nomeação não seja uma regra nem algo obrigatório, trata-se de uma boa prática de programação. Posteriormente, quando tivermos de manipular o componente via código, é muito mais fácil identificarmos a funcionalidade de um componente com um nome significativo, como lblDigiteMensagem, do que com nomes genéricos, como label1. Vamos adicionar o componente TextBox de modo similar ao que fizemos para inserir o Label. Para isso, basta localizarmos o componente na Caixa de Ferramentas e o arrastarmos para o ponto desejado, conforme mostrado na figura 72. Figura 72 – Adicionando o componente TextBox ao formulário 80 Unidade III Podemos mudar, também, a propriedade Name da mesma forma que fizemos com o Label. Para isso, clicamos com o botão direito do mouse sobre o componente (TextBox) e obtemos o menu de contexto mostrado na figura 73. Figura 73 – Menu de ações do componente TextBox No menu apresentado, devemos selecionar a opção Propriedades. Assim, é apresentada, na lateral direita, a lista de propriedades do componente, conforme mostra a figura 74. Figura 74 – Propriedades do componente TextBox 81 PROGRAMAÇÃO ORIENTADA A OBJETOS II Devemos encontrar e selecionar a propriedade Name e alterá-la para txtDigiteMensagem, conforme mostra a figura 75. Figura 75 – Propriedade Name alterada para txtDigiteMensagem O próximo componente que deve ser inserido no formulário é o Botão. Para isso, devemos buscar o componente na Caixa de Ferramentas, clicar no componente Button e arrastá-lo para o ponto desejado no formulário, como mostra a figura 76. Figura 76 – Componente Button adicionado ao formulário 82 Unidade III Após essaação, devemos acessar as propriedades do componente Button, clicando sobre ele com o botão direito e selecionando o item Propriedades, conforme mostra a figura 77. Figura 77 – Menu de ações do componente Button O resultado, mostrado na figura 78, é similar ao resultado dos casos anteriores. Figura 78 – Propriedades do componente Button Vamos alterar as propriedades Name e Text. • A propriedade Name deve ser mudada para btnOk, conforme mostra a figura 79. • A propriedade Text deve ser mudada para Ok, conforme mostra a figura 80. 83 PROGRAMAÇÃO ORIENTADA A OBJETOS II Figura 79 – Propriedade Name do componente Button Figura 80 – Propriedade Text do componente Button Após todos esses passos, a tela construída tem aspecto similar à da figura 81. Figura 81 – Camada de apresentação 84 Unidade III Contudo, ainda que esse “desenho” da aplicação já se pareça com um programa real, ainda não executamos o programa propriamente dito. Para que possamos fazer essa execução, o Microsoft Visual Studio deve compilar o programa e, posteriormente, realizar a aplicação. Isso pode ser feito pelo acionamento do botão Iniciar, que fica no menu superior do Microsoft Visual Studio, como mostra a figura 82. Vale lembrar que, se houver erros no programa (como erros de sintaxe no código-fonte), não é possível executar a aplicação. Nesse caso, o Microsoft Visual Studio aponta os erros e busca ajudar o desenvolvedor a corrigir a aplicação. Figura 82 – Botão Iniciar, que executa a aplicação 85 PROGRAMAÇÃO ORIENTADA A OBJETOS II Na figura 83, temos o resultado da execução do programa. Se interagirmos com o programa executado, notaremos que ele não tem funcionalidade. Por isso, devemos fechar a tela do programa e voltar ao Microsoft Visual Studio. Figura 83 – Resultado da execução 86 Unidade III No momento, o programa é apenas uma tela com um campo para digitarmos um texto. Vamos adicionar uma funcionalidade simples: queremos que o usuário digite um texto no componente TextBox e que, depois de acionar o botão Ok, o conteúdo digitado apareça logo abaixo da tela, como o conteúdo de um componente Label. Para isso, devemos inserir mais um componente Label no projeto. Introduzimos esse componente abaixo da caixa de texto, conforme mostra a figura 84. Não é necessário que o posicionamento fique no exato local indicado na figura, mas precisamos nos certificar de que existe espaço suficiente para que a mensagem do usuário seja exibida. Figura 84 – Inserindo um novo Label no formulário 87 PROGRAMAÇÃO ORIENTADA A OBJETOS II Vamos alterar as propriedades Name e Text do novo componente adicionado. Para isso, clicamos com o botão direito do mouse em algum ponto dentro do quadrado que delimita o componente Label e selecionamos a opção Propriedades, como mostra a figura 85. Figura 85 – Menu de ações do componente label1 88 Unidade III Selecionamos a propriedade Name e mudamos o seu nome para lblMensagem, conforme mostra a figura 86. Figura 86 – Alterando a propriedade Name Ainda resta mudarmos a propriedade Text do componente Label, conforme mostra a figura 87. Podemos digitar um texto padrão, como exibido na figura: “Sua mensagem aparecerá aqui!”. No entanto, há um problema: queremos que a propriedade mostre a mensagem de texto digitada pelo usuário. Assim, se o usuário digitar “Olá!” e clicar no botão Ok, nesse local da tela deveríamos visualizar o texto “Olá!”. A questão é que não sabemos qual é o texto que o usuário pode digitar. Apenas sabemos que, ao digitar o texto, essa informação está armazenada no componente TextBox. Desejamos copiar o conteúdo desse componente para o Label e, com isso, mostrarmos o texto em outra parte da tela. Figura 87 – Propriedades do componente Label adicionado 89 PROGRAMAÇÃO ORIENTADA A OBJETOS II Para fazermos o que foi explicado, precisamos escrever o código-fonte na linguagem C#, que manipula as informações vindas dos componentes do formulário. Sabemos que a mensagem deve ser copiada após o usuário clicar no botão Ok. Logo, devemos codificar essa ação do botão. Para isso, clicamos duas vezes no botão exibido no formulário, de forma que o Microsoft Visual Studio exiba a tela de texto mostrada na figura 88, na qual é possível programar as ações dos componentes. Figura 88 – Modo de codificação Na figura 88, temos parte do código-fonte da aplicação em estudo em linguagem C#. Nessa figura, há um detalhe importante a ser destacado: observamos que o código foi gerado automaticamente pelo Microsoft Visual Studio, a partir da nossa interação com a aplicação. Isso simplifica bastante o processo de desenvolvimento. No momento não é necessário nos preocuparmos com todos os detalhes do código. Vamos nos centrar apenas no trecho de código que devemos alterar. Já temos a definição de uma classe chamada de Form1 na linha 13, correspondente ao formulário que estamos editando. Essa classe é composta por vários métodos, sendo um deles o método btnOk_Click, mostrado na linha 20. Esse é o método que precisamos alterar para implementarmos a funcionalidade desejada. Quando o usuário digita um texto na TextBox, ele fica armazenado na propriedade Text desse componente. O nome que escolhemos para o componente é txtDigiteMensagem. Vale lembrar que, quando escrevemos um código e queremos ter acesso a um atributo de um objeto, utilizamos a notação objeto.atributo (supondo que a visibilidade seja adequada no contexto). Assim, para acessarmos a propriedade Text de txtDigiteMensagem devemos fazer: txtDigiteMensagem.Text 90 Unidade III Mas isso ainda não é tudo o que precisamos fazer. Devemos copiar o conteúdo de txtDigiteMensagem. Text para a propriedade Text de outro componente – no caso, lblMensagem. Para acessarmos a propriedade Text de lblMensagem, devemos fazer algo similar: lblMensagem.Text Agora, realizamos a cópia do conteúdo de txtDigiteMensagem.Text para lblMensagem.Text. Fazemos isso com o operador de atribuição =. Vale lembrar que esse operador funciona da seguinte forma: Destino = Origem Dessa forma, devemos fazer: lblMensagem.Text = txtDigiteMensagem.Text; Esse código deve ser executado pelo botão quando ele for clicado, ou seja, esse código deve estar dentro do método btnOk_Click, como mostrado na linha 22 da figura 89. O ponto e vírgula no final é necessário na linguagem C# para indicar o final de um comando, algo bastante comum em várias linguagens de programação, como C, C++ e Java. Contudo, nem todas as linguagens trabalham dessa forma. A linguagem Python, por exemplo, não requer esse delimitador. Figura 89 – Código do botão Ok 91 PROGRAMAÇÃO ORIENTADA A OBJETOS II Se executarmos a aplicação com o botão Iniciar, conforme mostra a figura 82, ela deve ser automaticamente compilada e iniciada (caso não existam erros no nosso código). Obtemos a tela mostrada na figura 90. Figura 90 – AplicacaoTeste sendo executada Agora, devemos inserir algum texto na TextBox. Por exemplo, podemos digitar o texto “Bons Estudos!”, como mostra a figura 91. No entanto, enquanto não clicarmos no botão Ok, o conteúdo do Label inferior continua o mesmo (no caso, o texto padrão “Sua mensagem aparecerá aqui!”). Porém, ao pressionarmos o botão Ok, o conteúdo deve mudar para “Bons Estudos!”, como aparece na figura 91. Figura 91 – Label recebe palavra digitada na caixa de texto 92 Unidade III Assim, conseguimos criar uma aplicação simples na linguagem C#. Vamos fazer um segundo exemplo, um pouco mais complexo. Considere uma aplicação que simule uma calculadora básica. Essa aplicação deve ter dois campos para a entrada de dados, um campo para a saída de informação (resultado do cálculo) e botões representando as quatro operações básicas da matemática (adição, subtração, multiplicação e divisão). Na figura 92, temos um protótipo da tela dessa aplicação. Figura 92 – Protótipo de uma calculadora simples Para construirmos uma aplicação com a interface ilustrada no protótipo, vamos precisar dos seguintes componentes:• 3 componentes do tipo Label; • 4 botões; • 3 caixas de texto (TextBox). No quadro 3 a seguir, apresentamos os tipos de componente, os nomes sugeridos (propriedade Name) e o texto contido no componente (propriedade Text). 93 PROGRAMAÇÃO ORIENTADA A OBJETOS II Quadro 3 – Componentes a serem utilizados no projeto Componente Nome do componente Texto do componente Label lblDigitePrimeiroNumero Digite o primeiro número Label lblDigiteSegundoNumero Digite o segundo número Label lblResultado Resultado Button btnAdicao + Button btnSubtracao - Button btnMultiplicacao * Button btnDivisao / TextBox txtDigitePrimeiroValor TextBox txtDigiteSegundoValor TextBox txtResultado Vamos adicionar os componentes ao programa segundo os procedimentos expostos nos passos a seguir. Passo 1. Inicialmente, criamos um novo projeto (do tipo WindowsFormsApplication) com o nome de Calculadora. Obtemos a tela mostrada na figura 93. Figura 93 – Projeto WindowsFormsApplication: calculadora 94 Unidade III Passo 2. Inserimos cada um dos componentes no formulário, arrastando-os e soltando-os, como fizemos no exemplo anterior. Dispomos os componentes no formulário seguindo o protótipo apresentado e obtemos a tela mostrada na figura 94. Figura 94 – Formulário: calculadora 95 PROGRAMAÇÃO ORIENTADA A OBJETOS II Passo 3. Devemos alterar as propriedades Name e Text de todos os componentes adicionados e do próprio formulário (a janela). Para isso, clicamos com o botão direito do mouse em cada um dos componentes e selecionamos a opção Propriedades. Como exemplo, consideremos o primeiro botão. Se clicamos com o botão direito do mouse sobre ele, obtemos o menu mostrado na figura 95. Selecionamos a opção Propriedades. Depois, na tela seguinte, mostrada na figura 96, alteramos a propriedade Text para + e a propriedade Name para btnAdicionar. A configuração resultante é mostrada na figura 97. Figura 95 – Menu de contexto para o botão Figura 96 – Alterando a propriedade Text do botão 96 Unidade III Figura 97 – Alterando a propriedade Name do botão Passo 4. Repetimos o processo de alteração para todas as propriedades Name e Text de todos os componentes adicionados e, também, do próprio formulário (janela). A configuração resultante é mostrada na figura 98. Figura 98 – Calculadora com todos os componentes adicionados 97 PROGRAMAÇÃO ORIENTADA A OBJETOS II Em qualquer programa, devemos pensar nos tipos de dado manipulados. A título de exemplo, vamos construir uma calculadora que trabalhe apenas com números inteiros, ou seja, números como 1, 10, -5, 0 etc. Dessa forma, não podemos entrar com números como 0,5 ou 12,7. Vamos assumir que essa seja uma restrição do nosso problema. Vamos refletir sobre como fazer as operações matemáticas e obter os resultados. A estratégia geral para a solução do problema é a seguinte. Primeiramente, declaramos duas variáveis inteiras que vão conter os valores de entrada dados pelo usuário. Declaramos, também, mais uma variável inteira que vai conter o resultado da operação matemática. Os valores das duas primeiras variáveis inteiras (que representam as entradas do usuário) devem ser obtidos das TextBox do formulário. Entretanto, aqui temos um problema: um conflito de tipos. Conforme dito inicialmente, as variáveis e as contas devem ser feitas com números inteiros. Contudo, o tipo da propriedade Text da TextBox é string, que é o tipo que a linguagem C# utiliza para armazenar cadeias de texto. Isso significa que devemos fazer uma conversão de string para inteiro e, depois, atribuir esse valor convertido para a variável. Uma vez feita a conversão e com os valores devidamente atribuídos às variáveis, realizamos o cálculo desejado e atribuímos o resultado desse cálculo para a variável que vai armazenar o resultado. Agora, temos o problema inverso: precisamos atualizar o valor da TextBox para mostrar o resultado calculado. No entanto, o resultado calculado encontra-se no formato de um número inteiro. Logo, precisamos converter tal resultado do formato de inteiro para o formato de cadeia (string) e atribuir essa cadeia à propriedade Text da TextBox. Vamos iniciar a escrita do código-fonte em linguagem C#. Por exemplo, vamos atribuir o comportamento da soma. Para isso, clicamos duas vezes no botão soma (aquele com o símbolo +) e somos redirecionados para o editor de código-fonte, conforme mostra a figura 99. Figura 99 – Modo codificação 98 Unidade III Observamos, na figura 99, a existência do método btnAdicionar_Click. Trata-se do método que devemos alterar para adicionarmos o comportamento desejado da calculadora. O nome gerado pelo Visual Studio, btnAdicionar_Click, está associado ao evento que vai ser processado pelo método, ou seja, o evento gerado quando o usuário clicar no botão. Esse não é o único evento possível. Para termos uma ideia dos eventos disponíveis para o componente em análise, podemos clicar com o lado direito do mouse sobre o botão e selecionar a opção Propriedades, conforme mostra a figura 100. Figura 100 – Propriedades do botão + Logo abaixo da janela de propriedades, existe um ícone com um símbolo de raio que lista os eventos atribuídos ao botão, como mostra a figura 101. Figura 101 – Eventos do botão + Observamos, na figura 101, que o evento acionado é o Click, no qual iremos codificar inicialmente. Vale notar que existem diversos eventos que podemos utilizar para a ação de um botão. 99 PROGRAMAÇÃO ORIENTADA A OBJETOS II Vamos escrever o código-fonte da adição. A primeira etapa consiste em declararmos as variáveis que receberão o conteúdo digitado na tela, conforme mostra a figura 102. Figura 102 – Declaração de variáveis Declaramos, nas linhas 22, 23 e 24, respectivamente, as variáveis valor1, valor2 e resultado, todas do tipo primitivo int (número inteiro). É por isso que devemos ter em mente que todos os cálculos são feitos de tal forma que os resultados apresentados também são números inteiros. Isso é particularmente problemático no caso da divisão, mas trata-se de uma limitação do exemplo em construção. É interessante verificarmos, na figura 102, uma facilidade que o Microsoft Visual Studio oferece: diferentes cores para diferentes aspectos do código-fonte. Observamos que as três variáveis são mostradas sublinhadas na cor verde, o que significa que essas variáveis foram declaradas, mas não foram usadas no código. A ideia da utilização de diferentes cores é ajudar o programador nas tarefas de codificação e de depuração. 100 Unidade III Devemos atribuir os valores de entrada dados pelo usuário às variáveis declaradas. Uma primeira tentativa é mostrada na figura 103: ela ocorre nas linhas 26 e 27, nas quais tentamos copiar o valor da propriedade Text de uma TextBox para uma variável inteira. A linha está sublinhada em vermelho porque temos um erro no código, referente aos tipos das variáveis, que são conflitantes. Por exemplo, na linha 27, valor2 é uma variável do tipo inteira (int), mas a propriedade Text de txtDigiteSegundoValor é do tipo string, o que não permite atribuição direta. Figura 103 – Variáveis recebendo valores informados na tela 101 PROGRAMAÇÃO ORIENTADA A OBJETOS II Para fazermos a atribuição, precisamos proceder à conversão de tipos. Felizmente, existe uma classe pronta que apresenta vários métodos para realizar a conversão, a classe Convert. Essa classe tem um método estático, chamado de ToInt16, que faz a conversão de um tipo string para um tipo inteiro de 16 bits. Devemos fazer isso para o conteúdo das duas TextBox, como mostrado nas linhas 26 e 27 da figura 104. Os valores convertidos são atribuídos às respectivas variáveis, valor1 e valor2. Figura 104 – Convertendo o tipo primitivo (string para inteiro) 102 Unidade III Visto que já temos os resultados nas variáveis inteiras, podemos realizar o cálculo solicitado. Na figura 105, na linha 29, fazemos a operação de adição das variáveis valor1 e valor2 e atribuímos o resultado obtido à variávelresultado, também do tipo inteiro. Como todas as variáveis têm o mesmo tipo, não há necessidade de nenhuma conversão. Figura 105 – Variável resultado recebendo o valor da soma 103 PROGRAMAÇÃO ORIENTADA A OBJETOS II O problema proposto ainda não está terminado. Temos de fazer com que o valor contido na variável resultado seja apresentado na TextBox txtResultado. Contudo, precisamos atribuir o valor de uma variável inteira a uma propriedade do tipo string. Logo, precisamos fazer outra conversão, de inteiro para string. Para isso, utilizamos outro método estático da classe Convert, o método ToString, como indicado na linha 31 da figura 106. Uma vez feita a conversão, podemos atribuir a string para a propriedade Text de txtResultado. Figura 106 – Componente txtResultado recebendo o valor da variável resultado 104 Unidade III Nesse ponto, já podemos testar a funcionalidade de adição que acabamos de codificar. Para isso, empregamos um atalho útil: pressionamos a tecla F5 do teclado. Assim, obtemos a configuração mostrada na figura 107. Figura 107 – Aplicação em modo de execução Vamos fazer um teste no programa: a soma dos números 10 e 10. Devemos digitar o primeiro número na primeira caixa de texto de entrada e o segundo número na segunda caixa de texto de entrada, conforme mostra a figura 108. Figura 108 – Valores informados na caixa de texto 105 PROGRAMAÇÃO ORIENTADA A OBJETOS II Após informarmos os valores, clicamos no botão + da tela, o que leva à execução do código apresentado anteriormente. Com isso, o valor da soma é apresentado na caixa de texto resultado, conforme mostra a figura 109. Figura 109 – Valor da soma apresentado na caixa de texto resultado É interessante notarmos que, se clicarmos nos botões que não tiveram nenhuma funcionalidade implementada, nada deve acontecer. Continuaremos adicionando funcionalidades ao longo deste livro-texto. Agora que sabemos que o código implementado está correto, seguimos implantando as demais funcionalidades. Devemos fechar o programa e implementar a funcionalidade de multiplicação. Para isso, clicamos duas vezes no botão *, o que leva à tela de edição de código. Escrevemos um código similar ao código da adição, exceto pelo fato de a operação feita com as variáveis ser a multiplicação. Logo, devemos fazer: resultado = valor1 * valor2; Observe o código-fonte mostrado na figura 110, com a linha da multiplicação (linha 43) em destaque. A aplicação foi executada e testamos a multiplicação de dois inteiros, como aparece na parte direita da figura. Figura 110 – Multiplicação 106 Unidade III A operação de subtração deve ser feita assim: clicamos duas vezes no botão de subtração e editamos o código como nos exemplos anteriores. O cálculo que devemos realizar é: resultado = valor1 - valor2; O resultado final é o mostrado na figura 111. Figura 111 – Código que efetua a subtração de valores Resta agora implementarmos a funcionalidade da divisão. Contudo, essa funcionalidade é um pouco mais complexa, pois precisamos tratar de um caso especial: o fato de não existir a divisão por zero. Saiba mais Leia o seguinte artigo para entender um pouco mais sobre o tema. OLIVEIRA, G. A. Divisão por zero. In: ESCOLA KIDS. [s.d.]. Disponível em: http://www.escolakids.com/divisao-por-zero.htm. Acesso em: 26 jul. 2020. Suponha que fizéssemos o código da divisão de forma similar aos códigos anteriores, obtendo a configuração mostrada na figura 112. Se executarmos a aplicação e tentarmos fazer a divisão dos números 10 e zero, obteremos a mensagem de erro mostrada na figura 112, exatamente na linha da divisão. Nesse caso, o Microsoft Visual Studio identificou o problema na linha do cálculo, parou a execução do programa e exibiu para o programador o ponto em que ocorreu o problema. 107 PROGRAMAÇÃO ORIENTADA A OBJETOS II Figura 112 – Problema da impossibilidade da divisão por zero Existem diversas formas de lidarmos com esse tipo de problema. Na próxima seção, vamos revisar o conceito de desvio condicional e ver como esse recurso pode ser utilizado para resolver a questão. 6.1 Desvios condicionais Quando escrevemos um programa em linguagem C#, a execução é feita de forma sequencial, ou seja, linha por linha e comando por comando. No entanto, há situações nas quais queremos desviar a execução do código ou executar um trecho de código apenas em casos especiais. Há, também, situações nas quais não queremos que determinado trecho de código seja executado. No exercício da calculadora, por exemplo, precisamos evitar que a divisão seja feita quando o divisor for zero. 6.1.1 Condição Um desvio condicional tem esse nome porque requer a avaliação de uma condição para que uma decisão seja tomada. Por exemplo, podemos ter uma situação em que um aluno faz duas provas e precisamos calcular a média das notas. Se essa média for maior ou igual a 5, o aluno é considerado aprovado. Se escrevermos um código no qual a variável media contém o valor calculado, temos a condição media >= 5,0 para que o aluno seja aprovado. Essa condição é uma expressão lógica e, portanto, deve ser avaliada apenas como verdadeira ou falsa. 6.1.2 Decisão Precisamos de um comando que seja capaz de avaliar uma condição e, com base nela, executar trechos de código. Na realidade, existem duas possibilidades para esse comando, expostas a seguir. • Avaliar uma condição e, caso ela seja verdadeira, executar um trecho de código. Se a condição for falsa, o trecho de código não deverá ser executado. Esse é o chamado desvio condicional simples. • Avaliar uma condição e, se ela for verdadeira, executar um trecho de código. Se a condição for falsa, um trecho de código diferente deverá ser executado. Esse é o caso do desvio condicional composto. 108 Unidade III Podemos, agora, retornar ao problema do exemplo. Só devemos fazer a operação de divisão caso o divisor seja diferente de zero. Por isso, adicionamos um desvio condicional (comando if) ao programa, como mostrado na linha 71 da figura 113. Figura 113 – Código em linguagem C# com condicional simples Finalmente, podemos executar o código. Vamos testar o programa fazendo a divisão com os valores mostrados na figura 114, em que temos um quociente com denominador diferente de zero. Figura 114 – Primeiro teste: quociente com denominador diferente de zero 109 PROGRAMAÇÃO ORIENTADA A OBJETOS II Na figura 115, fazemos outro teste, em que temos um quociente com denominador igual a zero. Não obtivemos nenhum erro, mas o programa não executou nenhuma ação. Trata-se de uma situação que pode deixar o usuário confuso. Figura 115 – Segundo teste: quociente com denominador igual a zero Para auxiliar o usuário, vamos exibir uma mensagem de erro no caso da divisão por zero. Observe que essa mensagem deve ser exibida apenas quando o divisor (armazenado na variável valor2) for igual a zero. Assim, devemos aplicar o caso de desvio condicional composto. Na figura 116, entre as linhas 71 e 76, temos um exemplo de uso dos comandos if e else da linguagem C#. Notamos que, quando a condição do if for verdadeira, executamos as linhas 73 e 74. Contudo, como estamos utilizando o comando else juntamente com o comando if, a linha 78 é executada apenas quando a condição do if for falsa, ou seja, no caso complementar. Assim, temos duas possibilidades de linha de execução, mutuamente excludentes e dependentes da condição do comando if. 110 Unidade III Figura 116 – Código em linguagem C# com condicional composta Podemos agora executar o código-fonte, obtendo o resultado mostrado na figura 117. O teste exemplificado na figura é da divisão de 10 por zero, o que fez com que o código exiba a MessageBox. Figura 117 – Apresentação do cenário com falha 111 PROGRAMAÇÃO ORIENTADA A OBJETOS II Saiba mais Leia a definição de Método MessageBox.Show para entender um pouco mais sobre o tema. MICROSOFT. MessageBox.Show method. In: MICROSOFT DOCS. [s.d.]. Disponível em: https://msdn.microsoft.com/pt-br/library/system.windows.forms.messagebox.show%28v=vs.110%29.aspx. Acesso em: 9 jul. 2020. 6.2 Melhorias na solução Neste ponto, a calculadora já apresenta algumas funcionalidades básicas. Porém, como em qualquer programa, ainda podemos realizar melhorias – por exemplo, adicionar um botão para sair da aplicação. Para isso, devemos fazer os passos indicados a seguir. Passo 1. Utilizar a Caixa de Ferramentas (ToolBox) para inserir o componente Button. Passo 2. Alterar a propriedade Name de button1 para btnSair. Passo 3. Alterar a propriedade Text de button1 para Sair. Com isso, obtemos a tela mostrada na figura 118. Figura 118 – Aplicação do botão Sair no modo formulário 112 Unidade III Temos de escrever o código correspondente à ação executada quando clicarmos no botão Sair. Clicamos duas vezes no botão Sair, no modo Design, e somos direcionados ao código-fonte, como mostra a figura 119. Figura 119 – Evento Click do botão Sair Para fecharmos a janela, “chamamos” o método Close(), como mostra a figura 120, linha 84. Figura 120 – Método Close() inserido no evento btnSair_Click Saiba mais Para saber mais sobre o método Close(), leia a documentação oficial. MICROSOFT. Form.Close method. In: MICROSOFT DOCS. [s.d.]. Disponível em: https://msdn.microsoft.com/en-us/library/system.windows.forms.form. close%28v=vs.110%29.aspx. Acesso em: 9 jul. 2020. 113 PROGRAMAÇÃO ORIENTADA A OBJETOS II Podemos executar a aplicação a fim de obtermos a tela mostrada na figura 121. Figura 121 – Aplicação em modo de execução com o botão Sair Se acionarmos o botão Sair, terminaremos a aplicação e voltaremos ao modo de edição do Microsoft Visual Studio. Outra melhoria que podemos agregar à aplicação é adicionar um botão para limpar todos os campos do formulário, o que pode ser prático para o usuário. Para isso, devemos fazer os passos indicados a seguir. Passo 1. Ir à Caixa de Ferramentas (ToolBox) e adicionar o componente Button. Podemos colocá-lo logo acima do botão Sair, como mostra a figura 122. Passo 2. Alterar a propriedade Name do botão adicionado para btnLimpar. Passo 3. Alterar a propriedade Text do botão adicionado para Limpar. Figura 122 – Botão Limpar incluído no modo Design 114 Unidade III Clicamos duas vezes no botão Limpar (no modo Design) e, com isso, podemos implementar o método btnLimpar_Click. Vamos digitar o código mostrado na figura 123. Figura 123 – Código para o evento Click do botão Limpar A estratégia geral de funcionamento do código é simples: na figura 123, nas linhas 89, 90 e 91, atribuímos uma cadeia de texto vazia, string.Empty (que representa a cadeia “”) às propriedades Text de txtDigitePrimeiroValor, txtDigiteSegundoValor e txtResultado. Isso limpa os valores dos campos e remove o conteúdo previamente existente. Em seguida, fazemos com que o foco da aplicação (localização do cursor) vá automaticamente para a primeira caixa de texto por meio do método Focus(), como mostra a linha 92 da figura 123. Depois disso, podemos executar o programa para obtermos a tela mostrada na figura 124. Figura 124 – Ação do botão Soma 115 PROGRAMAÇÃO ORIENTADA A OBJETOS II Para testarmos a aplicação, usamos alguns números (por exemplo, 10 e 5) e executamos uma operação (por exemplo, soma). O resultado deve ser mostrado na caixa de texto inferior da tela, como aparece na figura 124. Se, posteriormente, acionarmos o botão Limpar, todos os campos devem ficar vazios, e o cursor deve ir para a primeira caixa de texto, como mostra a figura 125. Figura 125 – Botão Limpar acionado Lembrete Não podemos esquecer que, após executarmos a aplicação para fazer um teste, devemos fechar a janela da calculadora e voltar ao modo de edição do Microsoft Visual Studio para continuarmos o trabalho no programa. 6.3 Caixa de mensagem (MessageBox) Podemos fazer uma modificação na aplicação com o objetivo de explorarmos algumas funcionalidades da linguagem C#. Em vez de mostrar os resultados em uma caixa de texto única abaixo da janela, vamos exibi-los em uma caixa de mensagem separada. Inicialmente, precisamos lembrar que, na linguagem C#, um comentário é feito com o uso dos caracteres //. Vale notar que um comentário é um trecho de texto que será ignorado pelo compilador e que serve apenas para ajudar o programador a explicar e a entender o código em que ele está trabalhando. Assim, imagine que tenhamos uma linha como a indicada a seguir. // teste de comentário O texto “teste de comentário” será totalmente ignorado pelo compilador. Suponha que digitássemos um comando válido na linguagem C#, como o sugerido a seguir. // valor1 = 0; 116 Unidade III Mesmo nessa situação, o código não seria executado, uma vez que todo o conteúdo da linha após os símbolos // deve ser ignorado. Na figura 126, temos um conjunto de comentários explicativos nas linhas 70, 71, 72 e 73. Na linha 77, o comentário foi utilizado simplesmente para desativar uma linha de código. Nas linhas 82, 83 e 84, temos mais comentários explicativos. Ainda na figura 126, devemos observar a adição da linha 78. Nela, foi introduzida uma MessageBox, que mostra na tela o resultado para o usuário. Observe que o componente MessageBox contém um método Show, que recebe como argumento uma string (uma cadeia de texto). No caso, queremos apresentar para o usuário uma resposta do tipo “O valor da divisão é: 10” em uma caixa de mensagem. Para isso, devemos concatenar o texto “O valor da divisão é:” com o conteúdo da variável resultado. Isso é feito na linha 78 da figura 126. Observe que o argumento passado para o método Show é composto por três partes: • a string fixa (“O valor da divisão é:”); • o operador +, que, aqui, realiza uma concatenação (e não uma soma, pois estamos trabalhando com strings, ou seja, cadeias de texto); • o trecho de código resultado.ToString(), que significa que vamos converter o tipo inteiro armazenado para uma string que pode ser concatenada com outras strings. Figura 126 – Código que possibilita apresentar valor na caixa de mensagem 117 PROGRAMAÇÃO ORIENTADA A OBJETOS II Se executarmos a aplicação agora (por exemplo, pressionando a tecla F5) e testarmos a operação de adição, obteremos o resultado mostrado na figura 127. Figura 127 – Resultado da divisão apresentado na caixa de mensagem Repetimos o mesmo procedimento para as demais operações. Iniciando pela multiplicação, obtemos o código mostrado na figura 128. Após a execução, chegamos ao resultado da figura 129. Figura 128 – Código que possibilita apresentar valor na caixa de mensagem 118 Unidade III Figura 129 – Resultado da multiplicação apresentado na caixa de mensagem Para o caso da subtração, devemos escrever o código exibido na figura 130, que é similar aos códigos anteriores. Após um exemplo de execução, temos como resultado o que é mostrado na figura 131. Figura 130 – Código que possibilita apresentar valor na caixa de mensagem 119 PROGRAMAÇÃO ORIENTADA A OBJETOS II Figura 131 – Resultado da subtração apresentado na caixa de mensagem Resta, ainda, fazermos o caso da adição, mostrado na figura 132. Testando o código, chegamos ao resultado da figura 133. Figura 132 – Código que possibilita apresentar valor na caixa de mensagem 120 Unidade III Figura 133 – Resultado da soma apresentado na caixa de mensagem Devemos implementar o comportamento do botão Sair. Vamos utilizar a seguinte regra: apresentamos uma caixa de mensagem na qual perguntamos ao usuário se ele quer ou não sair da aplicação. Para implantarmos esse comportamento, clicamos duas vezes no botão Sair, no modo Design, e editamos o médoto btnSair_Click, como mostra a figura 134. Figura 134 – Implementação da nova caixa de mensagem Nesse método, usamos uma MessageBox, mas temos de pensar em alguns argumentos especiais. Existem várias opções para a MessageBox. Uma delas é adicionar botões do tipo Sim ou Não para darmos respostas simples do usuário. Isso é feito com o argumento MessageBoxButtons.YesNo. Adicionalmente, podemos: • atribuirum título para a caixa de mensagem (no caso, Atenção); 121 PROGRAMAÇÃO ORIENTADA A OBJETOS II • inserir um ícone para indicar que a caixa representa uma pergunta pelo argumento MessageBoxIcon.Question. Como o usuário deve responder a uma pergunta, o método retorna como resultado qual foi o botão pressionado (Sim ou Não), um valor que deve ser armazenado em uma variável. Na figura 134, essas ações estão ilustradas nas linhas 97 e 98. Observamos que é declarada a variável result para armazenar a resposta do usuário. Na linha 100 da figura 134, detectamos o botão que o usuário selecionou testando o conteúdo da variável result. Se essa variável contiver DialogResult.No, significa que o usuário selecionou o botão No (ou Não) na caixa de mensagem. Observe atentamente a lógica do if: apenas se o conteúdo da variável result for diferente de DialogResult.No, a linha 102 deve ser executada. Essa linha contém o comando Close(), que fecha a aplicação. Assim, somente no caso de o usuário selecionar a opção No é que a aplicação não será fechada, já que o conteúdo da linha 102 não será executado. Ao fazermos essas modificações, executarmos o código e selecionarmos o botão Sair, vemos a mensagem mostrada na figura 135. Para fecharmos a aplicação, selecionamos o botão Sim. Figura 135 – Caixa de mensagem Podemos fazer outras melhorias no código. Por exemplo, a caixa de texto Resultado permanece editável, mas não deveria, já que o seu propósito é apenas mostrar o resultado dos cálculos (ela não pode ser utilizada para a entrada de dados). Observamos, na figura 136, que podemos entrar com valores arbitrários nessa caixa de texto. 122 Unidade III Figura 136 – Editando a caixa de texto de Resultado Caixas de texto apresentam uma propriedade chamada de Enabled, que permite ativar ou desativar a entrada de texto pelo usuário. Se clicarmos com o botão direito do mouse na caixa de texto de Resultado e selecionarmos suas propriedades, obtemos a tela mostrada na figura 137. Figura 137 – Propriedade Enabled da caixa de texto Resultado 123 PROGRAMAÇÃO ORIENTADA A OBJETOS II Percebemos que a propriedade Enabled é do tipo booliano (true/false – verdadeiro/falso). Se quisermos fazer com que a caixa de texto fique bloqueada para edição, devemos selecionar a opção False, como mostra a figura 138. Figura 138 – Propriedade Enabled setada para False Saiba mais Para entender um pouco mais sobre a propriedade Control.Enabled, leia o texto indicado a seguir. MICROSOFT. Control.Enabled property. In: MICROSOFT DOCS. [s.d.]. Disponível em: https://msdn.microsoft.com/pt-br/library/system.windows. forms.control.enabled%28v=vs.110%29.aspx. Acesso em: 10 jul. 2020. 124 Unidade III Vamos alterar o código criado anteriormente e mostrado nas figuras 126, 128, 130 e 132: • na figura 126, “descomentaremos” a linha 77; • na figura 128, “descomentaremos” a linha 45; • na figura 130, “descomentaremos” a linha 60; • na figura 132, “descomentaremos” a linha 31. Dessa forma, podemos mostrar o resultado da operação na caixa de texto pelo comando a seguir: txtResultado.Text = Convert.ToString(resultado); Com essas alterações, o resultado do cálculo é exibido tanto na caixa de texto de resultado quanto na caixa de mensagem na tela. Executando a aplicação, obtemos a tela mostrada na figura 139. Figura 139 – Caixa de texto com a propriedade Enabled False 125 PROGRAMAÇÃO ORIENTADA A OBJETOS II Notamos que a caixa de texto do resultado fica com a cor cinza, e não conseguimos escrever ou editar valores diretamente. Contudo, se fizermos um cálculo, o resultado ainda será exibido, pois ele é diretamente associado pelo código do programa, e não pela edição, conforme mostram as figuras 140, 141, 142 e 143. Figura 140 – Operação de soma apresentando resultado na caixa de texto bloqueada Figura 141 – Operação de subtração apresentando resultado na caixa de texto bloqueada 126 Unidade III Figura 142 – Operação de divisão apresentando resultado na caixa de texto bloqueada Figura 143 – Operação de multiplicação apresentando resultado na caixa de texto bloqueada Outra funcionalidade que podemos colocar na aplicação é a de alterar a visibilidade dos componentes que apresentam os resultados (o Label lblResultado e a caixa de texto txtResultado), para que eles 127 PROGRAMAÇÃO ORIENTADA A OBJETOS II apareçam apenas quando tivermos o resultado de um cálculo, mas fiquem invisíveis antes disso. Para isso, existe a propriedade Visible, que permite ocultar o componente. Essa propriedade também é do tipo booliano (true/false – verdadeiro/falso). Saiba mais Para entender um pouco mais sobre a propriedade Control.Visible, leia o texto indicado a seguir. MICROSOFT. Control.Visible property. In: MICROSOFT DOCS. [s.d.]. Disponível em: https://msdn.microsoft.com/pt-br/library/system.windows. forms.control.visible%28v=vs.110%29.aspx. Acesso em: 10 jul. 2020. Inicialmente, selecionamos as propriedades da caixa de texto txtResultado e alteramos a propriedade Visible, como mostra a figura 144. Figura 144 – Alterando a propriedade Visible da caixa de texto Resultado 128 Unidade III Para essa implementação, precisamos, também, efetuar a alteração da propriedade Visible do componente Label (lblResultado) para False, como mostra a figura 145. Figura 145 – Alterando a propriedade Visible do componente Label Resultado (False) 129 PROGRAMAÇÃO ORIENTADA A OBJETOS II Após efetivarmos essas alterações, se executarmos a aplicação, obteremos um resultado muito similar ao mostrado na figura 146. Figura 146 – Execução da aplicação sem que apareçam os componentes Label e TextBox Se os componentes lblResultado e txtResultado não foram apresentados, como será apresentado o resultado da ação matemática? Temos de habilitar as propriedades Visible para os componentes lblResultado e txtResultado diretamente via código, como mostra a figura 147. Nas linhas 30 e 31 da figura 147, atribuímos o valor true (verdadeiro) para as propriedades Visible de lblResultado e txtResultado, o que faz com que esses componentes se tornem visíveis. Figura 147 – Implementação no evento btnAdicionar_Click 130 Unidade III Quando acionamos o botão Soma, alteramos a propriedade Visible dos componentes lblResultado e txtResultado para true (verdadeiro), o que possibilita a visualização do resultado do cálculo. Por exemplo, se executarmos a aplicação e entrarmos com dois números, mas ainda não fizermos nenhuma operação, obtemos a tela mostrada na figura 148. Figura 148 – Comportamento inicial da aplicação Após selecionarmos uma operação (por exemplo, soma), os componentes lblResultado e txtResultado podem ser imediatamente visualizados na tela com o resultado do cálculo. Além disso, como mantivemos o código da MessageBox, o resultado também é exibido em uma caixa de mensagem na tela, como mostra a figura 149. Figura 149 – Resultado do cálculo apresentado para o usuário 131 PROGRAMAÇÃO ORIENTADA A OBJETOS II Queremos que, quando o usuário pressionar o botão limpar, os componentes lblResultado e txtResultado voltem a ficar invisíveis. Para tanto, devemos alterar suas propriedades relativas a Visible no botão btnLimpar_Click. Com isso, devemos obter o código da figura 150. Figura 150 – Tornando lblResultado e txtResultado invisíveis Se executarmos novamente o programa, podemos fazer alguma operação matemática, como a mostrada na figura 151. Após esse cálculo, se selecionarmos o botão Limpar, retornamos à situação inicial, como mostra a figura 152, sem que os componentes lblResultado e txtResultado fiquem visíveis na tela. Figura 151 – Soma apresentada para o usuário 132 Unidade III Figura 152 – Botão Limpar acionado e aplicação retornando ao estado inicial Ainda há mais melhorias que podemos fazer no programa, como adicionar um componente chamado de GroupBox para ajudar a dispor as informações do formulário na tela. Esse componente encontra-se em ToolBox, Containers, GroupBox, como mostraa figura 153. Figura 153 – Componente GroupBox 133 PROGRAMAÇÃO ORIENTADA A OBJETOS II Devemos, agora, inserir esse componente no formulário, como mostra a figura 154. Figura 154 – GroupBox adicionado no modo Design do formulário Depois da adição do componente, devemos mudar as propriedades indicadas a seguir. • Name – grpEntradaValores • Text – Entrada de Valores Para realizarmos essa ação, clicamos com o botão direito do mouse no componente GroupBox e selecionamos o item Propriedades, da mesma forma que fizemos nos demais componentes, como mostra a figura 155. Figura 155 – Alterando as propriedades Name e Text do componente GroupBox 134 Unidade III Queremos fazer com que os componentes que utilizamos para a entrada de dados fiquem dentro da GroupBox que acabamos de adicionar. Para isso, selecionamos os elementos elencados a seguir, segurando a tecla Ctrl do teclado e clicando nos próprios componentes. • lblDigitePrimeiroNumero • txtDigitePrimeiroNumero • lblDigiteSegundoNumero • txtDigiteSegundoNumero Temos como resultado a tela mostrada na figura 156. Figura 156 – Componentes selecionados 135 PROGRAMAÇÃO ORIENTADA A OBJETOS II Após a seleção, efetuamos a combinação de teclas Ctrl + X para realizarmos o recorte dos componentes. Desse modo, chegamos à tela mostrada na figura 157. Figura 157 – Formulário com os componentes selecionados recortados Em seguida, selecionamos o GroupBox Entrada de Valores e, nele, efetuamos a combinação de teclas Ctrl + V, a fim de fazermos a inclusão dos componentes, como mostra a figura 158. Figura 158 – Componentes inseridos dentro do GroupBox Entrada de Valores 136 Unidade III Rearranjamos o posicionamento do GroupBox Entrada de Valores em um local mais conveniente no formulário, como mostra a figura 159. Figura 159 – GroupBox Entrada de Valores colocado à esquerda do formulário Repetimos os passos anteriores e incluímos o GroupBox Operações Matemáticas, como mostra a figura 160. Figura 160 – Incluindo o GroupBox Operações Matemáticas 137 PROGRAMAÇÃO ORIENTADA A OBJETOS II Copiando os botões para dentro do GroupBox e rearranjando a tela da aplicação, obtemos a tela da figura 161. Figura 161 – GroupBox Operações Matemáticas com os componentes Soma, Subtração, Divisão e Multiplicação Repetimos o mesmo processo para os componentes relativos a Resultado, como mostra a figura 162. Figura 162 – GroupBox com o componente Resultado 138 Unidade III Ao executarmos a aplicação, obtemos a tela da figura 163. Figura 163 – Layout reformulado da aplicação Saiba mais Para entender mais sobre a classe GroupBox, leia o texto indicado a seguir. MICROSOFT. GroupBox class. In: MICROSOFT DOCS. [s.d.]. Disponível em: https://msdn.microsoft.com/pt-br/library/system.windows.forms.group box%28v=vs.110%29.aspx. Acesso em: 10 jul. 2020. Ainda há algumas melhorias adicionais que podemos fazer na aplicação, como: • travar formulário para redimensionamento; • ocultar componentes do formulário (minimizar, maximizar e fechar). 139 PROGRAMAÇÃO ORIENTADA A OBJETOS II Para inibirmos o redimensionamento do formulário, alteramos a propriedade AutoSizeMode para GrowAndShrink, como mostra a figura 164. Figura 164 – Propriedade AutoSizeMode Saiba mais Para entender mais sobre a propriedade Form.AutoSizeMode, leia o texto indicado a seguir. MICROSOFT. Form.AutoSizeMode property. In: MICROSOFT DOCS. [s.d.]. Disponível em: https://msdn.microsoft.com/pt-br/library/system.windows. forms.form.autosizemode%28v=vs.110%29.aspx. Acesso em: 16 jul. 2020. 140 Unidade III Para testarmos o efeito da modificação, podemos executar a aplicação. Veremos que não é possível redimensionar a tela. Nesse momento, a aplicação é similar à mostrada na figura 165. Figura 165 – Aplicação “travada” para redimensionamento Mesmo que tentemos encostar o cursor do mouse em volta do formulário, não será possível efetuarmos o redimensionamento da tela. Isso ocorre devido ao fato de termos mudado a propriedade AutoSizeMode para GrowAndShrink. Outra melhoria reside em ocultarmos a apresentação dos itens Minimizar, Maximizar e Fechar. Para isso, devemos alterar a propriedade ControlBox de frmCalculadora para False, como mostra a figura 166. Figura 166 – Propriedade ControlBox 141 PROGRAMAÇÃO ORIENTADA A OBJETOS II Após a execução dessa alteração, ficamos com um formulário similar ao mostrado na figura 167. Figura 167 – Modo Design atualizado Se executarmos a aplicação, notamos que os botões Minimizar, Maximizar e Fechar são retirados do formulário, como mostra a figura 168. Figura 168 – Aplicação em modo de execução 142 Unidade III Resumo Iniciamos a unidade III abordando os temas de padrões de projeto e trabalhamos com um exemplo de aplicação. Vimos que existem padrões de projeto voltados à criação de objetos, de padrões estruturais e de padrões comportamentais. Com relação aos padrões de criação, vimos o FactoryMethod, no qual geramos classes cujo objetivo é criar objetos e devolver referências para esses objetos. Assim a aplicação recebe tais objetos, em vez de instanciá-los diretamente. Vale notar que a aplicação deve ser escrita de forma a depender da interface que os objetos implementam, e não da sua classe concreta. Quanto aos padrões estruturais, vimos padrões chamados de Adapter, Composite e Decorator. O padrão Adapter permite que criemos uma espécie de adaptador entre objetos que não poderiam se comunicar, em razão de alguma diferença na interface desejada. O padrão de projeto Composite possibilita que trabalhemos com hierarquias complexas de objetos sem que nos preocupemos se estamos lidando com um único objeto ou com toda uma coleção. O padrão Decorator faz com que possamos adicionar comportamento a um objeto sem modificá-lo diretamente. Com relação aos padrões comportamentais, vimos o padrão Observer, que funciona como um mecanismo de notificação de modificação quando um objeto muda de estado. O padrão Strategy permite que mudemos a utilização de um algoritmo de forma transparente ao restante da aplicação. O padrão arquitetural MVC (Model-View-Controller) organiza a aplicação em três tipos de objeto: • objetos ligados ao modelo (Model), que focalizam as regras de negócio; • objetos ligados à visualização (View), que se centram na forma como a informação é apresentada ao usuário; • objetos controladores (Controller), que fazem o papel de ligar o modelo com a visualização. 143 PROGRAMAÇÃO ORIENTADA A OBJETOS II Exercícios Questão 1. Considere as afirmativas a seguir sobre o uso de padrões de projeto (design patterns). I – O uso de padrões de projeto garante que uma aplicação terá baixo custo de manutenção. II – O padrão de projeto Adapter é um padrão estrutural que permite o uso de classes com interfaces que originalmente seriam incompatíveis. O uso desse padrão de projeto possibilita que tais interfaces se comuniquem. III – O padrão de projeto Observer é um padrão comportamental que permite que um grupo de vários objetos sejam notificados de uma mudança de estado em um objeto especial. É correto o que se afirma apenas em: A) I. B) II. C) III. D) II e III. E) I e III. Resposta correta: alternativa D. Análise da questão A primeira afirmativa não é correta, pois a mera aplicação do uso de padrões de projeto não garante que um programa tenha baixo custo de manutenção. O uso correto de padrões e o bom gerenciamento de uma equipe composta por profissionais de qualidade aumentam as chances de que um projeto apresente custo de manutenção adequado. Vale notar que o mero emprego dos padrões, especialmente se não houver a aplicação rigorosa e criteriosa, não assegura baixo custo de manutenção. A segunda afirmativa é correta, uma vez que o caso descrito se refere precisamente ao uso do padrão Adapter. Isso vale para a terceira afirmativa, que também é correta. 144 Unidade III Questão 2. Considere o fragmento de código de um programa escrito na linguagem C# mostrado
Compartilhar