Menu
Coddy logo textTech

Wprowadzenie do wzorców projektowych

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

Wzorce projektowe to wielokrotnego użytku rozwiązania typowych problemów pojawiających się podczas projektowania oprogramowania. Nie są to fragmenty kodu, które kopiujesz bezpośrednio, lecz szablony wskazujące, jak strukturyzować typy i ich interakcje, aby rozwiązywać konkretne wyzwania.

Wzorce projektowe są zazwyczaj podzielone na trzy kategorie:

KategoriaCelPrzykłady
KreacyjneMechanizmy tworzenia obiektówSingleton, Factory, Builder
StrukturalneŁączenie typów w większe strukturyAdapter, Decorator, Composite
BehawioralneKomunikacja między obiektamiObserver, Strategy, Command

W Go wzorce projektowe wyglądają inaczej niż w tradycyjnych językach programowania obiektowego.

Bez klas i dziedziczenia Go implementuje wzorce za pomocą interfejsów, osadzania struktur i kompozycji. Na przykład tam, gdzie Java mogłaby użyć klasy abstrakcyjnej, Go używa interfejsu. Tam, gdzie C++ mogłoby użyć dziedziczenia, Go używa osadzania.

Znajomość wzorców pomaga rozpoznawać typowe problemy i skutecznie komunikować rozwiązania innym programistom. Gdy ktoś wspomina „użyj tutaj wzorca Strategia”, cały zespół rozumie to podejście bez długich wyjaśnień.

W kolejnych lekcjach zaimplementujesz kilka podstawowych wzorców w Go, zaczynając od wzorców kreacyjnych, takich jak Singleton i Factory, a następnie przechodząc do wzorców behawioralnych, takich jak Observer i Strategy.

challenge icon

Wyzwanie

Łatwy

Zbudujemy prosty system powiadomień, który pokaże, jak wzorce projektowe pomagają porządkować kod! Utworzysz strukturę, którą w przyszłych lekcjach można łatwo rozszerzyć o wzorce takie jak Observer czy Strategy, ale na razie skup się na przygotowaniu przejrzystych interfejsów i typów zgodnych z dobrymi zasadami OOP.

Podzielisz kod na trzy pliki:

  • notifier.go: Zdefiniuj podstawowy interfejs i typy dla systemu powiadomień.

    Utwórz interfejs Notifier z jedną metodą Send(message string) string, która zwraca wiadomość z potwierdzeniem.

    Zaimplementuj dwa konkretne typy powiadomień:

    • EmailNotifier z polem Address. Jego metoda Send zwraca Email to [address]: [message]
    • SMSNotifier z polem PhoneNumber. Jego metoda Send zwraca SMS to [phone]: [message]
  • dispatcher.go: Utwórz dyspozytor, który obsługuje dowolne powiadomienia za pośrednictwem interfejsu.

    Utwórz strukturę NotificationDispatcher, która przechowuje wycinek interfejsów Notifier. Dodaj następujące metody:

    • AddNotifier(n Notifier) do rejestrowania powiadomienia
    • Broadcast(message string) []string, która wysyła wiadomość za pośrednictwem wszystkich zarejestrowanych powiadomień i zwraca wycinek wszystkich wiadomości z potwierdzeniem

    Utwórz również konstruktor NewNotificationDispatcher(), który zwraca zainicjalizowany dyspozytor.

  • main.go: Skonfiguruj powiadomienia i rozsyłaj wiadomości.

    Odczytaj liczbę powiadomień do utworzenia. Dla każdego powiadomienia odczytaj jego typ (email lub sms) oraz miejsce docelowe (adres lub numer telefonu). Dodaj każde z nich do dyspozytora.

    Następnie odczytaj wiadomość do rozesłania. Wyślij ją za pośrednictwem wszystkich powiadomień i wypisz każde potwierdzenie w osobnym wierszu.

Dane wejściowe będą miały następujący format:

  • Wiersz 1: Liczba powiadomień
  • Dla każdego powiadomienia: typ (email lub sms), a następnie miejsce docelowe
  • Ostatni wiersz: Wiadomość do rozesłania

Na przykład dla danych:

3
email
alice@example.com
sms
555-1234
email
bob@example.com
Server maintenance at midnight

Oczekiwany wynik:

Email to alice@example.com: Server maintenance at midnight
SMS to 555-1234: Server maintenance at midnight
Email to bob@example.com: Server maintenance at midnight

A dla danych:

2
sms
555-9999
sms
555-0000
Meeting canceled

Oczekiwany wynik:

SMS to 555-9999: Meeting canceled
SMS to 555-0000: Meeting canceled

Ta struktura pokazuje, jak interfejsy umożliwiają tworzenie elastycznych i rozszerzalnych rozwiązań. Dyspozytor nie zna konkretnych typów powiadomień. Wie tylko, że mogą one wywołać Send. To podstawa, na której opierają się wzorce takie jak Observer i Strategy!

Spróbuj swoich sił

package main

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

func main() {
	reader := bufio.NewReader(os.Stdin)

	// Odczytaj liczbę obiektów powiadamiających
	countStr, _ := reader.ReadString('\n')
	count, _ := strconv.Atoi(strings.TrimSpace(countStr))

	// Utwórz nowy dyspozytor
	dispatcher := NewNotificationDispatcher()

	// Odczytaj każdy obiekt powiadamiający i dodaj go do dyspozytora
	for i := 0; i < count; i++ {
		notifierType, _ := reader.ReadString('\n')
		notifierType = strings.TrimSpace(notifierType)

		destination, _ := reader.ReadString('\n')
		destination = strings.TrimSpace(destination)

		// TODO: Utwórz odpowiedni obiekt powiadamiający na podstawie typu
		// i dodaj go do dyspozytora
		// Wskazówka: Sprawdź, czy notifierType to "email" czy "sms"

	}

	// Odczytaj wiadomość do rozesłania
	message, _ := reader.ReadString('\n')
	message = strings.TrimSpace(message)

	// TODO: Roześlij wiadomość i wypisz każde potwierdzenie

}
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