No post sobre interfaces fluentes afirmei que a implementação do exemplo não tinha sido difícil, mas para situações um mais complexas, do tipo "mundo real", a coisa podia complicar. O Martin Fowler apresenta outro problema das interfaces fluentes que é a violação de algumas regras de OO e boa prática de programação.
A primeira é que todos os métodos retornam o próprio objeto, isto no mínimo é esquisito, mas além disto viola uma regra de OO que métodos devem ser divididos entre query e commands. Métodos do tipo query retornam um valor, mas não alteram o estado do objeto. Já métodos do tipo commands alteram o estado do objeto, mas não retornam um valor (eu sinceramente nem sabia que esta regra existia... )
Outro problema é que temos que incluir alguns métodos nos lugares “errados” para obter a fluência que desejamos. Veja no caso do exemplo que fiz no post anterior, se quiséssemos marcar uma linha da ordem como livre de impostos.
Para obter o seguinte resultado:
Order order = cust.NewOrder()
.With(1, 10.0F).NonTaxable()
.With(2, 12.3F)
.ShipTo("My address");
Eu teria que fazer esta alterações:
public class Order
{
//...
private OrderLine _currentOrderLine;
//....
public Order NonTaxable()
{
_currentOrderLine.NonTaxable = true;
return this;
}
}
public class OrderLine
{
//....
private bool _nonTaxable;
public bool NonTaxable
{
get { return _nonTaxable; }
set { _nonTaxable = value; }
}
//...
}
O método NonTaxable na classe Order não parece estar no lugar certo, afinal ele altera uma propriedade da linha e não da ordem em si.
Que bom que algumas pessoas não só identificam os problemas, mas também sugerem soluções. O próprio Martin Fowler sugere uma solução interessante que é criar uma classe OrderBuilder, responsável pela criação de um objeto Order. Nela fica toda a lógica da interface fluente, deixando a classe Order limpa, contendo apenas os seus métodos e propriedades. Para maiores detalhes veja o artigo original do Fowler.