Artikel Ini adalah lanjutan pembahasan implementasi design-pattern yang sebelumnya dibahas pada lebih dekat dengan visitor-pattern. 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;
Tanggung jawab pengiriman notifikasi peringatan saat ini diemban oleh objek PerformanceWarningVisitor yang merupakan implementasi dari visitor-pattern (dijelaskan pada lebih dekat dengan visitor-pattern ).
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.
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
Top comments (0)