π£ chap10. λλ€λ₯Ό μ΄μ©ν λλ©μΈ μ μ© μΈμ΄
chap10. λλ€λ₯Ό μ΄μ©ν λλ©μΈ μ μ© μΈμ΄
10.1 λλ©μΈ μ μ© μΈμ΄
DSL(domain specific languages)μ λ²μ© νλ‘κ·Έλλ° μΈμ΄κ° μλλΌ νΉμ λΉμ¦λμ€ λλ©μΈμ λ¬Έμ λ₯Ό ν΄κ²°νλ €κ³ λ§λ μΈμ΄λ€.
νΉμ λλ©μΈμλ§ κ΅νλλ―λ‘ μ€μ§ μμ μ λ¬Έμ λ₯Ό μ΄λ»κ² ν΄κ²°ν μ§μλ§ μ§μ€ν μ μκ³ λ³΅μ‘μ±μ μ λ€λ£° μ μλ€.
- DSLμ κ°λ°νκΈ° μν΄ νμν μ
- μμ¬ μν΅μ μ: νλ‘κ·Έλλ¨Έκ° μλ μ¬λλ μ΄ν΄ν μ μλλ‘ μ½λμ μλκ° λͺ νν μ λ¬λμ΄μΌ ν¨(μ½λκ° λΉμ¦λμ€ μꡬμ¬νμ λΆν©νλμ§ νμΈ κ°λ₯)
- ν λ² μ½λλ₯Ό ꡬννμ§λ§ μ¬λ¬λ² μ½λλ€: κ°λ μ±μ μ μ§λ³΄μμ ν΅μ¬. λλ£κ° μ½κ² μ΄ν΄ν μ μλλ‘ μ½λ ꡬν νμ
μ₯μ
- κ°κ²°ν¨
- κ°λ μ±
- μ μ§λ³΄μ
- λμ μμ€μ μΆμν
- μ§μ€
- κ΄μ¬μ¬ λΆλ¦¬(Separation of concerns)
λ¨μ
- DLS μ€κ³μ μ΄λ €μ
- κ°λ° λΉμ©
- μΆκ° μ°ν κ³μΈ΅
- μλ‘ λ°°μμΌ νλ μΈμ΄
- νΈμ€ν μΈμ΄ νκ³
λ΄λΆ DSL
- μμ μλ°μ½λ κ°μ κΈ°μ‘΄ νΈμ€ν μΈμ΄λ₯Ό κΈ°λ°μΌλ‘ ꡬνν DSL
- μ μ°μ±μ΄ λ¨μ΄μ§κΈ° λλ¬Έμ κ°λ¨νκ³ ννλ ₯ μλ DSLμ λ§λλλ° νκ³κ° μμμ§λ§ λλ€ ννμμ΄ λ±μ₯νλ©΄μ μ΄λμ λ ν΄κ²°λ μ μμ
- μμ μλ°λ‘ DSL μ ꡬν μ μ₯μ
- μΈλΆ DSLμ λΉν΄ μλ‘μ΄ ν¨ν΄κ³Ό κΈ°μ μ λ°°μ DSLμ ꡬννλ λ Έλ ₯μ΄ κ°μ
- μμ μλ°λ‘ DSL μ ꡬννλ©΄ λλ¨Έμ§ μ½λμ ν¨κ» μ»΄νμΌ κ°λ₯. (λ€λ₯Έ μΈμ΄μ μ»΄νμΌλ¬ λλ μΈλΆ DSLμ λ§λλ λꡬλ₯Ό μ¬μ©νμ§ μμλ λ¨)
- μλ‘μ΄ μΈμ΄λ₯Ό λ°°μ°κ±°λ 볡μ‘ν μΈλΆ λꡬλ₯Ό λ°°μΈ νμκ° μμ
- DSL μ¬μ©μλ κΈ°μ‘΄μ μλ° IDEλ‘ μλ μμ±, 리ν©ν°λ§ κΈ°λ₯ κ·Έλλ‘ μ¬μ© κ°λ₯
- μΆκ° DSLμ μ½κ² ν©μΉ μ μμ
λ€μ€ DSL
μλ°λ μλμ§λ§ JVMμμ μ€νλλ©° λ μ μ°νκ³ ννλ ₯μ΄ κ°λ₯ν μΈμ΄(ex. μ€μΉΌλΌ, 그루λΉβ¦)λ‘ κ΅¬νν DSL
μ½νλ¦°, μ€λ‘ κ°μ΄ μ€μΉΌλΌμ νΈνμ±μ΄ μ μ§λλ©° λ¨μνκ³ μ½κ² λ°°μΈ μ μλ μ μΈμ΄λ μ‘΄μ¬νλ€.
μ΄ μΈμ΄λ€μ λͺ¨λ μλ°λ³΄λ€ μ μΌλ©° μ μ½μ μ€μ΄κ³ , κ°νΈν λ¬Έλ²μ μ§ν₯νλλ‘ μ€κ³λμλ€.
DSL μΉνμ μ΄μ§λ§ λ€μκ³Ό κ°μ λ¨μ λ€μ΄ μ‘΄μ¬νλ€.
- μλ‘μ΄ νλ‘κ·Έλλ° μΈμ΄λ₯Ό λ°°μ°κ±°λ λκ΅°κ° ν΄λΉ κΈ°μ μ μ§λκ³ μμ΄μΌ ν¨
- λ κ° μ΄μμ μΈμ΄κ° νΌμ¬νλ―λ‘ μ¬λ¬ μ»΄νμΌλ¬λ‘ μμ€λ₯Ό λΉλνλλ‘ λΉλ κ³Όμ μ κ°μ ν΄μΌ ν¨
- JVM μμ μ€νλμ§λ§ μλ°μ νΈνμ±μ΄ μλ²½νμ§ μμ κ²½μ°κ° λ§μ (μ±λ₯ μμ€ κ°λ₯)
μΈλΆ DSL
- μ€ν λμ΄λ‘ (standalone)
- νΈμ€ν μΈμ΄μλ λ 립μ μΌλ‘ μ체μ λ¬Έλ²μ κ°μ§λ DSL
μμ λ§μ λ¬Έλ²κ³Ό ꡬ문μΌλ‘ μ μΈμ΄λ₯Ό μ€κ³ν΄μΌ νκ³ μΈμ΄ νμ±, νμμ κ²°κ³Ό λΆμ, μΈλΆ DSL μ€νν μ½λλ₯Ό λ§λ€μ΄μΌ ν¨
μ΄ λ°©λ²μ μ νν΄μΌ νλ€λ©΄ ANTLR κ°μ μλ° κΈ°λ° νμ μμ±κΈ°λ₯Ό μ΄μ©νλ©΄ λμμ λ°μ μ μμ
- μ₯μ
- 무νν μ μ°μ±μ κ°μ§
- νμν νΉμ±μ μλ²½νκ² μ 곡νλ μΈμ΄λ‘ μ€κ³ κ°λ₯
- λΉμ¦λμ€ λ¬Έμ λ₯Ό λ¬μ¬νκ³ ν΄κ²°νλ κ°λ μ± μ’μ μΈμ΄ μ ν κ°λ₯
- μλ°λ‘ κ°λ°λ μΈνλΌκ΅¬μ‘° μ½λμ λΉμ¦λμ€ μ½λλ₯Ό λͺ ννκ² λΆλ¦¬ κ°λ₯
- λ¨μ
- μΌλ°μ μΈ μμ μ΄ μλλ©° μ½κ² κΈ°μ μ μ»μ μ μμ
- μμ μ΄ λ³΅μ‘νκ³ μ μ΄ λ²μλ₯Ό μ½κ² λ²μ΄λ μ μμ
- μ²μ μ€κ³ν λͺ©μ μ λ²μ΄λλ κ²½μ°κ° λ§μ
- DSLκ³Ό νΈμ€νΈ μΈμ΄ μ¬μ΄μ μΈκ³΅ κ³μΈ΅μ΄ μκΉ
10.2 μ΅μ μλ° APIμ μμ DSL
λ€μ΄ν°λΈ μλ° API μλ μλ° μλ‘μ΄ κΈ°λ₯μ μ₯μ λ€μ΄ μ μ©λμλ€.
μ€νΈλ¦Ό API λ₯Ό ν΅ν΄ DSL μ΄ μ¬μ©λ μλ₯Ό νμΈνλ€.
μ€νΈλ¦Ό APIλ 컬λ μ μ μ‘°μνλ DSL
Stream
Β μΈν°νμ΄μ€λ λ€μ΄ν°λΈ μλ° API μ μμ λ΄λΆ DSLμ μ μ©ν μ’μ μλ€.
컬λ μ μ νλͺ©μ νν°, μ λ ¬, λ³ν, κ·Έλ£Ήν, μ‘°μνλ μμ§λ§ κ°λ ₯ν DSL μ΄λ€.
Stream
Β μΈν°νμ΄μ€λ₯Ό μ΄μ©νμ¬ ν¨μνμΌλ‘ ꡬννλ©΄ μ½κ³ κ°κ²°νλ€.
μ€νΈλ¦Ό APIμ ν루μΈνΈ νμ λν μ€κ³λ DSLμ νΉμ§ μ€ νλμ΄λ€.(μ€κ° μ°μ° κ²μΌλ¦, λ€λ₯Έ μ°μ°μΌλ‘ νμ΄νλΌμΈ κ°λ₯)
1
**Files.**lines**(Paths.**get**(**fileName**)).**filter**(**line **->** line**.**startWith**(**"ERROR"**)).**limit**(**40**).**collect**(**toList**());**
λ°μ΄ν°λ₯Ό μμ§νλ DSLμΈ Collectors
Collector
Β μΈν°νμ΄μ€λ λ°μ΄ν° μμ§(μμ§, κ·Έλ£Ήν, νμ΄μ
)μ μννλ DSLλ‘ κ°μ£Όν μ μλ€.
νΉν λ€μ€ νλ μ λ ¬μ μ§μνλλ‘ ν©μ³μ§ μ μμΌλ©°,Β Collectors
Β λ λ€μ€ μμ€ κ·Έλ£Ήνλ₯Ό λ¬μ±ν μ μλλ‘ ν©μ³μ§ μ μλ€.
1
2
3
4
5
6
7
**Map<String,** **Map<Color,** **List<Car>>>** carsByBrandAndColor **=** cars**.**stream**().**collect**(**grouping**(**Car:**:**getBrand**,** groupingBy**(**Car:**:**getColor**)));**
*// λ Comparators μ°κ²°*
**Comparator<Person>** comparator **=** comparing**(**Person:**:**getAge**).**thenComparing**(**Person:**:**getName**);**
*// μ€μ²©*
**Collector<?** **super** **Car,** **?,** **Map<Brand,** **Map<Color,** **List<Car>>>>** carGroupingCollector **=**groupingBy**(**Car:**:**getBrand**,** groupingBy**(**Car:**:**getColor**));**
10.3 μλ°λ‘ DSLμ λ§λλ ν¨ν΄κ³Ό κΈ°λ²
- μ£Όμ κ°κ²©μ λͺ¨λΈλ§νλ μμ μλ° λΉμ¦
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
public class Stock {
private String symbol;
private String market;
public String getSymbol(){
return symbol;
}
public void setSymbol(String symbol) {
this.symbol = symbol;
}
...
}
public class Trade {
public enum Type { BUY, SELL }
private Type type;
private Stock stock;
private int quantity;
private double price;
...
}
public class Order {
private String customer;
private List<Trade> trades = new ArrayList<>();
...
}
μ£Όλ¬Έ μμ± μ½λ
1
2
3
4
5
6
7
8
9
10
11
12
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");
trade.setStock(stock1);
...
νμ§λ§ μ΄λ¬ν μ½λλ μ₯ν©νκ³ λΉκ°λ°μμΈ λλ©μΈ μ λ¬Έκ°κ° μ΄ν΄νκ³ κ²μ¦νκΈ° μ΄λ ΅λ€.
μ§κ΄μ μΌλ‘ λλ©μΈ λͺ¨λΈμ λ°μν μ μλ DSL μ΄ νμνλ€. μ΄ μ± μμλ λ€μκ³Ό κ°μ DSL ν¨ν΄λ€μ μκ°νκ³ μλ€.
- λ©μλ 체μΈ
- μ€μ²©λ ν¨μ
- λλ€ ννμμ μ΄μ©ν ν¨μ μνμ±
λ©μλ 체μΈ
λ©μλ 체μΈμ DSL μμ κ°μ₯ νν λ°©μ μ€ νλμ΄λ€.
μ₯μ
- μ¬μ©μκ° μ§μ λ μ μ°¨μ λ°λΌ ν루μΈνΈ APIμ λ©μλ νΈμΆμ κ°μ
- νλΌλ―Έν°κ° λΉλ λ΄λΆλ‘ κ΅ν λ¨
- λ©μλ μ΄λ¦μ΄ μΈμμ μ΄λ¦μ λμ νμ¬ κ°λ μ± κ°μ
- λ¬Έλ²μ μ‘μμ΄ μ΅μν
- μ νν νλΌλ―Έν°μ μ λμ
- μ μ λ©μλ μ¬μ©μ μ΅μννκ±°λ μμ¨ μ μμ
λ¨μ
- λΉλλ₯Ό ꡬνν΄μΌ ν¨
- μμ μμ€μ λΉλλ₯Ό νμ μμ€μ λΉλμ μ°κ²°ν λ§μ μ μ°© μ½λκ° νμ
- λλ©μΈ κ°μ²΄μ μ€μ²© ꡬ쑰μ μΌμΉνκ² λ€μ¬μ°κΈ°λ₯Ό κ°μ ν μ μμ
1
2
3
4
5
6
Order order = forCustomer("BigBank")
.buy(80)
.stock("IBM")
.on("NYSE")
...
.end();
β μ΅μ μμ€ λΉλλ₯Ό λ§λ€κ³ μ£Όλ¬Έμ κ°μΈμ κ±°λλ₯Ό μΆκ°ν μ μλλ‘ ν΄μΌ ν¨
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
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.SELL, quantity);
}
public MethodChainingOrderBuilder addTrade(Trade trade) {
order.addTrade(trade);
return this;
}
public Order end() {
return order;
}
}
public class TradeBuilder {
private final MethodChainingOrderBuilder builder;
public final Trade trade = new Trade();
private TradeBuilder(MethodChainingOrderBuilder builder, Trade.Type type, int quantity) {
this.builder = builder;
trade.setType(type);
trade.setQuantity(quantity);
}
public StockBuilder stock(String symbol) {
return new StockBuilder(builder, trade, symbol);
}
}
public class StockBuilder {
private final MethodChainingOrderBuilder builder;
private final Trade trade;
private final Stock stock = new Stock();
private StockBuilder(MethodChainingOrderBuilder builder, Trade trade, String symbol) {
this.builder = builder;
this.trade = trade;
stock.setSymbol(symbol);
}
public TradeBuilderWithStock on(String market) {
stock.setMarket(market);
trade.setStock(stock);
return new TradeBuilderWithStock(builder, trade);
}
}
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) {
trade.setPrice(price);
return builder.addTrade(trade);
}
}
μ€μ²©λ ν¨μ μ΄μ©
μ€μ²©λ ν¨μ DSL ν¨ν΄μ λ€λ₯Έ ν¨μ μμ ν¨μλ₯Ό μ΄μ©ν΄ λλ©μΈ λͺ¨λΈμ λ§λ λ€.
- μ₯μ
- μ€μ²© λ°©μμ΄ λλ©μΈ κ°μ²΄ κ³μΈ΅ ꡬ쑰μ κ·Έλλ‘ λ°μ
- ꡬνμ μ₯ν©ν¨μ μ€μΌ μ μμ
- λ¨μ
- κ²°κ³Ό DSL μ λ λ§μ κ΄νΈλ₯Ό μ¬μ©
- μ μ λ©μλ μ¬μ©μ΄ λΉλ²
- μΈμ λͺ©λ‘μ μ μ λ©μλμ λ겨μ€μΌ ν¨
- μΈμμ μλ―Έκ° μ΄λ¦μ΄ μλλΌ μμΉμ μν΄ μ μ λ¨
- λλ©μΈμ μ ν μ¬ν νλκ° μμΌλ©΄ μΈμλ₯Ό μλ΅ν μ μμΌλ―λ‘ λ©μλ μ€λ²λ‘λ© νμ
1
2
3
4
Order order = order("BigBank",
buy(80, stock("IBM", on("NYSE")), at(125.00)),
sell(50, stock("GOOGLE", on("NASDAQ")), at(375.00))
);
ꡬν μ½λ
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
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);
}
private static Trade buildTrade(int quantity, Stock stock, double price, Trade.Type type) {
Trade trade = new Trade();
trade.setQuantity(quantity);
trade.setType(type);
trade.setStock(stock);
trade.setPrice(price);
return trade;
}
public static double at(double price) {
return price;
}
publid static Stock stock(String Symbol, String market) {
Stock stock = new Stock();
stock.setSymbol(symbol);
stock.setMarket(market);
return stock;
}
}
λλ€ ννμμ μ΄μ©ν ν¨μ μνμ±
λλ€ ννμμΌλ‘ μ μν ν¨μ μνμ€λ₯Ό μ¬μ©νλ€.
- μ₯μ
- ν루μΈνΈ λ°©μμΌλ‘ λλ©μΈ κ°μ²΄ μ μ κ°λ₯
- μ€μ²© λ°©μμ΄ λλ©μΈ κ°μ²΄ κ³μΈ΅ ꡬ쑰μ κ·Έλλ‘ λ°μ
- μ νν νλΌλ―Έν°μ μ λμ
- μ μ λ©μλλ₯Ό μ΅μννκ±°λ μμ¨ μ μμ
- λΉλμ μ μ°© μ½λκ° μμ
- λ¨μ
- μ€μ μ½λκ° νμ
- λλ€ ννμ λ¬Έλ²μ μν μ‘μμ μν₯μ λ°μ
μ‘°ν©νκΈ°
μ€μ²©λ ν¨μ ν¨ν΄κ³Ό λλ€ κΈ°λ²μ νΌμ©νλ©΄ λ€μκ³Ό κ°μ΄ μ¬μ©ν μ μλ€.
- μ₯μ
- κ°λ μ± ν₯μ
- λ¨μ
- μ¬λ¬ κΈ°λ²μ νΌμ©νκΈ° λλ¬Έμ μ¬μ©μκ° DSLμ λ°°μ°λ μκ°μ΄ μ€λ κ±Έλ¦Ό