Menu
Coddy logo textTech

Wzorzec Strategy

Część sekcji Programowanie obiektowe ścieżki GO w Coddy. Lekcja 90 z 107.

Wzorzec strategii pozwala zdefiniować rodzinę algorytmów, enkapsulować każdy z nich i umożliwić ich wzajemną wymienność w trakcie działania programu. W przeciwieństwie do wzorca Observer, w którym wiele obiektów reaguje na jedno zdarzenie, wzorzec Strategy pozwala pojedynczemu obiektowi dynamicznie przełączać się między różnymi zachowaniami.

W Go implementujemy wzorzec Strategy, definiując interfejs dla algorytmu i wstrzykując różne implementacje do struktury kontekstu:

type PaymentStrategy interface {
    Pay(amount float64) string
}

type CreditCard struct{}
func (c CreditCard) Pay(amount float64) string {
    return fmt.Sprintf("Paid %.2f via Credit Card", amount)
}

type PayPal struct{}
func (p PayPal) Pay(amount float64) string {
    return fmt.Sprintf("Paid %.2f via PayPal", amount)
}

Struktura kontekstu przechowuje odwołanie do interfejsu strategii, dzięki czemu można zmienić algorytm bez modyfikowania kodu kontekstu:

type Checkout struct {
    strategy PaymentStrategy
}

func (c *Checkout) SetStrategy(s PaymentStrategy) {
    c.strategy = s
}

func (c *Checkout) ProcessPayment(amount float64) string {
    return c.strategy.Pay(amount)
}

Teraz możesz zmienić metodę płatności w czasie działania programu:

checkout := &Checkout{}

checkout.SetStrategy(CreditCard{})
fmt.Println(checkout.ProcessPayment(100.00))  // Zapłacono 100.00 kartą kredytową

checkout.SetStrategy(PayPal{})
fmt.Println(checkout.ProcessPayment(50.00))   // Zapłacono 50.00 przez PayPal

Wzorzec strategii sprawdza się idealnie, gdy masz kilka sposobów wykonania operacji i musisz wybrać jeden na podstawie danych wejściowych użytkownika, konfiguracji lub warunków w czasie działania. Typowe zastosowania obejmują algorytmy sortowania, metody kompresji i reguły walidacji.

challenge icon

Wyzwanie

Łatwy

Zbudujmy system formatowania tekstu, używając wzorca Strategia! Utworzysz różne strategie formatowania, które można zamieniać w czasie działania programu, dzięki czemu ten sam procesor tekstu będzie generować różne style wyjściowe bez zmiany jego podstawowego kodu.

Rozmieścisz kod w trzech plikach:

  • formatter.go: Zdefiniuj interfejs strategii i konkretne strategie formatowania.

    Utwórz interfejs TextFormatter z metodą Format(text string) string, która przekształca tekst zgodnie z regułami strategii.

    Zaimplementuj trzy strategie formatowania:

    • UppercaseFormatter: zamienia cały tekst na wielkie litery
    • SnakeCaseFormatter: zamienia spacje na podkreślenia i zapisuje tekst małymi literami
    • TitleFormatter: zamienia pierwszą literę każdego słowa na wielką (słowa są oddzielone spacjami)
  • processor.go: Utwórz strukturę kontekstu, która używa strategii formatowania.

    Utwórz strukturę TextProcessor, która przechowuje strategię TextFormatter. Dodaj następujące metody:

    • SetFormatter(f TextFormatter), aby zmieniać aktywną strategię formatowania
    • Process(text string) string, która stosuje bieżący formater do tekstu

    Utwórz także konstruktor NewTextProcessor(), który zwraca procesor bez ustawionego początkowego formatera.

  • main.go: Pokaż, jak zamieniać strategie w czasie działania programu.

    Wczytaj tekst, a następnie liczbę operacji formatowania. Dla każdej operacji wczytaj typ formatowania (upper, snake lub title), ustaw odpowiedni formater w procesorze, przetwórz oryginalny tekst i wypisz wynik.

Podane zostaną następujące dane wejściowe:

  • Wiersz 1: tekst do sformatowania
  • Wiersz 2: liczba operacji formatowania
  • Kolejne wiersze: typ formatowania dla każdej operacji

Na przykład, dla danych:

hello world today
3
upper
snake
title

Wynik powinien być następujący:

HELLO WORLD TODAY
hello_world_today
Hello World Today

A dla danych:

Go Programming Language
2
snake
upper

Wynik powinien być następujący:

go_programming_language
GO PROGRAMMING LANGUAGE

A dla danych:

design patterns are useful
1
title

Wynik powinien być następujący:

Design Patterns Are Useful

Zwróć uwagę, że ten sam TextProcessor generuje zupełnie różne wyniki tylko dzięki zmianie strategii formatera. Procesor nie wie ani nie musi wiedzieć, którego konkretnego formatera używa. Po prostu deleguje działanie do aktualnie ustawionej strategii!

Spróbuj swoich sił

package main

import (
	"bufio"
	"fmt"
	"os"
	"strconv"
	"strings"
)

func main() {
	reader := bufio.NewReader(os.Stdin)
	
	// Wczytaj tekst do sformatowania
	text, _ := reader.ReadString('\n')
	text = strings.TrimSpace(text)
	
	// Wczytaj liczbę operacji
	countStr, _ := reader.ReadString('\n')
	count, _ := strconv.Atoi(strings.TrimSpace(countStr))
	
	// Utwórz nowy procesor tekstu
	processor := NewTextProcessor()
	
	// Wykonaj każdą operację formatowania
	for i := 0; i < count; i++ {
		formatType, _ := reader.ReadString('\n')
		formatType = strings.TrimSpace(formatType)
		
		// TODO: Na podstawie formatType ("upper", "snake" lub "title"),
		// ustaw odpowiedni formater w procesorze
		// i wypisz przetworzony tekst
		
	}
}
quiz iconSprawdź się

Ta lekcja zawiera krótki quiz. Zacznij lekcję, żeby na niego odpowiedzieć i śledzić swoje postępy.

Wszystkie lekcje w sekcji Programowanie obiektowe

Poćwicz samodzielnie: Kompilator Go online