Orientação à Objetos em Javascript – Criação de Classe e Languages Patterns

E aí galera, como passaram o natal !?!?!

Espero que muito bem =)

Caros, eu gostaria de mostrar muitas coisas legais que podem ser feitas em js e algumas que inclusive já fiz. Porém é muito complicado mostrar sem que todos tenham em mente como funciona a programação orientada à objetos na linguagem Javascript.

Meu intuito nesse post é mostrar como eu ( Eduardo Ottaviani ) faço minhas classes pois uso uma forma diferente de criação de classes das formas convencionais.

O Javascript é uma linguagem muito peculiar, ela implementa tudo mas de formas diferentes e é uma linguagem muito dinâmica, muito flexível. Então você pode implementar as coisas de muitas formas diferentes. O Javascript inclusive nos incentiva a procurar soluções em outras linguagens. jQuery é uma implementação em OOP e usa conceitos de outras linguagens como perl e lisp.

Para quem deseja ser um excelente programador em Js eu recomendo fortemente que desenvolva alguma coisa em outras linguagens, porque têm suas peculiaridades e muitas implementações padrão das linguagens pode ser reproduzida no Js afim de se resolver um problema lógico ou apenas dar uma idéia de como montar um código que te pareça mais amigável sintáticamente.

Bom, além de js eu me aventurei um pouco em outras linguagens, como python, php, ruby e smalltalk. Algumas peculiariadades delas eu acabei incorporando no js.

Por exemplo, vocês já devem ter reparado que não uso ponto-e-vírgulas no meu código e uso o menos possível chaves para if´s que tenham apenas uma instrução e quando tem uma instrução do tipo função ou um operador. Essa sintaxe para mim é muito mais enxuta muito mais limpa e peguei de python.

“Mas CARAY o que isso tem haver com OOP!?!?!?!”

Calma fi..ochhh… to passando a vaselina pra ir com carinho.

Existem várias implementações de Classes em Js, e há muitas na internet, vou deixar no final do post alguns artigos sobre OOP que pesquisei durante meu percurso pela estrada nerd.

Mas o que eu não gosto delas é que usam um design que não me agrada, lembrando o design de objetos nativo da linguagem como o Date().

Esse design:

function Pessoa(nome, idade){
 this.nome = nome
 this.idade = idade
}

Eu particularmente acho horrível esse pattern. Não gosto mesmo. Parece que pessoa é uma função… não curto.

É aí que as linguagens Ruby e Smalltalk entram, elas  me deram uma idéia para criar um design diferente.

No Smalltalk explicando bem por cima, bem grosseiramente, tudo é objeto e para criar uma classe você também usa um objeto. Portanto esse objeto cria uma Classe. Passando para o Js essa idéia, a classe Pessoa acima ficaria:

var Pessoa = {

 Class : function(nome, idade){

 this.nome = nome
 this.idade = idade

 }

}

Pronto! Olha lá, é um objeto que cria uma classe. Portanto Pessoa é um objeto onde tem um construtor para a classe do tipo Pessoa. Eu acho muito mais fácil para organizar o código e fica muito claro que aquilo não é uma função e sim uma classe, além de facilitar na hora de criar variáveis e métodos estáticos. Outra vantagem veremos mais pra frente num post futuro, quando precisamos usar composição ou agregação.

Beleza, mas uma coisa ainda não me agrada nessa classe, os atributos… Algumas raras vezes precisamos iterar pelos atributos de um objeto, mas essa tarefa se torna muito verbosa porque precisamos verificar se o atributo do objeto é uma variável ou um método, isso é meio chato além de prejudicar o processamento.

Então usamos um conceito de outra linguagem, Ruby. Não existem atributos na nossa classe, apenas métodos. Assim sabemos que seja lá o que for iterarmos não precisa haver verificação, tudo é método. Métodos podem fazer tudo o que atributos fazem, mas não o contrário, então podemos sempre implementar em forma de métodos.

var Pessoa = {

 Class : function( nome, idade ){

 this.nome = function(n){
 return n ? nome = n : nome
 }

 this.idade = function(i){
 return i ? idade = i : idade
 }

 }

}

Olha que belezinha… muito mais bonita a cara dessa classe, fala aí. Os métodos são setters e getters ao mesmo tempo, se passar um valor a função seta as variaveis privadas (nome, idade) que são criadas no momento da instância do objeto. Se não passar nenhum valor, ela retorna o valor das variáveis. Pra que ficar criando setNome, setIdade, getNome, getIdade ??? Não precisa disso…

Bom, pode ser que você não goste muito da sintaxe na hora de criar um objeto:

var Edu = new Pessoa.Class("Eduardo Ottaviani", 25)

Eu não tenho problema nenhum com a palavrinha “Class” ali. Mas pode ser que alguém sinta uma coceira por causa disso, principalmente se o nome da classe for muito maior que Pessoa.

Bom, utilizo nesse caso um método existente nas Classes em Ruby. O famoso “new”. No js a palavra new é reservada, mas podemos usá-la como usamos a palavra Class, com letra maiúscula. É só criar esse método estático na nossa Classe:

var Pessoa = {

 New : function(nome, idade){ return new this.Class(nome, idade) },

 Class : function( nome, idade ){

 this.nome = function(n){
 return n ? nome = n : nome
 }

 this.idade = function(i){
 return i ? idade = i : idade
 }

 }

}

Olha o New ali, na primeira linha da nossa classe. O New é um método estático da Classe e retorna uma nova instância passando os parâmetros para o construtor real da classe.

Agora para os que não gostam de instanciar o objeto da forma Nome.Class :

var Edu = Pessoa.New("Eduardo Ottaviani", 25)

Que classe bonita fala sério…

Viram, com conceitos de outras linguagens mudamos a cara da nossa classe. Eu costumo chamar as características das linguagens de Languages Patterns. Por isso do título do post. Então, usamos alguns poucos Languagens Patterns  para criar nosso próprio pattern de criação de Classes. Não só para o código ficar mais bonito e vistoso, mas para ficar mais intuitivo, mais na cara, mais semântico.

Mais pra frente falarei sobre composição, agregação, herança, polimorfismo e outras peculiaridades desse paradigma orientado a objetos.

É isso galera, desejo para vocês um ótimo ano novo, que o ano que vem seja de muita paz e alegria, sucesso e dinheiro para todos nós.

Vocês viram que meu blog tá nevando ? \o/  Achei mó legal isso … pena que só vai até dia 4. =/

Como o prometido, os links para estudos em JOOP:

Julio Greff  – Javascript orientado á objetos parte 1

Prosa digital – UML e javascript – Capítulo 1

GOOGLE :  Pra quem não conhece essa ferramenta

Anúncios

10 comentários sobre “Orientação à Objetos em Javascript – Criação de Classe e Languages Patterns

  1. Ótimo post, esse assunto me interessa bastante. Estou lendo o livro http://jsdesignpatterns.com/ onde são mostradas varias implementações de oop em javascript, emulando a maneira como linguagens totalmente orientada a objeto fazem; recomendo a leitura a todos os seus leitores.

    Sinceramente a maneira tradicional de declarar classes no js era meio desconfortável pra mim (mesmo não programando em outra linguagem) então sempre declaro a função dentro de uma váriavel:

    var Classe = function(){
    this.propriedade
    this.metodo = function(){}
    }

    esse padrão funciona legal pra mim pq posso até passar a classe toda como argumento uma função e todas as vantagens de variáveis.
    Achei curiosa sua maneira de implementar pq até agora só uso objetos pra declarar classes que não precisam ser instaciadas (singleton pattern).

    Abraços parabéns pelo blog tem me ajudado muito, continue postando.

  2. @manobi

    Muito obrigado cara.
    Que bom que se interessa também pelos design patterns em js. Inclusive estive lendo esses dias sobre MVC em js, http://www.alistapart.com/articles/javascript-mvc/, e estou implementando isso em um projeto específico na agência.

    Eu planejo mostrar mais pra frente, outras implementações com esse design que uso para criar classes. Eu acho muito melhor que a maneira tradicional.

    Mas a sua forma e a tradicional são iguais. Da sua forma e da tradicional, existirá uma variável global chamada Classe, que você pode passar como parâmetro.

    Muito obrigado pela contribuição! Espero que apareçam mais desenvolvedores para discutir. Acho muito enriquecedor isso. Pretendo mostrar também algo sobre singleton, agora que mencionou.

    Abraços!

    • É verdade. Acho que não pensei pra falar, mas pra mim dessa forma, pelo menos fica mais fácil de diferenciar das funções normais. Do seu jeito fica muito mais complicado ainda não tô nesse nível.

      Vou ficar no aguardo do seu exemplo de singleton, por acaso é parecido com esse: http://pt.wikipedia.org/wiki/Singleton (rolar até a parte do javascript). Se for me diga porquê fazer desse jeito ao invés de usar um objeto, já que só precisa de uma instância. achei que o cara escreveu muito código sem necessidade.

      Assunto é muito bom. Parabéns mais uma vez pelo blog.

      Abraços

      • Não é não manobi.

        Eu pesquisei muitos casos de singleton em javascript, e todos seguem essa forma como está no wikipédia.

        O grande problema desse método é que vc sempre pode instanciar um objeto. No caso do wikipédia, é só você chamar new Page() duas vezes, e voi lá, tem duas instâncias da classe.

        Todas tendem a criar uma propriedade instance pública para saber se já foi instanciado. Mas tem um problema, as propriedades públicas sempre podem ser reescritas, então você sempre pode fazer minhaclass.instance = true.

        O singleton será o meu primeiro post sobre design patterns em js e vou conseguir mostrar o porque que essa forma de criar classe que eu uso considero melhor.

        Abraços man! Obrigado mais uma vez.

  3. Fala brow!

    Desde que comecei a estudar JS e pelas empresas que passei, sempre tive o costume de fazer dessa maneira function Pessoa()…blabbla.bla, rsrsr…Realmente eh bem tosco, comparada a sua implementacao, vou dar uma estudada e ficar atendo as suas dicas! Como vc implementaria a classe abaixo? Abraaaaaass, Huggler.

    function Pessoa(){
    this.pessoas = [];
    };
    Pessoa.prototype.getNome = function(){
    return this.nome;
    };
    Pessoa.prototype.setNome = function(nome){
    this.nome = nome;
    };
    Pessoa.prototype.addPessoa = function(nome, idade, cod){
    var obj = {};
    obj.idade = idade;
    obj.nome = nome;
    obj.codEmpresa = cod;
    this.pessoas.push(obj);
    };

    function Empresa(){
    this.empresas = [];
    };
    Empresa.prototype = new Pessoa();
    Empresa.prototype.addEmpresa = function(nome, cod){
    var obj = {};
    obj.nome = nome;
    obj.cod = cod;
    this.empresas.push(obj);
    };
    Empresa.prototype.funcionarios = function(cod){
    var func = [];
    for(var x = 0; x<this.pessoas.length; x++){
    if(this.pessoas[x].codEmpresa == cod){
    func.push(this.pessoas[x]);
    }
    }
    return func;
    };

    var e = new Empresa();
    e.addEmpresa('Google Inc', 10);
    e.addPessoa('Felipe Huggler', 20, 10);
    e.addPessoa('Hugo Tostes', 90, 10);
    e.addPessoa('Luis Claudinho', 28, 10);

    e.addEmpresa('Microsoft', 12);
    e.addPessoa('Jack Bower', 20, 12);
    e.addPessoa('Sandra Bullock', 90, 12);
    e.addPessoa('Tais Araujo', 28, 12);

    alert(e.funcionarios(10));

    • E aí Huggler, tudo bom!?? Então, eu implementaria de forma diferente, há repetição de código aí nessa implementação, e também existem getters que retornam conteúdo de variáveis públicas!!! A idéia é reuso do código e encapsular da melhor forma possível, escondendo suas variáveis de manipulação.

      Eu faria uma classe Organização abstrata, ou seja, não pode ser instanciável, e crio uma classe Empresa que herda dessa classe organização e herdo os métodos. Também uso sobrecarga por número de parâmetros, para reutilizar o método de adicionar, tanto funcionários como empresas.

      var Interface = {
      abstract :function(constructor){
      if( this.constructor == constructor )
      throw new Error(‘Classe abstrata não pode ser instanciada’)
      }
      }

      var Organizacao = {

      Class :function(){

      Interface.abstract.apply( this, [Organizacao.Class] )

      var data = { empresas :[], funcionarios :[] }

      this.add = function(){
      return this.add[ arguments.length ].apply( this, arguments )
      }

      this.add[2] = function(nome, codigo){
      data.empresas.push({ nome :nome, codigo :codigo })
      }

      this.add[3] = function(nome, idade, codigo){
      data.funcionarios.push({ nome :nome, idade :idade, codigo :codigo })
      }

      function get(type, codigo){
      var ret = []
      var search_for = data[ type ]
      for(var i = 0; i < search_for.length; i++)
      if( search_for[i].codigo == codigo)
      ret.push(search_for[i])
      return ret
      }

      this.get_funcionario = function(id){
      return get('funcionarios', id)
      }

      this.get_empresa = function(id){
      return get('empresas', id)
      }

      }

      }

      var Empresa = {
      Class :function(){
      Organizacao.Class.apply( this )

      // Outros métodos
      }
      }

      var e = new Empresa.Class

      e.add('Google Inc', 10)
      e.add('Felipe Huggler', 20, 10)
      e.add('Hugo Tostes', 90, 10)
      e.add('Luis Claudinho', 28, 10)
      e.add('Microsoft', 12)
      e.add('Jack Bower', 20, 12)
      e.add('Sandra Bullock', 90, 12)
      e.add('Tais Araujo', 28, 12);

      console.log(e.get_funcionario(10));
      console.log(e.get_empresa(10));

  4. Shoooow de bola Man!!! Tenho algumas duvidas brooow!

    1) Qual foi o motivo da criacao da abstract? Ela esta sendo utilizada em qual momento?

    2) A this.add ficou foooooda cara, ideia mto maneira…this.add[ arguments.lenght ].apply( this, arguments )…significa…que na funcao add[ n ], sera aplicada ela this.add, mais os parametros recebidos por ela?

    Abraaaass!

    • É apenas uma forma de abstrair o problema. Eu quis fazer uma classe abstrata que servisse de uma generalização para futuramente utilizar em classes onde fosse uma especialização de Organização.

      É apenas uma forma de pensar mais genéricamente, nesse caso não é preciso, mas eu sempre penso desta forma.

      No this.add eu usei uma forma de polimorfismo, que é a sobrecarga ou overload pela quantidade de parâmetros.

      Eu poderia explicar mais detalhadamente, mas não seria necessário, eu postei aqui ó:
      Overload em Javascript

  5. Show de bola…
    Esse seu artigo só vem a confirmar o conceito de aprender pelo menos uma linguagem de programação por ano, como fala no livro O Programador Pragmático.
    Muito bom mesmo, aprendi muito.

  6. Olá Eduardo!
    Primeiramente meus parabéns por este blog e a forma como você trabalha com javascript.
    E sou um programador que migrou do ambiente desktop para o web e por esse motivo sempre achei que está linguagem era meio que desvalorizada , tendo em vista que ela é a principal quando se fala em front-end um fato que se agrava mais ainda quando se fala em aplicações complexas que rodam na web. Minha primeira aplicação foi a migração de um sistema desktop para web e olha penei para aprender e manter as características que eu tinha no ambiente desktop.
    Hoje a cada dia eu procuro cada vez me especializar tanto no front-end com também no back-end pois por necessidade eu acabo trabalhado com os dois e graças ao seu blog eu pude reaver antigas ideias que deixei de lado por não ter recursos que as tornassem atrativas por serem dispendiosas demais.
    Um fato que achei legal são as explicações conceituais que a partir delas nos podemos usar a criatividade e elaborar novas soluções. Eu até brinquei com amigo meu que se brincar é capaz de alguém criar uma linguagem nova kkk! Bom eu já me estendi demais em meu comentário! O blog está show é o meu novo livro de cabeceira! Site , pagina kkkk!

Deixe um comentário

Preencha os seus dados abaixo ou clique em um ícone para log in:

Logotipo do WordPress.com

Você está comentando utilizando sua conta WordPress.com. Sair / Alterar )

Imagem do Twitter

Você está comentando utilizando sua conta Twitter. Sair / Alterar )

Foto do Facebook

Você está comentando utilizando sua conta Facebook. Sair / Alterar )

Foto do Google+

Você está comentando utilizando sua conta Google+. Sair / Alterar )

Conectando a %s