Archive for the 'oop' Category


Proxy Pattern: Exemplo e Aplicação 2

Desde meu último post acabei não cumprindo com o que esperava. Como já devo ter mencionado, estou cursando Engenharia da Computação Cooperativo, onde o curso intercala módulo acadêmico e estágio, permitindo tempo integral (desde que não tenha DPs para pagar). Comento sobre isso em outro post, vamos voltar ao assunto.

Depois de realizar meu primeiro laboratório de engenharia de software, não adotar um framework na minha camada de persistência tornou muito trabalhoso sua modelagem e manutenção. Cada operação exigia escrita em código ou stored procedure o que tornava “uma tarefa simples” em trabalhosa, não que demorasse muito, mas depois de muitas linhas de coisas para coisas tão banais o processo ficava um tanto… chato.

Desde então, tenho como objetivo aprender um framework para essa finalidade. Claro, não podia ficar de lado o Hibernate, mas no momento estou curtindo C# e no caso temos o NHibernate. Conversei com um colega do trabalho e ele aparentemente não gostou muito do NHibernate. Não entrei muito em detalhes do por que ele era ruim, mas a comparação era bem direta se comparado com o Hibernate do Java. Portanto, ele costuma usar o ActiveRecord que usa como base o NHibernate.

Mas nas últimas semanas saiu o NHibernate 2.0, apesar de a página não estar atualizada. E concerteza deve ter melhorado em muitos aspectos. Por isso escolhi o NHibernate como estudo. Pretendo falar mais sobre ele em outro post (quando der).

Resumo

O uso do (N)Hibernate é bem direto, use POJO (plain old java object) ou POCO (plain old c# object), onde os objetos contém basicamente get/set. Talvez minha definição esteja um tanto incompleta, então me corrijam se falei absurdos.

No Java todos os métodos por default podem ser overrided, bastando reescrevê-lo em sua classe estendida. Já no C# a coisa fica mais explicita. Por default nenhum método/property pode ser overrided, para tal é necessário acrescentar a keyword “virtual”, e quando realizamos um override a keyword “override”, já veremos um código.

O que quero dizer com isso? Bem, como no Java isso já é default para todos os objetos então só é necessário definir os getters e setters da classe, já para o NHibernate todos os properties devem vir com a keyword virtual, caso contrário a coisa não funciona.

Então me perguntei: por que tenho que colocar todas as properties como ‘virtual’?

Bom, inicialmente achei que o NHibernate deveria simplesmente instanciar um objeto da entidade mapeada e então preencher todos os properties um a um. Mas o (N)Hibernate existe uma funcionalidade chamada de Lazy Load.

O que é Lazy Load?

Serei bem breve, digamos que você tenha um objeto e este possui uma referência para um outro objeto, seria um desperdício recurarmos o estado do objeto referenciado se nem usassémos ele. O que o lazy load faz é carregar este objeto (realizar a query no banco de dados) realmente quando precisamos. Mas como diabos isso ocorre?

A resposta é usando Proxy Pattern.

O que ele faz é atuar como um proxy entre a chamada de um property/método. Uau, entendi nada, o que é proxy?

Eu sempre me perguntava isso. Um proxy é digamos um “passo” intermediário de um fluxo. O exemplo mais comum é em redes de computadores. Digamos que sua máquina acesse a internet diretamente, ou seja, o seu computador e a “nuvem”. Se quisessemos realizar um filtro no neste tráfego, poderíamos utilizar um serviço de proxy que atua entre a nuvem e seu computador, de modo que todas as requisições passem sempre pelo proxy, tratando os dados trafegados e aplicando filtros adequadamente.

Como implementamos um proxy pattern? Veja um exemplo bem simples abaixo:

   1: public class MyClass
   2: {
   3:     public virtual string Message { get; set; }
   4:  
   5:     public virtual void DoSomething()
   6:     {
   7:         Console.WriteLine("Doing something really important.");
   8:     }
   9: }
  10:  
  11: public class MyClassProxed : MyClass
  12: {
  13:     public override string Message
  14:     {
  15:         get
  16:         {
  17:             Console.WriteLine("Proxying on reading...");
  18:             return base.Message;
  19:         }
  20:         set
  21:         {
  22:             Console.WriteLine("Proxying on saving...");
  23:             base.Message = value;
  24:         }
  25:     }
  26:  
  27:     public override void DoSomething()
  28:     {
  29:         Console.WriteLine("Proxying DoSomething() before");
  30:         base.DoSomething();
  31:         Console.WriteLine("Proxying DoSomething() after");
  32:     }
  33: }

O que basicamente fazemos é extender a classe MyClass criando uma MyClassProxed dando override nos métodos e properties. Para testarmos, seria muito simples:

   1: MyClass myClass = new MyClass() {Message = "Hello World!"};
   2:  
   3: Console.WriteLine("Normal behavior");
   4: Console.WriteLine("MyClass.Message = {0}", myClass.Message);
   5: Console.Write("MyClass.DoSomething()");
   6: myClass.DoSomething();
   7:  
   8: Console.WriteLine();
   9:  
  10: Console.WriteLine("Normal behavior plus proxying");
  11: myClass = new MyClassProxed() {Message = "HelloWorld!"};
  12: Console.WriteLine("MyClass.Message = {0}", myClass.Message);
  13: Console.Write("MyClass.DoSomething()");
  14: myClass.DoSomething();

Como a classe MyClassProxed extende a class MyClass basicamente a interface não muda, logo do nosso ponto de vista qual implementação usamos não importa, seja MyClass ou MyClassProxed, para nós o que importa é a interface da property Message e o método DoSomething(). O resultado esperado é algo como:

proxy

Conclusão

Utilizando este pattern é possível realizar o lazy load de forma transparente para o desenvolvedor.

Esse pattern é bem conhecido e pode ser encontrado no livro Design Patterns, Elements of Reusable Object-Oriented Software do GoF (Gang Of Four), que por sinal é uma leitura básica para qualquer desenvolver.

Infelizmente, o conteúdo do livro não é de fácil digestão quando sua experiência como desenvolvedor é pequena, muitos patterns não fazem sentido pois você não consegue comporrender os problemas de implementação que existem.

Espero poder dar continuidade neste tipo de post, até uma próxima vez.

Pilares do Paradigma Orientado a Objetos (Parte 1) 0

O paradigma orientado a objetos é algo que não há como evitar caso deseje ser um desenvolvedor. Toda aplicação exige uma organização e metodologia para desenvolvimento, não basta abrir o editor de texto e digitar.

Alguns princípios da orientação a objetos estão listadas abaixo:

Encapsulamento (encapsulation)

Toda aplicação é composta de pequenos elementos que unidos concluem o produto final. É comum a ocorrência de métodos (“funções”) que dependem de outros para concluir sua operação. Um método que delega um objeto a fazer uma determinada parte de sua operação não precisa saber como ele faz, para ele é suficiente saber que dada uma entrada ele manipula ela e retorna o que deseja. Essa metodologia de tratamento da entrada não transparente é o que se chama de encapsulamento.

Esse encapsulamento pode ocorrer de duas formas: por delegação ou métodos privados.

  • delegação é quando usamos um objeto instânciado de outra classe que contém métodos que auxiliam a função de um método;
  • métodos privados são métodos internos da classe, ou seja, não são vistos externamente, servem apenas para concluir pequenas operações.

Na orientação a objetos é comum subdividir tarefas criando pequenos blocos com uma única finalidade e não classes lotadas de linhas de códigos.

Em resumo, todo método de uma classe é encapsulada, apresentando ao exterior apenas as suas operações (nomes dos métodos), para o usuário não importa como ela faz.

Especialização (specialization)

A especialização esta relacionada a herança. Em geral, muitas coisas compartilham propriedades bases. Uma moto, carro e bicicleta são meios de transporte. Embora cada um possua suas particularidades que os diferenciam. Poderiamos partir de uma base admitindo que todos sejam veiculos, e poderíamos especificar/especializar essa classe consideram veiculos motorizados ou não. Tudo dependeria da forma que tratamos nosso projeto. Poderíamos subdividir em classes de objetos de 2 rodas ou 4 rodas.

Uma caracteristica importante é que uma classe pode apenas especializar uma outra classe, ou seja, deve-se projetar bem.

Quando desejamos caracterizar mais uma classe podemos implementar uma interface. Em geral, uma interface representa um tipo de dado. Uma propriedade que se mantem a todos que a implementarem, não importando como cada um faz.

Keywords for properties and methods on C# 1

Em linguagens orientadas a objeto temos meios de definir o acesso e uso dos elementos. Segue uma lista de algumas dessas palavras e sua funcionalidade.

  • public: declara que uma propriedade/método possa ser acessado externamente, ou seja, é visível fora do objeto.
  • private: oposto do public, toda propriedade/método só pode ser acessada internamente da classe.
  • protected: semelhante ao private, ou seja, não é visível fora do objeto, mas é compartilhado entre seus derivados transmida hierarquicamente.
  • static: um método/propriedade estática são elementos da classe em si, ou seja, não independem de sua implementação, são compartilhadas por todas e não podem ser alteradas. Em geral são constantes ou métodos que não dependem de parâmetros da classe.

Algumas outras keywords frequentemente usadas:

  • virtual: um método virtual é um método que pode ser sobreposto (override); ou seja, um método non-override não poderá ser sobreposto. Uma forma de lidar com isso seria usar a keyword new method, escondendo o método base na derivada. Por default, no Java todos os métodos são virtuais e, portanto, podem ser sobrepostos. Obs: não aplicável a métodos abstratos e estáticos.
  • override: declara que um método esta sobrepondo um método base – aspecto do polimorfismo – “one interface, multiple methods” (uma interface, múltiplos métodos).
  • abstract: declara uma classe semi-implementada, ou seja, possui método que não puderam ser implementadas genericamente, e portanto, devem ser implementadas por seus derivados.
  • interface: define uma assinatura para um tipo de dado (data type). É uma forma de dizer que todo tipo que implementa uma dada interface terá certos elementos, sempre! É muito semelhante a abstract, a diferença é que num algumas implementações já estão feitas. Outro detalhe relevante é que na herança uma classe pode apenas derivar de uma única classe base mas pode implementar quantas interfaces desejar. Todos os métodos de uma interface são públicos, um tanto óbvio.
  • sealed: impede que uma classe seja herdada. Semelhante ao final no Java.