Bersolek Ria dengan Decorator Pattern
Tags: indonesia, designpatterns, go
Published: 2023-07-01 08:31:29

Artikel Ini adalah lanjutan pembahasan implementasi _design-pattern_ yang sebelumnya dibahas pada _[lebih dekat dengan visitor-pattern](https://dev.to/mhakimamransyah/lebih-dekat-dengan-visitor-pattern-2747)_. Domain permasalah dan _sources code_ yang digunakan merupakan lanjutan dari pembahasan sebelumnya.

## Prolog
Pada saat _daily standup_ kemarin anda mendapatkan arahan dari atasan anda untuk melakukan _enhance_ pada fitur pengiriman notifikasi peringatan yang telah dibuat. Sebelumnya anda hanya menggunakan fungsi sederhana untuk mengirimkan notifikasi peringatan ke seluruh level pegawai. Atasan anda meminta agar _sources code_ yang ada mampu mengakomodasi untuk mengirimkan notifikasi menggunakan beberapa media yang berbeda-beda. Adapun ketentuan yang diminta oleh atasan anda adalah;
- Seluruh level pegawai akan menerima notifikasi melalui _push notification_ pada aplikasi _mobile_ perusahaan.
- Selain _push notification_, **supervisor** dapat menerima notifikasi melalui email.
- Selain _push notification_, **manajer** dapat menerima notifikasi melalui email & pesan _whatsapp_.

Secara umum saat ini aplikasi anda memiliki relasi kelas sebagai berikut; 

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/580jhan8l8ltqob4qelg.png)

Tanggung jawab pengiriman notifikasi peringatan saat ini diemban oleh objek _PerformanceWarningVisitor_ yang merupakan implementasi dari _visitor-pattern_ (dijelaskan pada _[lebih dekat dengan visitor-pattern](https://dev.to/mhakimamransyah/lebih-dekat-dengan-visitor-pattern-2747)_ ).

## Mendekor ulang objek
Anda tahu bahwa saat ini notifikasi peringatan hanya dikirimkan melalui _push notifications_. Sesuai dengan ketentuan yang diberikan, anda harus menambahkan media notifikasi lainnya tanpa menghapus atau menghilangkan _default_ notifikasi yang saat ini digunakan.

Anda sadar bahwa membuat objek yang berdiri sendiri bukanlah ide yang bagus karena (sekali lagi) setiap jenis notifikasi akan berakumulasi dengan jenis notifikasi lain. Sederhananya ketentuan tersebut dapat dijelaskan seperti berikut

**Staf**       -> _Push Notification_
**Supervisor** -> _Push Notification_ | Email
**Manajer** -> _Push Notification_ | Email | _WhatsApp Number_

## Decorator Pattern
Setelah gugling dan bertapa cukup lama, anda akhirnya memutuskan untuk menggunakan _decorator-pattern_ untuk menangani kasus ini. Anda akan membuat sebuah _decorator_ yang akan mendekorasi ulang fungsi _push-notifications_ sehingga memiliki fungsi notifikasi dengan media yang berbeda-beda.

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/1oddvs6z0agoks7x3mzr.png)

Anda membuat sebuah kelas _factory_ yang bertugas untuk meng-_assemble_ berbagai macam _decorator_ sesuai dengan level pegawai yang ada. Singkatnya implementasi kelas tersebut adalah sebagai berikut;

**notification_factory.go**
```
type NotificatorContract interface {
	StaffNotifier() entity.Notifier
	SupervisorNotifier() entity.Notifier
	ManagerNotifier() entity.Notifier
}

type Notificator struct{}

func (notifier *Notificator) StaffNotifier() entity.Notifier {
	return decorator.NewPushNotificationDecorator()
}

func (notifier *Notificator) SupervisorNotifier() entity.Notifier {
	pushNotification := decorator.NewPushNotificationDecorator()
	emailNotification := decorator.NewEmailDecorator(pushNotification)
	return emailNotification
}

func (notifier *Notificator) ManagerNotifier() entity.Notifier {
	pushNotification := decorator.NewPushNotificationDecorator()
	emailNotification := decorator.NewEmailDecorator(pushNotification)
	whatsAppNotification := decorator.NewWhatsAppDecorator(emailNotification)
	return whatsAppNotification
}

func NewNotificator() *Notificator {
	return &Notificator{}
}
```
_Factory_ tersebut nantinya akan dimanfaatkan oleh objek _PerformanceWarningVisitor_.

**performance_warning_visitor.go**

```
type PerformanceWarningVisitor struct {
	Notif factory.NotificatorContract
}

func (visitor PerformanceWarningVisitor) VisitStaff(staff *entities.Staff) (interface{}, error) {

	var warningType string

	notification := visitor.Notif.StaffNotifier()

	if staff.PerformancePercentage < 30 {
		warningType = STERN_WARNING
	}

	if staff.PerformancePercentage >= 30 && staff.PerformancePercentage < 67 {
		warningType = WARNING
	}

	notification.SendMessage(
		staff,
		fmt.Sprintf("Notification %s send to staff : %s \n", warningType, staff.Name),
	)

	return warningType, nil
}

func (visitor PerformanceWarningVisitor) VisitSupervisor(spv *entities.Supervisor) (interface{}, error) {

	var warningType string

	durationInYear := (time.Now()).Sub(spv.JoinDate).Hours() / 8760
	notification := visitor.Notif.SupervisorNotifier()

	if spv.PerformancePercentage < 30 {
		warningType = STERN_WARNING
	}

	if durationInYear >= 10 && (spv.PerformancePercentage >= 30 && spv.PerformancePercentage < 60) {
		warningType = WARNING
	}

	if durationInYear < 10 && (spv.PerformancePercentage >= 30 && spv.PerformancePercentage < 70) {
		warningType = WARNING
	}

	notification.SendMessage(
		spv,
		fmt.Sprintf("Notification %s send to supervisor : %s \n", warningType, spv.Name),
	)

	return warningType, nil
}

func (visitor PerformanceWarningVisitor) VisitManager(manager *entities.Manager) (interface{}, error) {

	var warningType string

	Age := (time.Now()).Sub(manager.BirthDate).Hours() / 8760
	notification := visitor.Notif.ManagerNotifier()

	if manager.PerformancePercentage < 40 {
		warningType = STERN_WARNING
	}

	if Age >= 40 && (manager.PerformancePercentage >= 40 && manager.PerformancePercentage < 60) {
		warningType = WARNING
	}

	if Age < 40 && (manager.PerformancePercentage >= 40 && manager.PerformancePercentage < 70) {
		warningType = WARNING
	}

	notification.SendMessage(
		manager,
		fmt.Sprintf("Notification %s send to manager : %s \n", warningType, manager.Name),
	)

	return warningType, nil
}
```

## Epilog
Seluruh sources code yang berkaitan dengan artikel ini dapat dilihat pada repository berikut https://github.com/Mhakimamransyah/practice-design-pattern

**Referensi Bacaan**
https://refactoring.guru/design-patterns/decorator
https://www.youtube.com/watch?v=metYIcjQLls

**Author**
https://github.com/Mhakimamransyah
https://www.linkedin.com/in/hakim-amr/
mailto: m.hakim.amransyah.hakim@gmail.com