Metody pobierające i ustawiające
Część sekcji Programowanie obiektowe ścieżki GO w Coddy. Lekcja 49 z 107.
Ponieważ pola nieeksportowane nie mogą być bezpośrednio używane spoza pakietu, musisz udostępnić metody umożliwiające kontrolowany dostęp. Są one powszechnie nazywane metodami pobierającymi i metodami ustawiającymi.
W Go konwencja dotycząca getterów jest prosta: używaj nazwy pola z wielką pierwszą literą. Nie dodawaj prefiksu „Get”, po prostu użyj Balance(), a nie GetBalance():
type BankAccount struct {
balance int // nieeksportowane
}
// Getter - zwraca wartość
func (b *BankAccount) Balance() int {
return b.balance
}
// Setter - modyfikuje wartość po sprawdzeniu jej poprawności
func (b *BankAccount) SetBalance(amount int) {
if amount >= 0 {
b.balance = amount
}
}
Prawdziwa moc metod ustawiających polega na dodawaniu walidacji lub logiki biznesowej. Zamiast pozwalać zewnętrznemu kodowi ustawiać dowolną wartość bezpośrednio, kontrolujesz, co jest dozwolone:
func (b *BankAccount) Deposit(amount int) bool {
if amount <= 0 {
return false
}
b.balance += amount
return true
}
Ta metoda Deposit działa jak wyspecjalizowany setter, który wymusza zasady: wpłaty nie mogą być ujemne. Kod zewnętrzny musi korzystać z Twoich metod, co zapewnia, że struktura zawsze pozostaje w prawidłowym stanie. Tak działa enkapsulacja: ukrywanie danych przy jednoczesnym udostępnianiu kontrolowanego zachowania.
Wyzwanie
ŁatwyZbudujmy konwerter temperatury, który pokazuje prawidłowe hermetyzowanie za pomocą metod pobierających i ustawiających. Utworzysz strukturę przechowującą temperaturę wewnętrznie w stopniach Celsjusza, ale udostępniającą kontrolowany dostęp za pomocą metod z walidacją.
Rozmieścisz kod w dwóch plikach:
temperature.go: Utwórz strukturęTemperaturez nieeksportowanym polemcelsius(float64). Zaimplementuj następujące metody:Celsius()- getter zwracający aktualną temperaturę w stopniach CelsjuszaSetCelsius(value float64)- setter, który akceptuje tylko wartości równe zeru absolutnemu (-273.15) lub wyższe. Jeśli wartość jest niższa od tego progu, temperatura powinna pozostać bez zmian.Fahrenheit()- zwraca temperaturę przeliczoną na stopnie Fahrenheita za pomocą wzoru:(celsius * 9/5) + 32SetFahrenheit(value float64)- przelicza wartość wejściową ze stopni Fahrenheita na Celsjusza i zapisuje ją, ale tylko wtedy, gdy wynikowa wartość w stopniach Celsjusza jest równa -273.15 lub wyższa
NewTemperature(celsius float64) *Temperature, który tworzy temperaturę z podaną wartością początkową (załóż, że konstruktor otrzymuje prawidłowe dane wejściowe).main.go: Odczytaj wartości temperatury z danych wejściowych i pokaż działanie metod pobierających i ustawiających. Utwórz temperaturę, wyświetl jej wartości w obu jednostkach, a następnie spróbuj ustawić nowe wartości i pokaż wyniki.
Podane zostaną następujące dane wejściowe:
- Wiersz 1: Początkowa wartość w stopniach Celsjusza
- Wiersz 2: Nowa wartość w stopniach Celsjusza do ustawienia
- Wiersz 3: Nowa wartość w stopniach Fahrenheita do ustawienia
Formatuj wszystkie wyświetlane temperatury z dokładnością do dwóch miejsc po przecinku. Wypisz następującą sekwencję:
- Po utworzeniu:
C: [celsius] F: [fahrenheit] - Po ustawieniu temperatury w stopniach Celsjusza:
C: [celsius] F: [fahrenheit] - Po ustawieniu temperatury w stopniach Fahrenheita:
C: [celsius] F: [fahrenheit]
Na przykład dla wartości 25, -300 i 212 wynik powinien wyglądać tak:
C: 25.00 F: 77.00
C: 25.00 F: 77.00
C: 100.00 F: 212.00Zauważ, że drugi wiersz pokazuje niezmienione wartości, ponieważ -300 jest poniżej zera absolutnego, więc setter odrzucił tę wartość. Trzeci wiersz pokazuje temperaturę po pomyślnym ustawieniu 212°F (co odpowiada 100°C). Na tym polega siła setterów. Egzekwują reguły, które zapewniają prawidłowość danych.
Spróbuj swoich sił
package main
import (
"fmt"
)
func main() {
// Odczytaj wartości wejściowe
var initialCelsius float64
var newCelsius float64
var newFahrenheit float64
fmt.Scanln(&initialCelsius)
fmt.Scanln(&newCelsius)
fmt.Scanln(&newFahrenheit)
// TODO: Utwórz nowy obiekt Temperature za pomocą konstruktora
// TODO: Wypisz wartości początkowe w formacie "C: [celsius] F: [fahrenheit]" z dokładnością do 2 miejsc po przecinku
// TODO: Spróbuj ustawić nową wartość Celsius i wypisz wynik
// TODO: Spróbuj ustawić nową wartość Fahrenheit i wypisz wynik
}
Ta lekcja zawiera krótki quiz. Zacznij lekcję, żeby na niego odpowiedzieć i śledzić swoje postępy.
Wszystkie lekcje w sekcji Programowanie obiektowe
1Podstawy OOP w Go
Pliki zewnętrzneObszar roboczy i moduły GoPakiety i importyNazwy eksportowane i nieeksportowaneWprowadzenie do OOP w GoStruktury jako klasyDefiniowanie metod dla strukturOdbiorniki wskaźnikowe i wartościoweInicjalizacja strukturFunkcje konstruktoraPodsumowanie – prosty kalkulator4Interfejsy
Wprowadzenie do interfejsówImplementacja niejawnaInterfejs jako kontraktPusty interfejs (any)Asercja typuPrzełącznik typówKompozycja interfejsówInterfejsy Stringer i ErrorPowtórka — kalkulator figur7Hermetyzacja
Pola eksportowane i nieeksportowaneHermetyzacja na poziomie pakietuMetody pobierające i ustawiająceUkrywanie informacji w GoPowtórka – dane studentów10Typy generyczne (Go 1.18+)
Wprowadzenie do typów generycznychParametry typówOgraniczenia typówStruktury generyczneObejście ograniczeń metod generycznychPodsumowanie — generyczna kolekcja2Typy i struktury w praktyce
Typy proste i złożoneDefiniowanie własnych typówTagi pól strukturStruktury anonimoweStruktury zagnieżdżoneWartości zerowe i domyślnePodsumowanie – książka kontaktów5Kompozycja zamiast dziedziczenia
Dlaczego Go nie ma dziedziczeniaPodstawy osadzania strukturPromowanie metodOsadzanie wielu strukturOsadzanie a agregacjaPrzesłanianie osadzonych metodPodsumowanie — hierarchia pracowników8Obsługa błędów i programowanie obiektowe
Interfejs błęduWłasne typy błędówOpakowywanie błędów (fmt.Errorf)Błędy wartowniczeerrors.Is() i errors.As()Panic, Defer i RecoverPodsumowanie — parser plików3Wskaźniki i pamięć
Podstawy wskaźników w GoWskaźniki do strukturPrzekazywanie przez wartość a przez referencjęFunkcja new()Odśmiecanie pamięci w GoPowtórka — kreator listy wiązanej6Polimorfizm w Go
Polimorfizm za pomocą interfejsówDuck typing w GoZasady spełniania interfejsówKolekcje polimorficzneWstrzykiwanie zależnościPowtórka — procesor płatności9Współbieżność i OOP
Podstawy goroutinesKanały i komunikacjaKanały buforowane i niebuforowaneInstrukcja selectsync.Mutex i sync.RWMutexsync.WaitGroupProjektowanie struktur bezpiecznych wątkowoPowtórka – pula workerów12Zaawansowane zagadnienia programowania obiektowego
Wzorzec opcji funkcyjnychWzorzec Builder w GoŁańcuchowe wywoływanie metodAliasy typów a definicje typówPodstawy refleksjiPrzegląd generowania koduPoćwicz samodzielnie: Kompilator Go online