Design Patterns: Meringkaskan Kode Dengan Dekorator

Ahmad Rizqi Meydiarso
Pujangga Teknologi
Published in
4 min readOct 21, 2018

Artikel ini adalah bagian pertama dari series Design Pattern yang akan di publikasikan di Pujangga Teknologi. Bagi yang belum terlalu paham dengan konsep design pattern: Design Pattern adalah koleksi dari solusi generik pemrograman untuk problem yang lumayan umum. Salah satu buku must-read di bidang ini adalah Design Pattern: Elements of Reusable Object Oriented Software, yang salah satu penulisnya adalah sang legenda Erich Gamma.

Contoh penggunaan dekorator pattern (Courtesy of https://assist-software.net/blog/implementation-decorator-pattern-c)

Dekorator Pattern

Salah satu fitur dari bahasa pemrograman yang mungkin bisa dibilang agak advanced adalah dekorator. Tujuan dari dekorator pattern ini adalah untuk menambahkan sebuah behavior umum ke dalam bagian kode di saat runtime tanpa cluttering the code. Behavior umum ini bisa berbagai macam, salah satu contoh use-case yang umum adalah menambahkan logging di sebuah function tanpa membuat kode menjadi unreadable:

Fungsi di atas sangatlah simpel, fungsi tersebut mengeluarkan hasil penambahan antara a dan b. Lalu kalau kita ingin menambahkan logging untuk parameter dan result difungsi tersebut maka fungsi tersebut menjadi seperti ini:

Walaupun secara fungsionalitas fungsi di atas valid, namun agak susah untuk melihat apa sejatinya tujuan dari fungsi ini secara 80% dari kode di atas bukanlah hal utamanya. Sedangkan inti dari fungsi tersebut hanyalah satu baris: result = a + b.

Dengan menggunakan dekorator fungsi di atas bisa direalisasikan sebagai berikut:

Disitulah fungsi dekorator yang bisa membuat kode menjadi lebih readable dengan menyembunyikan bagian-bagian kode yang tidak perlu. Selain itu @log bisa digunakan untuk memberikan fungsionalitas logging kepada banyak fungsi lain.

Annotasi dan Dekorator

Sebenarnya ada dua macam implementasi dari dekorator ini, di bahasa pemrograman statis seperti Java dan C# ada fitur yang disebut annotation / attribute. Walaupun secara penggunaan bisa dibilang mirip, perbedaan antar annotation dan dekorator adalah bagaimana fungsi dekorator / annotator dijalankan: dekorator dijalankan disaat runtime sedangkan annotator dijalankan diwaktu compile-time.

Karena annotation dijalankan disaat compile-time, annotation tidaklah se-powerful dekorator, annotation hanya bisa digunakan untuk medapatkan metadata. Sedangkan dekorator bisa merubah behavior dari target method atau property secara langsung. Walaupun begitu, annotation bisa dikombinasikan dengan framework yang memberikan fungsionalitas yang sama dengan dekorator. Contoh penggunaan annotation dengan framework adalah Spring Boot.

Support dari Bahasa Pemrograman

Pada dasarnya dekorator pattern bisa dipakai di semua bahasa pemrograman, walau tanpa syntaktik sugar. Fungsi log di atas diimplementasikan di bahasa pemrograman TypeScript. Sebenarnya fungsi log diatas bisa diimplementasikan dengan vanilla javascript seperti berikut:

Syntaktik sugar yang diberikan oleh bahasa pemrograman bevariasi. Biasanya dalam bentuk @ notation atau [] notation seperti di bahasa C#.

Referensi untuk implementasi dekorator / annotator diberbagai bahasa pemrograman:

Penggunaan di Framework-Framework Populer

Dekorator / Annotation digunakan di framework2 populer:

  • Spring Boot
    Java framework ini salah satu pelopor menggunaan Annotation untuk mengurangi konfigurasi & boilerplate. Annotation digunakan untuk dependency injection, routing dll.
  • Unity Container
    Unity Container adalah sebuah dependency injection framework untuk .NET dan C# yang menggunakan konsep annotation untuk deklarasi dependency.
  • Nest
    Nest adalah sebuah framework MVC untuk Typescript / Node.js environment. Framework ini menggunakan kapabilitas dekorator dari Typescript untuk mendeklarasikan Controllers, Router dll.
  • MobX
    MobX adalah sebuah library untuk state management di React. Library ini banyak menggunakan dekorator untuk mendeklarasikan behavior dan states.
  • Angular
    Angular adalah sebuah front-end framework berbasis Typescript yang banyak menggunakan dekorator untuk deklarasi component dan binding.
  • Flask
    Flask adalah sebuah web-framework berbasis python, dimana framework ini banyak menggunakan dekorator untuk definisi routing dll.

Contoh-Contoh Penggunaan

Di sini saya akan membahas use-case dari penggunaan dekorator selain yang sudah ditampilkan di atas.

Definisi Routing

Mungkin pembaca familiar dengan express.js dengan syntaxnya untuk mendefinisikan routing:

app.get("/users/:id", function(req, res) {})

Definisi itu bisa diubah dengan dekorator menjadi seperti berikut:

@Controller({path: "/users"})
class UserController {
@Get("/:id")
getUserById(@Param() id: string, req: HttpRequest,
res: HttpResult) {
// do something
}
}

Dengan dekorator, semua route yang berhubungan dengan User bisa dikumpulkan menjadi satu kelas controller sehingga code bisa terlihat lebih terstruktur.

Akses Kontrol

Dekorator juga bisa digunakan untuk mengatur akses seperti contoh berikut.

class UserController {
@Access({roles: ["admin", "user"]})
@Get("/users/:id")

getUserById(@Param() id: string, req: HttpRequest,
res: HttpResult) {
// do something
}
}

Contoh di atas, akses ke route /users/:id hanya bisa dilakukan oleh yang mempunyai role admin atau user.

Definisi ORM

Hal yang cukup sering digunakan oleh ORM Framework adalah penggunaan dekorator untuk mapping antara table fields dengan data object.

@table("user")
class User {
@field("first_name")
public firstName: string;
@field("last_name")
public lastName: string;
@field("email")
public email: string;
}

Validasi Data

Dekorator bisa digunakan untuk memvalidasi data sebelum disimpan. Contoh dibawah ini dekorator digunakan untuk memvalidasi email. Sang dekorator akan merubah property email menjadi sebuah getter / setter yang akan memvalidasi input saat assignment.

class User {
@validate(/[^@]+@[^\.]+\..+/g)
public email: string;

Data Binding

Contoh lain dalam penggunaan dekorator adalah untuk membuat data binding di frontend framework seperti vue, angular dan lain-lain. Di contoh di bawah, sebuah class diberi property yang dideklarasikan sebagai bindable. Value yang bindable ini akan otomatis bisa untuk disambungkan ke property value di sebuah input, sehingga kalau ada perubahan value pada name ataupun di input element, data tersebut automatis tersinkronkan.

class User {
@bindable
public name: string;
}
var user = new User();<input bind:value="{user.name}" type="text" />user.name = "Rizqi" // input will change

Berikutnya

Banyak sekali contoh-contoh penggunaan, dan list di atas tidaklah exhaustif sehingga mungkin pembaca menemukan contoh-contoh lain yang menarik dalam penggunaan dekorator. Edisi selanjutnya saya akan menulis seri “Practice” dimana saya akan mengimplementasikan sebuah library / framework kecil dengan menggunakan design pattern ini.

P.S. Jika teman-teman menyukai artikel semacam ini, silakan subscribe ke newsletter kita dan dapatkan notifikasi artikel terbaru langsung di inbox kamu!

--

--