Esempi di creazione di un DSL interno con Java con diversi pattern
This commit is contained in:
141
modern-java/src/main/java/org/gym/fp/moderjava/DslTest.java
Normal file
141
modern-java/src/main/java/org/gym/fp/moderjava/DslTest.java
Normal 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("----------------------------------------");
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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));
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
17
modern-java/src/main/java/org/gym/fp/moderjava/dsl/Tax.java
Normal file
17
modern-java/src/main/java/org/gym/fp/moderjava/dsl/Tax.java
Normal 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;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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());
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user