Esempi di creazione di un DSL interno con Java con diversi pattern

This commit is contained in:
Fabio Scotto di Santolo
2019-11-28 13:37:22 +01:00
parent 4995879731
commit 1dcc63c284
14 changed files with 576 additions and 0 deletions

View File

@@ -0,0 +1,141 @@
package org.gym.fp.moderjava;
import org.gym.fp.moderjava.dsl.*;
import static java.lang.System.out;
import static org.gym.fp.moderjava.dsl.LambdaOrderBuilder.order;
import static org.gym.fp.moderjava.dsl.MethodChainingOrderBuilder.forCustomer;
import static org.gym.fp.moderjava.dsl.NestedFunctionOrderBuilder.at;
import static org.gym.fp.moderjava.dsl.NestedFunctionOrderBuilder.buy;
import static org.gym.fp.moderjava.dsl.NestedFunctionOrderBuilder.on;
import static org.gym.fp.moderjava.dsl.NestedFunctionOrderBuilder.order;
import static org.gym.fp.moderjava.dsl.NestedFunctionOrderBuilder.sell;
import static org.gym.fp.moderjava.dsl.NestedFunctionOrderBuilder.stock;
public class DslTest {
public static void main(String[] args) {
doUnacceptableDslTest();
doMethodChainingPatternTest();
doNestedFunctionsPatternTest();
doLambdaSequencingPatternTest();
doMixedPatternTest();
doUsingMethodReferenceDslTest();
}
private static void doUnacceptableDslTest() {
Order order = new Order();
order.setCustomer("BigBank");
Trade trade1 = new Trade();
trade1.setType(Trade.Type.BUY);
Stock stock1 = new Stock();
stock1.setSymbol("IBM");
stock1.setMarket("NYSE");
trade1.setStock(stock1);
trade1.setPrice(125.00);
trade1.setQuantity(80);
order.addTrade(trade1);
Trade trade2 = new Trade();
trade2.setType(Trade.Type.BUY);
Stock stock2 = new Stock();
stock2.setSymbol("GOOGLE");
stock2.setMarket("NASDAQ");
trade2.setStock(stock2);
trade2.setPrice(375.00);
trade2.setQuantity(50);
order.addTrade(trade2);
}
private static void doMethodChainingPatternTest() {
Order order = forCustomer("BigBank")
.buy(80)
.stock("IBM")
.on("NYSE")
.at(125.00)
.sell(50)
.stock("Google")
.on("NASDAQ")
.at(375.00)
.end();
out.println("Order: " + order.toString());
out.println("----------------------------------------");
}
private static void doNestedFunctionsPatternTest() {
Order order = order("BigBank",
buy(80,
stock("IBM", on("NYSE")),
at(125.00)),
sell(50,
stock("Google", on("NASDAQ")),
at(375.00))
);
out.println("Order: " + order.toString());
out.println("----------------------------------------");
}
private static void doLambdaSequencingPatternTest() {
Order order = order(o -> {
o.forCustomer("BigBank");
o.buy(t -> {
t.quantity(80);
t.price(125.00);
t.stock(s -> {
s.symbol("IBM");
s.market("NYSE");
});
});
o.sell(t -> {
t.quantity(50);
t.price(375.00);
t.stock(s -> {
s.symbol("GOOGLE");
s.market("NASDAQ");
});
});
});
out.println("Order: " + order.toString());
out.println("----------------------------------------");
}
private static void doMixedPatternTest() {
Order order = MixedBuilder.forCustomer("BigBank",
MixedBuilder.buy(t -> t.quantity(80)
.stock("IBM")
.on("NYSE")
.at(125.00)),
MixedBuilder.sell(t -> t.quantity(50)
.stock("Google")
.on("NASDAQ")
.at(375.00))
);
out.println("Order: " + order.toString());
out.println("----------------------------------------");
}
private static void doUsingMethodReferenceDslTest() {
Order order = MixedBuilder.forCustomer("BigBank",
MixedBuilder.buy(t -> t.quantity(80)
.stock("IBM")
.on("NYSE")
.at(125.00)),
MixedBuilder.sell(t -> t.quantity(50)
.stock("Google")
.on("NASDAQ")
.at(375.00))
);
double value = new TaxCalculator()
.with(Tax::regional)
.with(Tax::surcharge)
.calculate(order);
out.printf("Calculate value order with taxes: %.2f\n", value);
out.println("----------------------------------------");
}
}

View File

@@ -0,0 +1,29 @@
package org.gym.fp.moderjava.dsl;
import java.util.List;
import java.util.Map;
import java.util.function.Function;
import java.util.stream.Collector;
import static java.util.stream.Collectors.groupingBy;
public class GroupingBuilder<T, D, K> {
private final Collector<? super T, ?, Map<K, D>> collector;
public GroupingBuilder(Collector<? super T, ?, Map<K, D>> collector) {
this.collector = collector;
}
public Collector<? super T, ?, Map<K, D>> get() {
return collector;
}
public <J> GroupingBuilder<T, Map<K, D>, J> after(Function<? super T, ? extends J> classifier) {
return new GroupingBuilder<>(groupingBy(classifier, collector));
}
public static <T, D, K> GroupingBuilder<T, List<T>, K> groupOn(Function<? super T, ? extends K> classifier) {
return new GroupingBuilder<>(groupingBy(classifier));
}
}

View File

@@ -0,0 +1,65 @@
package org.gym.fp.moderjava.dsl;
import java.util.function.Consumer;
public class LambdaOrderBuilder {
private Order order = new Order();
public static Order order(Consumer<LambdaOrderBuilder> consumer) {
LambdaOrderBuilder builder = new LambdaOrderBuilder();
consumer.accept(builder);
return builder.order;
}
public void forCustomer(String customer) {
order.setCustomer(customer);
}
public void buy(Consumer<TradeBuilder> consumer) {
trade(consumer, Trade.Type.BUY);
}
public void sell(Consumer<TradeBuilder> consumer) {
trade(consumer, Trade.Type.SELL);
}
private void trade(Consumer<TradeBuilder> consumer, Trade.Type type) {
TradeBuilder builder = new TradeBuilder();
builder.trade.setType(type);
consumer.accept(builder);
order.addTrade(builder.trade);
}
public static class TradeBuilder {
private Trade trade = new Trade();
public void quantity(int quantity) {
trade.setQuantity(quantity);
}
public void price(double price) {
trade.setPrice(price);
}
public void stock(Consumer<StockBuilder> consumer) {
StockBuilder builder = new StockBuilder();
consumer.accept(builder);
trade.setStock(builder.stock);
}
}
public static class StockBuilder {
private Stock stock = new Stock();
public void symbol(String symbol) {
stock.setSymbol(symbol);
}
public void market(String market) {
stock.setMarket(market);
}
}
}

View File

@@ -0,0 +1,31 @@
package org.gym.fp.moderjava.dsl;
public class MethodChainingOrderBuilder {
public final Order order = new Order();
private MethodChainingOrderBuilder(String customer) {
order.setCustomer(customer);
}
public static MethodChainingOrderBuilder forCustomer(String customer) {
return new MethodChainingOrderBuilder(customer);
}
public TradeBuilder buy(int quantity) {
return new TradeBuilder(this, Trade.Type.BUY, quantity);
}
public TradeBuilder sell(int quantity) {
return new TradeBuilder(this, Trade.Type.SELL, quantity);
}
public MethodChainingOrderBuilder addTrade(Trade trade) {
order.addTrade(trade);
return this;
}
public Order end() {
return order;
}
}

View File

@@ -0,0 +1,68 @@
package org.gym.fp.moderjava.dsl;
import java.util.function.Consumer;
import java.util.stream.Stream;
public class MixedBuilder {
public static Order forCustomer(String customer, TradeBuilder... builders) {
Order order = new Order();
order.setCustomer(customer);
Stream.of(builders).forEach(b -> order.addTrade(b.trade));
return order;
}
public static TradeBuilder buy(Consumer<TradeBuilder> consumer) {
return buildTrade(consumer, Trade.Type.BUY);
}
public static TradeBuilder sell(Consumer<TradeBuilder> consumer) {
return buildTrade(consumer, Trade.Type.SELL);
}
private static TradeBuilder buildTrade(Consumer<TradeBuilder> consumer, Trade.Type type) {
TradeBuilder builder = new TradeBuilder();
builder.trade.setType(type);
consumer.accept(builder);
return builder;
}
public static class TradeBuilder {
private Trade trade = new Trade();
public TradeBuilder quantity(int quantity) {
trade.setQuantity(quantity);
return this;
}
public TradeBuilder at(double price) {
trade.setPrice(price);
return this;
}
public StockBuilder stock(String symbol) {
return new StockBuilder(this, trade, symbol);
}
}
public static class StockBuilder {
private final TradeBuilder builder;
private final Trade trade;
private final Stock stock = new Stock();
public StockBuilder(TradeBuilder tradeBuilder, Trade trade, String symbol) {
this.builder = tradeBuilder;
this.trade = trade;
this.stock.setSymbol(symbol);
}
public TradeBuilder on(String market) {
this.stock.setMarket(market);
trade.setStock(this.stock);
return builder;
}
}
}

View File

@@ -0,0 +1,46 @@
package org.gym.fp.moderjava.dsl;
import java.util.stream.Stream;
public class NestedFunctionOrderBuilder {
public static Order order(String customer, Trade... trades) {
Order order = new Order();
order.setCustomer(customer);
Stream.of(trades).forEach(order::addTrade);
return order;
}
public static Trade buy(int quantity, Stock stock, double price) {
return buildTrade(quantity, stock, price, Trade.Type.BUY);
}
public static Trade sell(int quantity, Stock stock, double price) {
return buildTrade(quantity, stock, price, Trade.Type.SELL);
}
private static Trade buildTrade(int quantity, Stock stock, double price, Trade.Type buy) {
Trade trade = new Trade();
trade.setQuantity(quantity);
trade.setType(buy);
trade.setStock(stock);
trade.setPrice(price);
return trade;
}
public static double at(double price) {
return price;
}
public static Stock stock(String symbol, String market) {
Stock stock = new Stock();
stock.setSymbol(symbol);
stock.setMarket(market);
return stock;
}
public static String on(String market) {
return market;
}
}

View File

@@ -0,0 +1,31 @@
package org.gym.fp.moderjava.dsl;
import lombok.ToString;
import java.util.ArrayList;
import java.util.List;
@ToString
public class Order {
private String customer;
private List<Trade> trades = new ArrayList<>();
public void addTrade(Trade trade) {
trades.add(trade);
}
public String getCustomer() {
return customer;
}
public void setCustomer(String customer) {
this.customer = customer;
}
public double getValue() {
return trades.stream()
.mapToDouble(Trade::getValue)
.sum();
}
}

View File

@@ -0,0 +1,25 @@
package org.gym.fp.moderjava.dsl;
import lombok.ToString;
@ToString
public class Stock {
private String symbol;
private String market;
public String getSymbol() {
return symbol;
}
public void setSymbol(String symbol) {
this.symbol = symbol;
}
public String getMarket() {
return market;
}
public void setMarket(String market) {
this.market = market;
}
}

View File

@@ -0,0 +1,21 @@
package org.gym.fp.moderjava.dsl;
public class StockBuilder {
private final MethodChainingOrderBuilder builder;
private final Trade trade;
private final Stock stock = new Stock();
public StockBuilder(MethodChainingOrderBuilder builder,
Trade trade, String symbol) {
this.builder = builder;
this.trade = trade;
this.stock.setSymbol(symbol);
}
public TradeBuilderWithStock on(String market) {
this.stock.setMarket(market);
trade.setStock(this.stock);
return new TradeBuilderWithStock(builder, trade);
}
}

View File

@@ -0,0 +1,17 @@
package org.gym.fp.moderjava.dsl;
public class Tax {
public static double regional(double value) {
return value * 1.1;
}
public static double general(double value) {
return value * 1.3;
}
public static double surcharge(double value) {
return value * 1.05;
}
}

View File

@@ -0,0 +1,17 @@
package org.gym.fp.moderjava.dsl;
import java.util.function.DoubleUnaryOperator;
public class TaxCalculator {
private DoubleUnaryOperator taxFunction = d -> d;
public TaxCalculator with(DoubleUnaryOperator f) {
this.taxFunction = taxFunction.andThen(f);
return this;
}
public double calculate(Order order) {
return this.taxFunction.applyAsDouble(order.getValue());
}
}

View File

@@ -0,0 +1,50 @@
package org.gym.fp.moderjava.dsl;
import lombok.ToString;
@ToString
public class Trade {
public enum Type {BUY, SELL}
private Type type;
private Stock stock;
private int quantity;
private double price;
public Type getType() {
return type;
}
public void setType(Type type) {
this.type = type;
}
public Stock getStock() {
return stock;
}
public void setStock(Stock stock) {
this.stock = stock;
}
public int getQuantity() {
return quantity;
}
public void setQuantity(int quantity) {
this.quantity = quantity;
}
public double getPrice() {
return price;
}
public void setPrice(double price) {
this.price = price;
}
public double getValue() {
return quantity * price;
}
}

View File

@@ -0,0 +1,18 @@
package org.gym.fp.moderjava.dsl;
public class TradeBuilder {
private final MethodChainingOrderBuilder builder;
private final Trade trade = new Trade();
public TradeBuilder(MethodChainingOrderBuilder builder,
Trade.Type buy, int quantity) {
this.builder = builder;
this.trade.setType(buy);
this.trade.setQuantity(quantity);
}
public StockBuilder stock(String symbol) {
return new StockBuilder(builder, trade, symbol);
}
}

View File

@@ -0,0 +1,17 @@
package org.gym.fp.moderjava.dsl;
public class TradeBuilderWithStock {
private final MethodChainingOrderBuilder builder;
private final Trade trade;
public TradeBuilderWithStock(MethodChainingOrderBuilder builder, Trade trade) {
this.builder = builder;
this.trade = trade;
}
public MethodChainingOrderBuilder at(double price) {
this.trade.setPrice(price);
return builder.addTrade(trade);
}
}