Skip to main content

Fluent Interface

  • Fluent Interface

Intenção

  • O Builder é um padrão de projeto criacional que permite a você implementar APIs orientadas a objetos de uma maneira que visa fornecer código mais legível e detectável.

Exemplo

using System;
namespace FluentInterfaceDesignPattern
{
public class Employee
{
public string FullName { get; set; }
public DateTime DateOfBirth { get; set; }
public string Department { get; set; }
public string Address { get; set; }
}
}

//

using System;
namespace FluentInterfaceDesignPattern
{
public class FluentEmployee
{
private Employee employee = new Employee();
public FluentEmployee NameOfTheEmployee(string FullName)
{
employee.FullName = FullName;
return this;
}
public FluentEmployee Born(string DateOfBirth)
{
employee.DateOfBirth = Convert.ToDateTime(DateOfBirth);
return this;
}
public FluentEmployee WorkingOn(string Department)
{
employee.Department = Department;
return this;
}
public FluentEmployee StaysAt(string Address)
{
employee.Address = Address;
return this;
}
public void ShowDetails()
{
Console.WriteLine($"Name: {employee.FullName}, \nDateOfBirth: {employee.DateOfBirth}, \nDepartment: {employee.Department}, \nAddress: {employee.Address}");
}
}
}

Exemplo com encadeamento de interfaces


/*INTERFACES*/
public interface IClickHouseSelectRoot
{
IClickHouseSelectQuery Select(string queryBase);

}
public interface IClickHouseSelectQuery
{
IClickHouseSelectFrom From(string from, bool adicionarPropriedadeDesduplicar = false);
}
public interface IClickHouseSelectFrom : IClickHouseOrderBy, IClickHouseLimit
{
IClickHouseSelectWhere Where(string condicao, object valor, bool deveAdicionarWhere = true);
IClickHouseSelectWhere WhereComplexSearch(WhereComplexSearchDto whereComplexSearchDto);
IClickHouseOrderBy GroupBy(string campos);

}

/*CLASS*/
public sealed class ClickHouseSelect : ClickHouseRoot,
IClickHouseSelectRoot,
IClickHouseSelectQuery,
IClickHouseSelectFrom,
IClickHouseSelectWhere,
IClickHouseGroupBy,
IClickHouseOrderBy,
IClickHouseLimit,
IClickHouseOffset
{
private string _orderBy;
private string _limit;
private string _offset;
private string _groupBy;


public IClickHouseSelectWhere And(string condicao, object valor, bool deveAdicionarParametro = true)
{
if (!deveAdicionarParametro) return this;

DeclaracaoParametroClickHouse clickHouseParametro = new(valor, condicao);

AtribuirParametro(clickHouseParametro.NomeParametro, clickHouseParametro.Valor);

if (AdicionouWhere(clickHouseParametro.Condicao)) return this;

_and += $"AND {clickHouseParametro.Condicao} ";

return this;
}

public IClickHouseSelectWhere Or(string condicao, object valor, bool deveAdicionarParametro = true)
{
if (!deveAdicionarParametro) return this;

DeclaracaoParametroClickHouse clickHouseParametro = new(valor, condicao);

AtribuirParametro(clickHouseParametro.NomeParametro, clickHouseParametro.Valor);

if (AdicionouWhere(clickHouseParametro.Condicao)) return this;

_or += $"OR {clickHouseParametro.Condicao} ";

return this;
}

public IClickHouseSelectFrom From(string from, bool adicionarPropriedadeDesduplicar = false)
{
_from = $"FROM {_nomeBanco}.{from}";

if (adicionarPropriedadeDesduplicar)
_from += " FINAL";

return this;
}

public IClickHouseSelectQuery Select(string queryBase)
{
_queryBase = queryBase;
return this;
}

public IClickHouseSelectWhere Where(string condicao, object valor, bool deveAdicionarWhere)
{
if (!deveAdicionarWhere) return this;

DeclaracaoParametroClickHouse clickHouseParametro = new(valor, condicao);

_where = $"WHERE {clickHouseParametro.Condicao}";

AtribuirParametro(clickHouseParametro.NomeParametro, clickHouseParametro.Valor);

return this;
}

public IClickHouseSelectWhere Between(ClickHouseBetween clickHouseBetween)
{
if (!clickHouseBetween.DeveAdicionarParametro) return this;

DeclaracaoParametroBetweenClickHouse declaracaoBetweenPrimeiroValor = new(clickHouseBetween.ValorInicial, clickHouseBetween.Condicao);
DeclaracaoParametroBetweenClickHouse declaracaoBetweenSegundoValor = new(clickHouseBetween.ValorFinal, declaracaoBetweenPrimeiroValor.Condicao, ehPrimeiraParte: false);

Parametros.Add(declaracaoBetweenPrimeiroValor.NomeParametro, declaracaoBetweenPrimeiroValor.Valor);
Parametros.Add(declaracaoBetweenSegundoValor.NomeParametro, declaracaoBetweenSegundoValor.Valor);

if (AdicionouWhere(declaracaoBetweenSegundoValor.Condicao)) return this;

_between += $"AND {declaracaoBetweenSegundoValor.Condicao}";

return this;
}

public IClickHouseLimit OrderBy(string orderBy, OrdenacaoQuery ordenacaoQuery)
{
_orderBy = $"ORDER BY {orderBy} {ordenacaoQuery.GetDescription()}";
return this;
}

public IClickHouseOffset Limit(int quantidade, bool deveAdicionar)
{
if (!deveAdicionar) return this;

var nomeParametro = "ParametroLimite";

var formatoParametro = new FormatoParametroClickHouse(nomeParametro, "Int").ParametroFormatado;

_limit = "LIMIT " + formatoParametro;

Parametros.Add(nomeParametro, quantidade);

return this;
}

public IClickHouseOffset Offset(int quantidade, bool deveAdicionar)
{
if (!deveAdicionar) return this;

var nomeParametro = "ParametroOffset";

var formatoParametro = new FormatoParametroClickHouse(nomeParametro, "Int").ParametroFormatado;

_offset = "OFFSET " + formatoParametro;

Parametros.Add(nomeParametro, quantidade);

return this;
}

public IClickHouseOrderBy GroupBy(string campos)
{
_groupBy = $"GROUP BY {campos}";
return this;
}

public IClickHouseSelectWhere WhereComplexSearch(WhereComplexSearchDto whereComplexSearch)
{
if (!whereComplexSearch.DeveAdicionarWhereComplexSearch) return this;

if (!whereComplexSearch.Condicoes.Any()) return this;

List<string> condicoesConcatenadas = new (whereComplexSearch.Condicoes.Count);

for (int i = 0; i < whereComplexSearch.Condicoes.Count; i++)
{
DeclaracaoParametroLikeClickHouse clickHouseLikeParametro = new(whereComplexSearch.Valor, whereComplexSearch.Condicoes[i], whereComplexSearch.PosicaoPorcentagem);
condicoesConcatenadas.Add($" {clickHouseLikeParametro.Condicao}");

AtribuirParametro(clickHouseLikeParametro.NomeParametro, clickHouseLikeParametro.Valor);
}

_where = $" WHERE ({String.Join(" OR ", condicoesConcatenadas)})";

return this;
}
}

Anotações

Diferença entre o builder e o fluent interface

  • Objetivo: Builder foca na construção passo a passo de objetos complexos, gerenciando o processo de construção e os detalhes de implementação. Fluent Interface foca na usabilidade e legibilidade do código, permitindo que métodos sejam encadeados de forma expressiva.
  • Implementação: Enquanto o padrão Builder geralmente requer uma classe Director e uma ou mais classes Builder para gerenciar a construção de objetos, uma Fluent Interface é uma abordagem de design que pode ser implementada dentro de qualquer classe, melhorando a forma como os métodos dessa classe são chamados e encadeados.
  • Uso: Builder é usado quando a criação de um objeto é complexa e composta por várias etapas, possivelmente necessitando de diferentes representações do objeto. Fluent Interfaces são usadas para melhorar a legibilidade e fluidez do código cliente ao chamar métodos de uma classe.