Menu
Coddy logo textTech

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.

challenge icon

Görev

Kolay

State 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) string metoduna sahip bir TicketState arayüzü oluşturun.

    Üç durum uygulayın:

    • OpenState — işlendiğinde, bileti InProgressState durumuna geçirir ve Ticket opened, assigning to support team değerini döndürür
    • InProgressState — işlendiğinde, ResolvedState durumuna geçer ve Working on ticket, issue resolved değerini döndürür
    • ResolvedState — işlendiğinde, aynı durumda kalır ve Ticket already resolved değerini döndürür
  • ticket.go: Mevcut durumu tutan ve davranışı ona devreden bilet yapınızı (struct) oluşturun.

    Bir ID alanına (string) ve bir state alanına (TicketState) sahip bir Ticket yapı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

    OpenState durumunda başlayan bir bilet döndüren bir NewTicket(id string) *Ticket yapıcı fonksiyonu (constructor) oluşturun.

  • 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 resolved

Ve ş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 resolved

Ve şu girdi verildiğinde:

ISSUE-42
1

Çıktınız şu olmalıdır:

Ticket opened, assigning to support team

Aynı 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 published

State 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
}
quiz iconKendini test et

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