Finally, ini adalah design pattern terakhir yang belum sempat gw bahas di blog ini dari 23 Design Pattern karya Gang of Four (GoF)😀. Sesuai namanya, Interpreter mengatur code menjadi kalimat sebuah bahasa, seperti bahasa SQL, HTML, scientific, atau bahasa DSL (Doman Specific Language) lainnya. Ciri-cirinya, terdapat satu interface sebagai Abstract Expression yang memiliki beberapa implementasi yang dapat digunakan secara recursive untuk membentuk sebuah kalimat atau grammar. Masing-masing implementasinya berfungsi sebagai Terminal Expression, yaitu implementasi yang bertugas memproduksi suatu grammar, ataupun Non-Terminal Expression, yaitu implementasi yang bertugas menampung & menerjemahkan Expression yang ditampung menjadi sebuah kalimat.
Interpreter Design Pattern adalah Behavioral Design Pattern yang menerjemahkan objek menjadi seperti sebuah kalimat atau grammar untuk suatu bahasa spesifik.
Design Pattern
Use Case
Karena ini salah satu Design Pattern yang kompleks, kita ambil contoh yang gampang aja, yaitu membangun HTML element menggunakan OOP yang hasilnya nanti seperti ini:
<div>
<div>
<p>hello</p>
<br />
<p>
<b>world</b>
</p>
</div>
</div>
Contoh Code
public class HtmlProcessor{
public static final String OPEN_DIV = "<div>";
public static final String CLOSE_DIV = "</div>";
public static final String OPEN_PARAGRAPH = "<p>";
public static final String CLOSE_PARAGRAPH = "</p>";
public static final String OPEN_BOLD = "<b>";
public static final String CLOSE_BOLD = "</b>";
public static final String BREAK_TAG = "<br />";
public static void main(String[] args){
interpret("hello", "world");
}
private static void interpret(String firstText, String secondText){
String interpret = OPEN_DIV + OPEN_DIV + OPEN_PARAGRAPH + firstText + CLOSE_PARAGRAPH + BREAK_TAG + OPEN_PARAGRAPH +
OPEN_BOLD + secondText + CLOSE_BOLD + CLOSE_PARAGRAPH + CLOSE_DIV + CLOSE_DIV;
System.out.println("interpret = " + interpret);
}
}
Sederhananya, kita tinggal concat string saja variabel dan element-nya.
Masalah
Dengan concat seperti itu, akan sangat menyulitkan code kita untuk di-maintain. Rawan dengan typo atau misplaced juga seandainya salah penempatan closing tag-nya.
Solusi
Sekarang kita coba terapkan Interpreter Design Pattern😎.
HtmlExpression Interface
public interface HtmlExpression{
String interpret();
}
TextExpression Class
//Terminal Expression
public class TextExpression implements HtmlExpression{
private final String text;
public TextExpression(String text){
this.text = text;
}
@Override
public String interpret(){
return text;
}
}
DivExpression Class
//Non-Terminal Expression
public class DivExpression implements HtmlExpression{
private final HtmlExpression[] expressions;
public DivExpression(HtmlExpression... expressions){
this.expressions = expressions;
}
@Override
public String interpret(){
StringBuilder builder = new StringBuilder("<div>");
for(HtmlExpression expression : expressions){
builder.append(expression.interpret());
}
builder.append("</div>");
return builder.toString();
}
}
ParagraphExpression Class
//Non-Terminal Expression
public class ParagraphExpression implements HtmlExpression{
private final HtmlExpression[] expressions;
public ParagraphExpression(HtmlExpression... expressions){
this.expressions = expressions;
}
@Override
public String interpret(){
StringBuilder builder = new StringBuilder("<p>");
for(HtmlExpression htmlExpression : expressions){
builder.append(htmlExpression.interpret());
}
builder.append("</p>");
return builder.toString();
}
}
BoldExpression Class
//Non-Terminal Expression
public class BoldExpression implements HtmlExpression{
private final HtmlExpression[] expressions;
public BoldExpression(HtmlExpression... expression){
this.expressions = expression;
}
@Override
public String interpret(){
StringBuilder builder = new StringBuilder("<b>");
for(HtmlExpression expression : expressions){
builder.append(expression.interpret());
}
builder.append("</b>");
return builder.toString();
}
}
BreakExpression Class
//Terminal Expression
public class BreakExpression implements HtmlExpression{
@Override
public String interpret(){
return "<br />";
}
}
Contoh penggunaan
public static void main(String[] args){
interpret("hello", "world");
}
private static void interpret(String firstText, String secondText){
TextExpression firstTextExpression = new TextExpression(firstText);
TextExpression secondTextExpression = new TextExpression(secondText);
BoldExpression boldExpression = new BoldExpression(secondTextExpression);
ParagraphExpression firstParagraph = new ParagraphExpression(firstTextExpression);
ParagraphExpression boldSecondParagraph = new ParagraphExpression(boldExpression);
BreakExpression breakExpression = new BreakExpression();
DivExpression childDivExpression = new DivExpression(firstParagraph, breakExpression, boldSecondParagraph);
DivExpression rootDivExpression = new DivExpression(childDivExpression);
System.out.println("interpret = " + rootDivExpression.interpret());
}
Kita menggunakan HtmlExpression sebagai Abstract Expression-nya. Lalu, kita menggunakan TextExpression & BreakExpression sebagai Terminal Expression, dan DivExpression, ParagraphExpression, dan BoldExpression sebagai Non-Terminal Expression yang menampung Terminal Expression dan menerjemahkannya menjadi grammar bahasa HTML. Kita tinggal susun objeknya seperti susunan HTML elemen dan eksekusi method interpret()
dari Expression-nya.
Kenapa menggunakan Interpreter Design Pattern?
Interpreter Design Pattern membantu kita menyusun objek untuk diterjemahkan menjadi kalimat atau grammar sebuah bahasa. Masing-masing objek disederhanakan dengan mengimplementasi satu Abstract Expression yang sama dan dapat disusun secara recursive seperti grammar suatu bahasa. Setiap Non-Terminal Expression akan menerjemahkan apapun implementasi dari Expression yang diinput tanpa harus tahu detail implementasinya. Walaupun tujuannya menyederhanakan objek menjadi sebuah bahasa, penggunaannya malah cukup rumit. Karena kerumitan inilah Interpreter Design Pattern menjadi salah satu Design Pattern yang jarang digunakan.
Verdict
Interpreter Design Pattern termasuk salah satu Design Pattern yang kasusnya cukup langka. Di dunia nyata, gw sendiri belum pernah menemukan kasus yang cocok diselesaikan menggunakan Design Pattern ini. Bahkan library untuk bikin HTML seperti Thymeleaf aja ga menggunakan Design Pattern ini dalam menyusun HTML. Banyak pendapat yang bilang bahwa Design Pattern karya GoF ini berisi 22 Design Pattern terbaik + sebuah joke. Joke yang dimaksud itu adalah Interpreter Design Pattern ini😅. Sekilas Design Pattern ini penggunaannya mirip Composite Design Pattern, tapi berbeda bentuk. Composite Design Pattern fokusnya adalah tentang hierarki objek antara objek tunggal & objek composite yang saling berkolaborasi. Sedangkan Interpreter Design Pattern ini berfokus pada interaksi antar objek dengan interface yang sama yang menghasilkan kalimat atau grammar.
Karena ini adalah Design Pattern terakhir dari karya GoF, maka lengkap sudah seri GoF Design Pattern yang gw bahas di blog ini👏. Selanjutnya mungkin nantinya gw akan bahas tentang Programming Principle atau Design Pattern lain selain karya GoF😎.