Posso começar com um estudo de caso simples: dada uma String retornar o número de palavras.
É assim mesmo, simples assim, inclusive muito fácil de implementar em qualquer linguagem, mas a questão não é essa, como desenvolvedor eu quero usar orientação a objetos no projeto.
Vamos a uma implementação tosca em Java:
String frase = "Uma frase de exemplo"; System.out.println(frase.trim().split("\\s+").length);Deu. Mostra 4. Entretanto eu quero reutilizar esta funcionalidade então em componentizo, bem, mas como?
Posso usar outro estudo de caso para dramatizar mais a história: verificar se uma String está em branco, ou seja, semelhante ao vazio só que ignorando espaços.
A implementação é medíocre:
String texto = " "; if (texto.trim().length() == 0) { System.out.println("vazio"); }Não obstante, como no primeiro caso, eu quero componentizar.
No Java, é clássico fazer uma classe utilitária, algo como TipoUtils, neste caso, StringUtils:
public class StringUtils { public static int words(String str) { return str.trim().split("\\s+").length; } public static boolean isBlank(String str) { return str.trim().length() == 0; } }E uso assim:
String texto = " "; if (StringUtils.isBlank(texto)) { System.out.println("vazio"); }Ainda posso usar um recurso introduzido no Java 5, o import estático.
import static meu.framework.utils.StringUtils.*; // algumas linhas abaixo String texto = " "; if (isBlank(texto)) { System.out.println("vazio"); }Qual o problema com esta implementação? É que ela soa totalmente procedural em contraste ao modelo OO escolhido, em outras palavras eu queria fazer isso:
String texto = " "; // quero o próprio objeto me diga se está em branco if (texto.isBlank()) { System.out.println("vazio"); } else { // quero que o próprio objeto me diga quantas palavras tem System.out.println("Existem " + texto.words() + " palavra(s)"); }Em Java, impossível. No Java a classe String é final, ou seja, não pode ser estendida.
Para constar, uma extensão da API base do Java já existe e é distribuída pelo projeto commons do Apache e uma classe StringUtils já existe para estender as funcionalidades relacionadas a Strings e é muito bem escrita.
Mas isso não me deixa contente por que outras linguagens lidam muito melhor com esta situação, dando melhor suporte para estender a API base.
Vamos ao mesmo exemplo usando C#. No C# é possível, de certo modo, estender qualquer classe, mesmo as finais (sealed em C#), usando somente a API pública da classe, que já é suficiente para realizar muitas proezas:
public static class StringUtils { public static int Words(this string str) { return Regex.Split(str.Trim(), "\\s+").Length; } public static bool IsBlank(this string str) { return str.Trim().Length == 0; } }Implementações de classes estáticas no C# permitem estender a funcionalidade qualquer classe. Na verdade é um açúcar sintático no qual ele passa o conteúdo da variável para o método estático, ainda sendo procedural, mas de melhor leitura e mais elegante que em Java. Eu posso chamá-lo assim:
string texto = " "; if (texto.IsBlank()) { Console.WriteLine("vazio"); } else { Console.WriteLine("Existem " + texto.Words() + " palavra(s)"); }Bem mais OO não acha? Pode ficar ainda melhor em Ruby, onde as classes são abertas. Em outras palavras, é possível estender a funcionalidade até mesmo das classes básicas como String e FixNum (inteiros). Claro que esta liberdade deve ser usada com parcimônia, é bem mais fácil fazer caca, mas com responsabilidade dá para fazer isso:
class String def words self.split.length end def blank? self.strip.length == 0 end endEntão eu posso usar estes métodos assim:
texto = "uma frase" print texto.words print "vazio" if texto.blank?Sinceramente, sinto falta dessa flexibilidade em Java.
Acho exagerado a recomendação do Pragmatic Programmers de que todo programador deveria aprender uma linguagem por ano, por outro lado entendo o motivo que é propiciar novas visões, pontos de vista, ser mais crítico ao seu código, saber que há alternativas para fazer, melhor ou pior, aquilo que tu já faz todo o dia.