Desenvolvimento - C#

Java e C#.NET - Um breve e introdutório estudo comparativo de suas sintaxes e convenções

O objetivo principal do artigo é demonstrar que os princípios de OO aplicados de forma brilhante pela linguagem Java, podem ser também aplicados em C#, no mesmo nível de qualidade, recebendo o mesmo resultado oferecido por Java.

por Everton Coimbra de Araújo



Apresentação

Foi com muita satisfação que respondi positivamente ao convite do Márcio Elias, para fazer parte da família de colaboradores do portal Linha de Código. Muito mais feliz ainda, em saber que o motivo do convite foi uma recomendação da Visual Books, editora pela qual já possuo cinco livros editados, e, é lógico, espero ter muito mais e, tenho um enorme carinho e respeito por toda a sua equipe.

Uma grande dúvida me cercou: “Qual área, assunto ou tema trabalhar neste primeiro artigo?”. Várias respostas vieram: Java, .NET, C#, Windows Forms, ASP.NET, JSF, Hibernate, OO, Delphi, UML ou outro tema afim. Mas, a decisão foi que, já que este é meu primeiro artigo no portal Linha de Código (e espero que possa escrever mais), porque não começar também do início? Mas começar bem do início talvez não fosse uma boa, mas nada impede que isso ocorra no futuro.

Bem, o início que eu escolhi foi um comparativo entre Java e C#, pois convivo com vários profissionais, acadêmicos e curiosos, que guardam para si certo preconceito em relação aos produtos Microsoft. Dizem que as ferramentas não são boas e que linguagem da Microsoft não é para profissional, pois foge de todos os princípios já estudados e fixados, principalmente os relacionados à Orientação a Objetos. Na realidade, acredito que este sentimento está relacionado à “evangelização” contra a Microsoft, devido ao movimento de software livre.

Bem, eu sou extremamente contra a qualquer posição bairrista, pois, enquanto desenvolvedores, precisamos estar atentos a vários fatores que nos levam a definir qual tecnologia, plataforma e ferramenta usaremos para um determinado projeto. Podemos ter uma situação em que a melhor solução seja Java e outra que seja .NET, ou ainda, quem sabe o bom e velho Delphi.

Analise também a situação: você é um excelente profissional em determinada tecnologia, mas foi convidado para participar de um projeto que utiliza outra. O que você fará? Negará o convite e dirá ao interessado que não conhece as ferramentas de desenvolvimento para esta tecnologia por que ela foge de seus princípios? Ou como um bom profissional e extremamente qualificado, aceitará o convite e o desafio? É claro que se agir como um bom profissional, certamente já terá estudado a tecnologia alvo.

Com o grande “bum” do software livre, muitas pessoas (não todas é claro) acabam confundindo as coisas e acabam pecando pelo bairrismo. Vejo em grande parte de palestras, eventos, trabalhos acadêmicos que apresentam os benefícios do software livre, o mesmo jargão que ouvi no início do software livre. Muitos “evangelizadores” se preocupam em apontar as falhas do produto proprietário, usando em todas as suas falas que o produto livre não tem “tela azul” e, acabam se esquecendo, na maioria das vezes, de ressaltar seus benefícios. Mas note que eu sou totalmente favorável à situação de que os Órgãos Públicos devam utilizar software livre, e investir, os recursos das licenças em educação. Mas sou completamente contrário “evangelizarmos” um único mundo.

Objetivos deste artigo

Bem, pelo caloroso texto da apresentação, pode-se pensar que o artigo tratará a briga entre o mundo proprietário (leia-se Microsoft) e o mundo livre, mas não gratuito, (leia-se Linux). Mas não é esta a idéia nem o objetivo do artigo. O objetivo principal é demonstrar que os princípios de OO aplicados de forma brilhante pela linguagem Java (da qual também sou adepto, defensor e incentivador de sua adoção), podem ser também aplicados em C#, no mesmo nível de qualidade, recebendo o mesmo resultado oferecido por Java, pois acredite, o C# é muito bom.

Não faz parte dos objetivos deste artigo apresentar qualquer ferramenta de desenvolvimento, quer seja em Java ou C#, mas saiba que existem ambientes gratuitos (e muito bons) para ambos os mundos. Também não faz parte dos objetivos deste artigo trabalhar ou apresentar conceitos e teorias sobre Orientação a Objetos.

Linguagens de Programação, bons profissionais e boas práticas

Bem, pontos de vista (ou opiniões) à parte, é extremamente importante, como um bom profissional, saber que, usando Delphi, Java ou C#, todos os princípios e boas práticas relacionadas à Orientação a Objetos e Padrões de Projetos podem ser aplicados, tudo depende do quão bom profissional é o desenvolvedor que utiliza tal ferramenta. O que não se pode aceitar, tampouco tolerar, é ouvirmos profissionais preferindo implementar um sistema que tenha uma interface visual “na unha”, por excesso de preciosismo, a utilizar um IDE que dê uma produtividade enorme, além de uma boa qualidade àquilo que seu cliente vê primeiro, que é a interface com o usuário, quer seja uma tela de uma aplicação desktop ou uma página em um browser. Quem pensa desta forma, é totalmente contrário a grande evolução que temos visto em relação às ferramentas de desenvolvimento e, quem é contrário a esta evolução, é contrário a informática. E acredite, isso ocorre muito e as pessoas nem se dão conta.

É preciso ressaltar que apesar do dito anteriormente, um sistema não é só uma boa interface com o usuário, toda a lógica do problema é trabalhada por trás da interface e a qualidade e corretude na resolução do problema, não depende apenas da linguagem, mas muito mais do desenvolvedor. Eu, por exemplo, já vi programas em Java escritos de forma estruturada. E aí? É a linguagem que é ruim?

Classes, atributos, tipos de dados, modificadores de escopo e acesso aos atributos

Usarei como exemplo para este artigo uma classe básica, Cliente, a qual será exibida em Java e em C#, e então comentários e comparações serão apresentados. Veja na Figura 1, a implementação em Java e na Figura 2, a implementação da mesma classe em C#.

Figura 1 - Implementação em Java

Figura 2 - Implementação em C#

Bem, tendo sido apresentadas as duas implementações, que possuem a mesma funcionalidade, mas por terem sido realizadas em linguagens diferentes, vamos na seqüência, tratar uma a uma.

Namespaces e Packages

Figura 3 - Estruturas para organizações das classes

Quando desenvolvemos uma aplicação, é interessante, para não dizer necessário, que as classes sejam distribuídas, ou organizadas, de forma que a estrutura organizacional passe, semanticamente uma regra, a qual esboce responsabilidades de cada conjunto de classes. Em Java, esta organização é realizada através de pacotes (packages) e, em C#, esta organização é conhecida por namespaces.

Conceitualmente não existem diferenças entre as duas linguagens, porém, sintaticamente existem diferenças, mas nada que não seja de fácil assimilação. Veja:

  • Em Java, um pacote representa fisicamente uma pasta (ou diretório para os puristas);
  • Em C# um namespace não está relacionado a uma pasta. É possível ter uma pasta com um nome e dentro desta pasta, classes que pertençam a um namespace com outro nome, ou ainda, em uma pasta é possível existirem classes com namespaces diferentes;

Prós e Contras

Para quem está iniciando em uma das linguagens, sem conhecer a outra, o aprendizado é fácil e natural, mas, para quem vem da linguagem Java para C#, confusões conceituais podem ocorrer, principalmente em relação ao fato de uma classe não necessariamente estar relacionada de forma direta a uma pasta, como ocorre em Java. Note que, caso você esteja fazendo uso de IDEs, a composição do nome de um namespace pode ser afetada caso a classe esteja sendo criada dentro de uma pasta, ou seja, o IDE pode compor o nome do namespace da classe a ser criada com o nome da pasta onde a criação esteja ocorrendo. Mas lembre-se que, ao contrário de Java, isso não é obrigatório em C#.

Assim como em Java que tem sua classe devidamente nomeada com o uso dos nomes dos pacotes a que ela pertence, uma classe em C# tem seu nome devidamente qualificado quando é referenciada com o caminho completo, que inclui o namespace da mesma. Em Java temos, por exemplo, javax.swing.JButton e em C# temos System.Windows.Forms.Button.

Particularmente acredito que o modelo do Java traga mais benefícios, onde existe uma regra sintática ligada diretamente à estrutura de pacotes. Deixar para o desenvolvedor a responsabilidade de atribuir os namespaces aos respectivos folders pode trazer prejuízos na produtividade e erros semânticos em toda a estrutura.

Importação de classes utilizadas na implementação

Figura 4 – Importação de classes utilizadas na implementação

Quando se implementa uma classe, seja qual for a responsabilidade dela, fatalmente ela incorrerá na situação de utilizar outras classes. Há uma grande possibilidade de que as classes que sejam utilizadas nesta implementação pertençam a um mesmo contexto, sendo, desta forma, visíveis. Porém, na maioria das vezes, se faz uso de classes que foram desenvolvidas por outros, ou, ainda, que façam parte da API (Application Program Interface) da linguagem eleita para implementar a solução.

Quando isso ocorre, é preciso que a classe em implementação tenha conhecimento da(s) classe(s) que utiliza, pois, para seu problema, não é preciso, por exemplo, saber como um JFrame é criado, gerenciado ou apresentado, é preciso saber apenas os serviços oferecidos por ele e não como eles são implementados (Encapsulamento). Mas, é preciso que a classe responsável por estes “detalhes” seja visível durante a compilação, pois, se na classe existir uma chamada a MessageBox, e não exista referência a este tipo, o compilador acusará problemas.

Esta situação é resolvida através de importações de “bibliotecas”. Qualquer linguagem oferece (precisa oferecer) este recurso. Em Java, as bibliotecas (classes) são importadas através da instrução import, que se situa abaixo da declaração do pacote ao qual a classe pertence. O C# também, obviamente, oferece este recurso, porém, de outra forma. As classes em C# são importadas através da instrução using e se encontram antes da declaração do namespace, pois em C#, a classe é delimitada pelo namespace a que pertence. Verifique nas Figuras 1 e 2 que os imports e usings estão localizados bem no início das classes.

Figura 5 – Processo de compilação e geração de bytecodes

A Figura 5, logo acima, exibe a situação onde a implementação da classe Janela.java faz uso das classes JFrame, JTextField, JButton e JLabel. No processo de compilação, que gerará o arquivo “executável”, apesar da classe implementada usar outras quatro, apenas um arquivo é gerado, no caso do Java e deste exemplo, o arquivo Janela.class. O que diferencia este processo no C#, é que ao invés de bytecodes, são gerados assemblies. Os assemblies gerados podem ser aplicações (exe) ou bibliotecas (dll).

Outro detalhe que diferencia esta funcionalidade entre as linguagens é que, em Java, é comum (mas não recomendado) ver situações como: import javax.swing.*;. Esta instrução importaria durante a compilação todas as classes utilizadas na classe em compilação que pertençam ao pacote javax.swing. Em C#, um namespace importado seria análogo ao exemplo citado de Java (import javax.swing.*;). Em Java, importa-se classes, como javax.swing.JFrame e em C# não se importa uma classe, e sim o namespace daquela classe.

Prós e Contras

Em meu ponto de vista, a situação oferecida pelo Java, de importar de forma explícita uma classe, e não seu pacote, apesar de isso ser possível, facilita em muito a identificação de a qual pacote uma classe pertence. Esta situação não ocorre em C#, mas a documentação oferecida (MSDN) é rica e auxilia em muito esta identificação, mas obviamente, na leitura de um código, na seção de importação não fica claro quais classes são utilizadas de cada namespace.

Outro detalhe que deve ser verificado, em C#, é que a instrução using não é exclusiva para a importação de bibliotecas (assemblies). Existe outro uso (muito bom) para ela, mas que está fora do escopo deste artigo. Já em Java, o import é exclusivo para a importação de classes.

Declaração das Classes

Figura 6 – Declaração de Classes

Uma classe, tanto em C# como em Java, representa um tipo de dado. Este tipo de dado é composto por atributos, que representam suas características, e métodos, que representam o comportamento da classe (ou serviços oferecidos por ela). E, como qualquer tipo de dado, presume-se que tipificará, neste caso, objetos a serem utilizados por outras classes.

Em Java, um arquivo pode ter várias classes, porém apenas uma delas pode ser pública, as demais terão seu acesso livre à todas as classes do mesmo pacote. Em C#, um arquivo pode ter várias classes também, porém, não existe a limitação de quantidade de classes públicas e as classes que não possuírem uma modificador de acesso, são por default internal.

Uma característica oferecida por C# e que não existe em Java é o conceito de partial class (classes parciais). Uma classe parcial pode ser visualizada como uma classe que possui sua implementação distribuída em mais de um arquivo. Essa característica pode ser facilmente visualizada em aplicações Windows Forms, criadas pelo Visual Studio, onde a interface (formulário) é alocada a um arquivo e o comportamento implementado para a mesma, em outro arquivo. O uso de classes parciais está fora do escopo deste artigo.

Em Java é possível alocar várias classes a um mesmo package, porém, como dito anteriormente, em arquivos separados se forem públicas. Em C#, uma classe pode ser declarada dentro de um namespace, em um único arquivo, Desta forma, dentro deste namespace, várias classes públicas também podem ser criadas.

Uma atenção especial deve ser dada à visibilidade das classes. Em C#, além dos já conhecidos modificadores de acesso (ou escopo) – public, private e protected – existem ainda os internal e protected internal. O internal permite acesso apenas por serviços implementados no mesmo projeto (assembly), já com o protected internal (assim como o private em Java) não tem uso permitido para a declaração de classes. O detalhamento sobre visibilidade e tempo de vida de objetos está fora do escopo deste artigo.

Uma classe, sem modificador de escopo em Java, tem como padrão o acesso por pacote, porém, em C# o padrão é o internal. O C#, assim como o Java, permite que classes sejam declaradas dentro de classes.

Prós e Contras

A possibilidade de criar várias classes públicas em um único arquivo pode parecer benéfica, porém, minha opinião é que este recurso pode complicar a vida de um desenvolvedor. Eu prefiro e recomendo que uma classe seja sempre declarada em um arquivo específico para ela.

Outra situação que deve ser vista e padronizada é de, em C#, o namespace a que uma classe pertence não estar ligado fisicamente com a pasta onde o mesmo é armazenado. Isso dá liberdade ao desenvolvedor, mas pode trazer problemas futuros se não existir uma boa disciplina para garantir esta organização.

É preciso definir um padrão para este ponto. Eu particularmente, em C#, adotei o padrão do Java. Uma classe por arquivo (porém faço uso de classes parciais em alguns casos) e mantenho cada classe em seu respectivo namespace.

Atributos e Propriedades

Figura 7 – Declaração de Atributos e Propriedades

É comum verificar iniciantes, sejam profissionais ou alunos, uma dificuldade conceitual em relação a atributos e propriedades. Este conceito errado vem dos princípios da Orientação a Objetos. Um atributo é uma característica de um determinado objeto, porém, não existe regra ou obrigatoriedade para que este atributo seja visível/acessível externamente. Para que um atributo tenha esta característica (ser visível a outros objetos/classes), é preciso transformá-lo em propriedade. Uma propriedade é uma característica de um objeto, a qual pode ser acessada externamente, normalmente por outra classe/objeto.

Em Java, um atributo é declarado propriedade quando o mesmo possui métodos acessores públicos definidos para ele, ou seja, os métodos get e set. Desta forma, um atributo de um objeto em Java só pode ser acessado através de chamadas a métodos, que retornem valores (get) e que recebem valores (set), atualizando o estado do objeto.

Em C# a transformação de um atributo para propriedade é diferente, segue o padrão Delphi, ou seja, os valores são obtidos e atribuídos através de um operador de igualdade (=). A Figura 7, acima, apresenta as declarações privadas para os atributos e publicas para as propriedades, semelhante ao Java. Porém, veja que uma propriedade em C#, possui (não obrigatoriamente) os métodos get e set, onde existe então a implementação para atribuição e retorno do valor do atributo.

Figura 8 – Utilizando os acessores

Prós e Contras

A convenção trabalhada em Java cumpre de maneira explícita o uso de mensagens (métodos), quer seja para um serviço específico de uma classe, quer seja para atribuição simples de um atributo. C# aplica o mesmo conceito, porém fazendo uso explícito de propriedades, o que é mais intuitivo. Atribuição e obtenção de valores precisa ser uma operação simples. É mais natural. Métodos (mensagens) são (e devem ser) utilizados para resolverem problemas específicos, o velho conceito do Dividir para Conquistar. A regra para consistência do atributo continua existindo em C#, da mesma forma que em Java, basta para isso, colocar esta regra no método get e set da propriedade.

Construtores

Figura 9 – Declaração de Construtores

Como pode ser verificado pelo apresentado na Figura 9, não existem diferenças na implementação de construtores. C# traz também o já famoso e útil this, que apenas para relembrar, é uma referência ao objeto atual da classe onde o mesmo é utilizado, quer seja para atributos, métodos ou até mesmo referenciando o uso em sobrecargas de construtores.

Conclusões

Tanto a plataforma Java e suas linguagens, como a plataforma .NET e suas linguagens, são ferramentas extremamente poderosas e ambas devem ser de conhecimento de um desenvolvedor que tenha a preocupação em estar em sintonia com o mercado.

Praticamente todos os recursos de desenvolvimento necessários para aplicações, quer sejam aplicações desktop, web, corporativas e para dispositivos móveis, estão disponíveis em qualquer uma das plataformas. Desta forma, cabe ao desenvolvedor avaliar seu cliente, projeto, custos, recursos, prazos e equipe, dentre outras variáveis, para saber qual é a melhor opção.

Opiniões bairristas devem ser desconsideradas por um bom profissional. Procure não apontar problemas de uma ou outra plataforma, mas sim, os benefícios que sua escolha trarão ao mais interessado no projeto: seu cliente.

Como pôde ser visto neste artigo, o início de aprendizado é simples, quer seja para um iniciante ou para quem utiliza uma das plataformas e quer (nem que seja de curioso) usar a outra.

Recomendações

É interessante, para aqueles que, depois da leitura deste artigo, notaram a semelhança entre as linguagens e que para nós desenvolvedores que vivemos de nosso serviço, atendendo demandas cada vez mais exigentes no prazo, qualidade e segurança, a barreira existente entre uma ou outra linguagem, está principalmente na “evangelização”. Cada tecnologia, através da concorrência, deve algo a outra, e quem ganha? Nós. Procure estar atento em ambas, se especialize em uma, mas não ignore a outra.

É óbvio que o apresentado neste artigo não chega nem a ser a “ponta do iceberg”, mas cabe a você agora investigar, estudar, praticar, testar e aplicar estas poderosíssimas linguagens, para tirar suas próprias conclusões.

Uma recomendação para continuidade no estudo que fica, é descobrir como estas linguagens implementam a orientação a objetos, como elas permitem o acesso a dados, como elas subsidiam aplicações desktop, web, para dispositivos móveis e AJAX dentre muitas outras tendências do mercado.

Como sempre digo a meus alunos, conte comigo e procurarei sempre atender da melhor maneira possível. A resposta pode não ser imediata, mas ela ocorrerá.

Agradecimentos Especiais

Meu interesse pela plataforma .NET surgiu como um desafio. Estava cercado de pessoas que pensavam (ou ainda pensam) que só Java interessa e o resto não vale nem esforço. Consegui demonstrar para várias destas pessoas, que o mundo pode existir com as duas tecnologias e que, inclusive, elas podem conviver juntas, uma auxiliando a outra. Entre estas tantas pessoas, uma em especial merece e sempre merecerá meu apoio e minha gratidão, pois aceitou o desafio, de braços abertos, de desbravar o .NET.

A Renata Cristina Furlan, foi minha aluna até o final deste ano de 2007, na UTFPR, campus Medianeira, no curso de Análise e Desenvolvimento de Sistemas e, nunca é demais dizer que é uma das melhores, não só em minha disciplina, mas certamente em todo o curso. Entre vários alunos puristas em Java, ela não teve receio em estudar esta plataforma e estamos criando em conjunto um framework para desenvolvimento de aplicações Windows Forms, o que certamente renderá vários frutos.

A Renata, como em várias atividades minhas, aceitou ser minha parceira neste primeiro artigo no portal Linha de Código. Validou, criticou, comentou, sugeriu e realizou todos os testes. Ela também, certamente, está disponível a auxiliar quem precise de ajuda, pois é de uma didática fantástica, podendo ser encontrada pelo e-mail renata_furlan@yahoo.com.br.

Everton Coimbra de Araújo

Everton Coimbra de Araújo - Desde 1987 atua na área de treinamento e desenvolvimento. Como Mestre em Ciência da Computação, é professor da UNIVERSIDADE TECNOLÓGICA FEDERAL DO PARANÁ, Campus Medianeira, onde leciona disciplinas relacionadas ao desenvolvimento de aplicações web, com Java e .NET.

É autor dos livros Desenvolvimento para WEB com Java, Orientação a Objetos com Java - Simples, Fácil e Eficiente, Algoritmo - Fundamento e Prática em sua terceira edição e dos livros Delphi - Implementação e Técnicas para Ambientes Virtuais e C++ Builder - Implementação e Técnicas para Ambientes Virtuais. Todos pela VisualBooks. Pode ser contactado através do e-mail everton@utfpr.edu.br ou evertoncoimbra@gmail.com.