Durum Kalıbı
Coddy'nin GO Journey'sinin Nesne Yönelimli Programlama bölümünün bir parçası — ders 95 / 107.
State deseni, bir nesnenin iç durumu değiştiğinde davranışını değiştirmesine olanak tanır ve nesnenin sınıfı değişmiş gibi görünmesini sağlar. Template Method algoritma adımlarını kontrol ederken, State duruma özgü davranışı ayrı nesnelere kapsüller ve mevcut duruma devreder.
Go'da, bir durum (state) arayüzü tanımlarız ve farklı davranışları uygulayan somut durumlar oluştururuz:
type State interface {
Handle(d *Document) string
}
type Document struct {
state State
}
func (d *Document) SetState(s State) {
d.state = s
}
func (d *Document) Publish() string {
return d.state.Handle(d)
}Her bir durum ne olacağını ve hangi durumun geleceğini belirler:
type DraftState struct{}
func (s DraftState) Handle(d *Document) string {
d.SetState(ModerationState{})
return "Draft submitted for moderation"
}
type ModerationState struct{}
func (s ModerationState) Handle(d *Document) string {
d.SetState(PublishedState{})
return "Moderation approved, now published"
}
type PublishedState struct{}
func (s PublishedState) Handle(d *Document) string {
return "Already published"
}Aynı metot çağrısı, mevcut duruma bağlı olarak farklı sonuçlar üretir:
doc := &Document{state: DraftState{}}
fmt.Println(doc.Publish()) // Taslak moderasyon için gönderildi
fmt.Println(doc.Publish()) // Moderasyon onaylandı, şimdi yayınlandı
fmt.Println(doc.Publish()) // Zaten yayınlanmışState, sipariş işleme iş akışları, kullanıcı arayüzü (UI) bileşenleri veya davranışın tamamen mevcut duruma bağlı olduğu bağlantı işleyicileri gibi farklı çalışma modlarına sahip nesneler için idealdir.
Görev
KolayState desenini kullanarak bir bilet destek sistemi oluşturalım! Açılmasından üzerinde çalışılmasına ve çözülmesine kadar farklı aşamalardan geçen bir destek bileti oluşturacaksınız; her bir durum hangi eylemlerin mümkün olduğunu ve bir sonraki adımda ne olacağını belirleyecek.
Kodunuzu üç dosya halinde düzenleyeceksiniz:
state.go: Durum arayüzünüzü (interface) ve bir biletin yaşam döngüsünün her aşamasını temsil eden somut durumları tanımlayın.Bileti işleyen ve potansiyel olarak bir sonraki duruma geçiren
Handle(t *Ticket) stringmetoduna sahip birTicketStatearayüzü oluşturun.Üç durum uygulayın:
OpenState— işlendiğinde, biletiInProgressStatedurumuna geçirir veTicket opened, assigning to support teamdeğerini döndürürInProgressState— işlendiğinde,ResolvedStatedurumuna geçer veWorking on ticket, issue resolveddeğerini döndürürResolvedState— işlendiğinde, aynı durumda kalır veTicket already resolveddeğerini döndürür
ticket.go: Mevcut durumu tutan ve davranışı ona devreden bilet yapınızı (struct) oluşturun.Bir
IDalanına (string) ve birstatealanına (TicketState) sahip birTicketyapısı oluşturun. Şu metodları ekleyin:- Biletin mevcut durumunu değiştirmek için
SetState(s TicketState) - Mevcut durumun Handle metoduna yetki devreden
Process() string
OpenStatedurumunda başlayan bir bilet döndüren birNewTicket(id string) *Ticketyapıcı fonksiyonu (constructor) oluşturun.- Biletin mevcut durumunu değiştirmek için
main.go: Aynı eylemin, biletin mevcut durumuna bağlı olarak nasıl farklı sonuçlar ürettiğini gösterin.Bir bilet ID'si ve biletin kaç kez işleneceğini okuyun. Bu ID ile yeni bir bilet oluşturun, ardından
Process()metodunu belirtilen sayıda çağırarak her sonucu ayrı bir satıra yazdırın.
Aşağıdaki girdiler sağlanacaktır:
- Satır 1: Bilet ID'si
- Satır 2: Biletin işlenme sayısı
Örneğin, şu girdi verildiğinde:
TKT-001
3Çıktınız şu olmalıdır:
Ticket opened, assigning to support team
Working on ticket, issue resolved
Ticket already resolvedVe şu girdi verildiğinde:
TKT-500
5Çıktınız şu olmalıdır:
Ticket opened, assigning to support team
Working on ticket, issue resolved
Ticket already resolved
Ticket already resolved
Ticket already resolvedVe şu girdi verildiğinde:
ISSUE-42
1Çıktınız şu olmalıdır:
Ticket opened, assigning to support teamAynı bilet üzerinde Process() çağırmanın her seferinde nasıl farklı sonuçlar ürettiğine dikkat edin; biletin davranışı durumlar arasında ilerledikçe değişir. Bir kez çözüldüğünde, kaç kez işlerseniz işleyin çözülmüş olarak kalır. Bilet nesnesi davranışını değiştiriyor gibi görünür, ancak aslında işi farklı durum nesnelerine devreder!
Kopya kağıdı
State (Durum) deseni, bir nesnenin iç durumu değiştiğinde davranışını değiştirmesine olanak tanır. Nesne, davranışı farklı durumları temsil eden ayrı durum nesnelerine devreder.
Bir durum (state) arayüzü tanımlayın:
type State interface {
Handle(d *Document) string
}Mevcut durumu tutan bir bağlam (context) nesnesi oluşturun:
type Document struct {
state State
}
func (d *Document) SetState(s State) {
d.state = s
}
func (d *Document) Publish() string {
return d.state.Handle(d)
}Duruma özgü davranışı kapsülleyen somut durumları uygulayın:
type DraftState struct{}
func (s DraftState) Handle(d *Document) string {
d.SetState(ModerationState{})
return "Draft submitted for moderation"
}
type ModerationState struct{}
func (s ModerationState) Handle(d *Document) string {
d.SetState(PublishedState{})
return "Moderation approved, now published"
}
type PublishedState struct{}
func (s PublishedState) Handle(d *Document) string {
return "Already published"
}Her durum ne olacağını belirler ve bir sonraki duruma geçiş yapar:
doc := &Document{state: DraftState{}}
fmt.Println(doc.Publish()) // Draft submitted for moderation
fmt.Println(doc.Publish()) // Moderation approved, now published
fmt.Println(doc.Publish()) // Already publishedState deseni, davranışın tamamen mevcut duruma bağlı olduğu farklı çalışma modlarına sahip nesneler için idealdir.
Kendin dene
package main
import (
"fmt"
)
func main() {
// Girişi oku
var ticketID string
var numProcesses int
fmt.Scanln(&ticketID)
fmt.Scanln(&numProcesses)
// TODO: Verilen ID ile yeni bir bilet oluşturun
// TODO: Bileti belirtilen sayıda işleyin
// ve her sonucu ayrı bir satıra yazdırın
}
Bu ders kısa bir quiz içerir. Soruları yanıtlamak ve ilerlemeni kaydetmek için derse başla.
Nesne Yönelimli Programlama bölümündeki tüm dersler
1Go OOP Temelleri
Harici DosyalarGo Çalışma Alanı ve ModüllerPaketler ve İçe AktarmalarDışa Aktarılan ve Aktarılmayan İsimlerGo'da OOP'ye GirişSınıf Olarak Struct'larStruct'larda Metot TanımlamaPointer ve Değer AlıcılarStruct BaşlatmaYapıcı FonksiyonlarÖzet - Basit Hesap Makinesi4Arayüzler
Arayüzlere GirişÖrtük UygulamaSözleşme Olarak ArayüzBoş Arayüz (any)Tür OnaylamaTür SeçimiArayüz BileşimiStringer ve Error ArayüzleriÖzet - Şekil Hesaplayıcı7Kapsülleme
Dışa Aktarılan ve Aktarılmayan AlanlarPaket Seviyesinde KapsüllemeGetter ve Setter MetotlarıGo'da Bilgi GizlemeÖzet - Öğrenci Kayıtları10Generics (Go 1.18+)
Generics'e GirişTür ParametreleriTür KısıtlamalarıGeneric Struct'larGeneric Metotlar İçin Geçici ÇözümÖzet - Generic Koleksiyon13Tasarım Kalıpları Bölüm 1
Tasarım Kalıplarına GirişSingleton KalıbıFactory KalıbıAbstract Factory KalıbıObserver KalıbıStrategy Kalıbı2Türler ve Struct'lar: Derinlemesine İnceleme
Temel ve Bileşik TürlerÖzel Tür TanımlamalarıStruct EtiketleriAnonim Struct'larİç İçe Geçmiş Struct'larSıfır Değerler ve VarsayılanlarÖzet - Rehber5Kalıtım Yerine Kompozisyon
Go'da Neden Kalıtım YokStruct Gömme TemelleriMetot YükseltmeBirden Fazla Struct GömmeGömme vs AgregasyonGömülü Metotları GölgelemeÖzet - Çalışan Hiyerarşisi8Hata Yönetimi ve OOP
error ArayüzüÖzel Hata TürleriHata Sarmalama (fmt.Errorf)Sentinel Hatalarerrors.Is() ve errors.As()Panic, Defer ve RecoverÖzet - Dosya Ayrıştırıcı11Standart Kütüphane ve OOP
io.Reader ve io.Writersort.Interface Arayüzüfmt.Stringer ArayüzüStruct'lar ile encoding/jsonhttp.Handler ArayüzüÖzet - REST API Modelleri14Tasarım Kalıpları Bölüm 2
Komut KalıbıAdaptör KalıbıDekoratör KalıbıŞablon Metot KalıbıDurum KalıbıKompozit KalıbıDekoratör olarak Middleware3İşaretçiler ve Bellek
Go'da İşaretçi TemelleriStruct İşaretçileriDeğer ile Geçme ve Referans ile Geçmenew() FonksiyonuGo'da Garbage CollectionÖzet - Linked List Oluşturucu6Go'da Polimorfizm
Interface'ler ile PolimorfizmGo'da Duck TypingInterface Karşılama KurallarıPolimorfik KoleksiyonlarDependency InjectionÖzet - Payment Processor9Eşzamanlılık ve OOP
Goroutine TemelleriKanallar ve İletişimTamponlu ve Tamponsuz KanallarSelect İfadesisync.Mutex ve sync.RWMutexsync.WaitGroupThread-Safe Struct TasarımıÖzet - Worker Pool