Implementation using API-Streams and API-Lambda Java 8

0

Good People.

Trying unsuccessfully to resolve a proposed exercise using the new functionality of the Java Streams and Lambda 8 APIs. In this exercise, you can only create and change signature methods in the Shopping Cart class. The idea is to use the functionality of the Streams and Lambda APIs in the resolution. Any idea how I can attack the resolution?

CartComprasFactory

public CarrinhoCompras criar(String identificacaoCliente) {
} 

public BigDecimal getValorTicketMedio() {
}

public boolean invalidar(String identificacaoCliente) {
}

Shopping Cart

public void adicionarItem(Produto produto, BigDecimal valorUnitario, int quantidade) {
}

public boolean removerItem(Produto produto) {
}

public boolean removerItem(int posicaoItem) {
}

public BigDecimal getValorTotal() {
}

Product

public class Produto {

    private Long codigo;
    private String descricao;

    public Produto(Long codigo, String descricao) {
    }

    //getters and setters
}

Item

public class Item {

    private Produto produto;
    private BigDecimal valorUnitario;
    private int quantidade;

    public Item(Produto produto, BigDecimal valorUnitario, int quantidade) {
    }

    public BigDecimal getValorTotal() {
    }

    //getters and setters
}
    
asked by anonymous 09.05.2017 / 20:10

1 answer

1

One possible solution to follow. It does not have ideal architecture and performance, but it illustrates several elements of Java 8, within the constraints of the statement.

Product Class:

package br.teste.compras;

public class Produto {

  private Long codigo;
  private String descricao;

  public Produto(Long codigo, String descricao) {
    setCodigo(codigo);
    setDescricao(descricao);
  }

  // getters and setters omitidos

}

Class Item:

package br.teste.compras;

import java.math.BigDecimal;

public class Item {
  private Produto produto;
  private BigDecimal valorUnitario;
  private int quantidade;

  public Item(Produto produto, BigDecimal valorUnitario, int quantidade) {
    setProduto(produto);
    setValorUnitario(valorUnitario);
    setQuantidade(quantidade);
  }

  public BigDecimal getValorTotal() {
    Multiplicador<Integer> multiplicador = (val1, val2) -> val2.multiply(BigDecimal.valueOf(val1));
    return multiplicador.multiplicar(getQuantidade(), getValorUnitario());
  }

  @FunctionalInterface
  interface Multiplicador<F> {
    BigDecimal multiplicar(F val1, BigDecimal val2);
  }

  //getters and setters omitidos

}

Class Shopping Cart:

package br.teste.compras;

import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.List;

public class CarrinhoCompras {
  private List<Item> items = new ArrayList<Item>();

  //São admitidas repetições de um mesmo produto.
  //Para uma melhor arquitetura, o valorUnitario deveria ser atributo de Produto.
  public void adicionarItem(Produto produto, BigDecimal valorUnitario, int quantidade) {
    items.add(new Item(produto, valorUnitario, quantidade));
  }

  public boolean removerItem(Produto produto) {
    return items.remove(produto); //retorna true se removido
  }

  public boolean removerItem(int posicaoItem) {
    //Não é a implementação mais eficiente, mas ilustra o uso do Java 8. 
    return items.removeIf(item -> posicaoItem == items.indexOf(item));
  }

  public BigDecimal getValorTotal() {
    return items.stream().map(Item::getValorTotal).reduce(BigDecimal.ZERO, BigDecimal::add);
  }

  //Único método adicionado à classe, conforme permitido pelo enunciado.
  public List<Item> getItems() {
    return items;
  }

}

Class Shopping CartFactory:

package br.teste.compras;

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.HashMap;
import java.util.Map;

public class CarrinhoComprasFactory {
  //Armazena os clientes e seus carrinhos.
  private final Map<String, CarrinhoCompras> map = new HashMap<>();

  public CarrinhoCompras criar(String identificacaoCliente) {
    map.put(identificacaoCliente, new CarrinhoCompras());
    return map.get(identificacaoCliente);
  }

  //Não está clara a função deste método, mas aqui retorna o valor médio dos valores totais nos carrinhos dos clientes.
  public BigDecimal getValorTicketMedio() {
    return map.values().stream()
              .map(carrinho -> carrinho.getValorTotal())
              .reduce(BigDecimal.ZERO, BigDecimal::add)
              .divide(BigDecimal.valueOf(map.size()), RoundingMode.FLOOR);
  }

  //Retorna true se existe esse cliente.
  public boolean invalidar(String identificacaoCliente) {
    return map.remove(identificacaoCliente) != null;
  }

}

A test class, also with some elements of Java 8:

package br.teste.compras;

import java.math.BigDecimal;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.ThreadLocalRandom;
import java.util.stream.Collectors;
import java.util.stream.LongStream;

public class Build {

    public static void main(String[] args) {
        CarrinhoComprasFactory factory = new CarrinhoComprasFactory();
        Map<Long, CarrinhoCompras> map = new HashMap<>();
        //Inclui 3 clientes
        LongStream.range(1, 4).forEach(idx -> map.put(idx, factory.criar("Cliente " + idx)));
        //adiciona 3 produtos no carrinho de cada cliente.
        map.forEach((clienteID, carrinho) -> {
            System.out.println("*** Cliente " + clienteID + " ***");
            LongStream.range(1, 4).forEach(idx -> {
                Long random = ThreadLocalRandom.current().nextLong(1, 100);
                carrinho.adicionarItem(
                        new Produto(random * 100, "Produto " +  clienteID * 1000 + idx),
                        BigDecimal.valueOf(random), (int)(random % 11 + 1));
            });
            //imprime os items gerados
            System.out.println(carrinho.getItems().stream()
                    .map(item -> item.getProduto().getDescricao() + "(" + item.getProduto().getCodigo() + "): " +
                            item.getQuantidade() + " x $" + item.getValorUnitario() + " = $" + item.getValorTotal())
                    .collect(Collectors.joining(", ")));
        });
        System.out.println("Media clientes 1, 2 e 3: $" + factory.getValorTicketMedio());
        factory.invalidar("Cliente 3");
        map.remove(Long.valueOf(3)); // :-(
        map.get(Long.valueOf(2)).removerItem(1);
        map.get(Long.valueOf(1)).removerItem(map.get(Long.valueOf(1)).getItems().get(0).getProduto());
        System.out.println("Media clientes 1 e 2: $" + factory.getValorTicketMedio());
    }

}

As the construction of item values is random, below is an example of output printed by the above class (Build):

*** Cliente 1 ***
Produto 10001(4400): 1 x $44 = $44, Produto 10002(2700): 6 x $27 = $162, Produto 10003(6900): 4 x $69 = $276
*** Cliente 2 ***
Produto 20001(3500): 3 x $35 = $105, Produto 20002(5200): 9 x $52 = $468, Produto 20003(9500): 8 x $95 = $760
*** Cliente 3 ***
Produto 30001(6700): 2 x $67 = $134, Produto 30002(2800): 7 x $28 = $196, Produto 30003(5000): 7 x $50 = $350
Media clientes 1, 2 e 3: $831
Media clientes 1 e 2: $673
    
24.05.2017 / 18:49