Inteligentne konstruktory
Konstrukcja z walidacją
Inteligentne konstruktory to bezpłatna lekcja Scala for Backend Engineering & Functional Programming na CoddyKit. To lekcja 2 z 4. Możesz przeczytać całą lekcję poniżej za darmo — a potem ćwiczyć ją interaktywnie w przeglądarce z wbudowanym edytorem kodu i tutorem AI dostępnym 24/7. To część ścieżki edukacyjnej Scala for Backend Engineering & Functional Programming, a Twój postęp synchronizuje się między webem a aplikacją CoddyKit. Kurs Scala for Backend Engineering & Functional Programming zawiera 4 lekcji w sumie.
Tworzenie z walidacją
Inteligentny konstruktor to fabryka, która sprawdza dane wejściowe przed utworzeniem wartości. Gwarantuje, że każda posiadana instancja spełnia niezmienniki typu.
- Surowy konstruktor jest ukryty.
- Publiczne jest tylko tworzenie z walidacją.
class Age private (val value: Int)
object Age:
def of(v: Int): Option[Age] =
if v >= 0 then Some(new Age(v)) else None
object Main:
def main(args: Array[String]): Unit =
println(Age.of(30).map(_.value))Prywatny konstruktor
Oznaczenie konstruktora głównego jako private uniemożliwia wywołującym pominięcie walidacji. Obiekt towarzyszący staje się jedynym punktem wejścia.
class Percentage private (val value: Int)
object Percentage:
def of(v: Int): Option[Percentage] =
if v >= 0 && v <= 100 then Some(new Percentage(v)) else None
object Main:
def main(args: Array[String]): Unit =
println(Percentage.of(50).map(_.value))
println(Percentage.of(150))Zwracanie Option
Zwracanie Option sygnalizuje, że tworzenie może się nie powieść. Wywołujący musi obsłużyć None, dzięki czemu niepoprawne dane nigdy nie przepływają po cichu dalej.
class NonEmpty private (val value: String)
object NonEmpty:
def of(s: String): Option[NonEmpty] =
if s.nonEmpty then Some(new NonEmpty(s)) else None
object Main:
def main(args: Array[String]): Unit =
println(NonEmpty.of("").map(_.value))
println(NonEmpty.of("hi").map(_.value))Zwracanie Either ze szczegółami błędu
Jeśli trzeba wyjaśnić, dlaczego walidacja się nie powiodła, należy zwrócić Either[Error, T]. Lewa gałąź zawiera opisowy komunikat.
class Username private (val value: String)
object Username:
def of(s: String): Either[String, Username] =
if s.isEmpty then Left("empty")
else if s.length > 10 then Left("too long")
else Right(new Username(s))
object Main:
def main(args: Array[String]): Unit =
println(Username.of(""))
println(Username.of("ada").map(_.value))Inteligentne konstruktory z case class
case class z prywatnym konstruktorem również działa. Należy pamiętać, że wygenerowane metody apply i copy także trzeba kontrolować, dlatego należy zdefiniować własną fabrykę i pozostawić konstruktor prywatny.
case class Email private (value: String)
object Email:
def of(s: String): Option[Email] =
if s.contains("@") then Some(Email(s)) else None
object Main:
def main(args: Array[String]): Unit =
println(Email.of("a@b.com"))
println(Email.of("bad"))Łączenie zwalidowanych wartości
Ponieważ inteligentne konstruktory zwracają Option lub Either, można łączyć je za pomocą konstrukcji for, aby tworzyć większe zwalidowane obiekty.
case class Name private (value: String)
object Name:
def of(s: String): Option[Name] =
if s.nonEmpty then Some(Name(s)) else None
case class Person(name: Name, age: Int)
object Main:
def make(n: String): Option[Person] =
for nm <- Name.of(n) yield Person(nm, 20)
def main(args: Array[String]): Unit =
println(Main.make("Bob"))Normalizowanie danych wejściowych
Inteligentny konstruktor może również normalizować dane, na przykład usuwać białe znaki lub zamieniać litery na małe, dzięki czemu wszystkie instancje mają postać kanoniczną.
case class Tag private (value: String)
object Tag:
def of(s: String): Option[Tag] =
val clean = s.trim.toLowerCase
if clean.nonEmpty then Some(Tag(clean)) else None
object Main:
def main(args: Array[String]): Unit =
println(Tag.of(" Scala "))Niezmienniki obowiązują zawsze
Gdy wartość przejdzie przez inteligentny konstruktor, jej niezmiennik jest gwarantowany przez cały czas jej istnienia. Kod korzystający z tej wartości może jej ufać bez ponownego sprawdzania.
case class PositiveInt private (value: Int)
object PositiveInt:
def of(n: Int): Option[PositiveInt] =
if n > 0 then Some(PositiveInt(n)) else None
object Main:
def doubleIt(p: PositiveInt): Int = p.value * 2 // always positive
def main(args: Array[String]): Unit =
PositiveInt.of(5).foreach(p => println(Main.doubleIt(p)))Łączenie z typami niejawnymi
Aby uzyskać zwalidowane wartości bez kosztu w czasie działania, połącz inteligentny konstruktor z typem niejawnym. Nie jest tworzony obiekt opakowujący, a walidacja nadal kontroluje proces tworzenia.
object Domain:
opaque type Score = Int
def of(n: Int): Option[Score] =
if n >= 0 && n <= 100 then Some(n) else None
extension (s: Score) def value: Int = s
object Main:
def main(args: Array[String]): Unit =
println(Domain.of(88).map(_.value))Wiele reguł walidacji
Zastosuj kilka sprawdzeń po kolei. Pierwsza niespełniona reguła przerywa działanie i zwraca jasny błąd.
object Password:
def of(s: String): Either[String, String] =
if s.length < 8 then Left("too short")
else if !s.exists(_.isDigit) then Left("need a digit")
else Right(s)
object Main:
def main(args: Array[String]): Unit =
println(Password.of("abc"))
println(Password.of("abcdef12"))Kiedy używać inteligentnych konstruktorów
Należy ich używać zawsze, gdy typ ma niezmienniki, które mogłoby naruszyć surowe tworzenie.
- Liczby z ograniczeniami, niepuste ciągi znaków, identyfikatory w określonym formacie.
- Zwracaj
Optionw prostych przypadkach powodzenia lub niepowodzenia, aEither, gdy potrzebne jest uzasadnienie. - Zachowaj surowy konstruktor jako prywatny.
case class Port private (value: Int)
object Port:
def of(n: Int): Option[Port] =
if n >= 1 && n <= 65535 then Some(Port(n)) else None
object Main:
def main(args: Array[String]): Unit =
println(Port.of(8080))
println(Port.of(70000))Szybkie sprawdzenie
Sprawdź swoją wiedzę na temat inteligentnych konstruktorów.
Podsumowanie
Poznał(a) Pan/Pani inteligentne konstruktory.
- Waliduj dane wejściowe w fabryce obiektu towarzyszącego.
- Ustaw surowy konstruktor jako prywatny.
- Zwracaj
OptionlubEither, aby wymusić obsługę niepowodzenia. - Opcjonalnie normalizuj dane wejściowe do postaci kanonicznej.
- Niezmienniki będą wtedy obowiązywać przez cały czas istnienia wartości.
case class Even private (value: Int)
object Even:
def of(n: Int): Option[Even] =
if n % 2 == 0 then Some(Even(n)) else None
object Main:
def main(args: Array[String]): Unit =
println(Even.of(4))
println(Even.of(5))Ucz się Scala dzięki korepetycjom AI — za darmo
Pisz i uruchamiaj kod w przeglądarce, otrzymuj natychmiastową pomoc od korepetytora AI dostępnego 24/7 i kontynuuj naukę w sieci lub w aplikacji.
- Kursy
- 39
- Lekcje
- 143
Często zadawane pytania
Czy lekcja „Inteligentne konstruktory” jest bezpłatna?
Tak — pełny tekst „Inteligentne konstruktory” jest dostępny za darmo tutaj w sieci. Aby ćwiczyć ją interaktywnie (wbudowany edytor kodu i tutor AI dostępny 24/7) i odblokować resztę kursu Scala for Backend Engineering & Functional Programming, przejdź na CoddyKit PRO. Kurs Scala for Backend Engineering & Functional Programming zawiera 4 lekcji w sumie.
Co nauczysz się w „Inteligentne konstruktory”?
Konstrukcja z walidacją Ćwiczysz Scala for Backend Engineering & Functional Programming z praktycznym kodem, który uruchamiasz bezpośrednio w przeglądarce, a tutor AI dostępny 24/7 odpowiada na Twoje pytania podczas pracy nad lekcją.
Czy potrzebuję doświadczenia, aby zacząć Scala for Backend Engineering & Functional Programming?
Nie wymagamy żadnego doświadczenia. Scala for Backend Engineering & Functional Programming w CoddyKit jest strukturyzowany dla początkujących i zaawansowanych użytkowników, więc możesz zacząć tutaj lub od początku i uczyć się w swoim tempie. To lekcja 2 z 4.
Ile czasu zajmuje lekcja „Inteligentne konstruktory”?
Większość lekcji CoddyKit trwa około 5–10 minut. Każda lekcja to mały, interaktywny krok, dzięki czemu robisz systematyczne postępy i zawsze wracasz dokładnie do tego samego miejsca — na webie i w aplikacji.
Czy mogę pisać i uruchamiać kod w tej lekcji Scala for Backend Engineering & Functional Programming?
Tak. Każda lekcja Scala for Backend Engineering & Functional Programming zawiera wbudowany edytor kodu, więc piszesz i uruchamiasz prawdziwy kod bezpośrednio w przeglądarce i od razu otrzymujesz sprzężenie zwrotne od AI — bez konfiguracji na komputerze.
Wszystkie lekcje w tym kursie
- Modelowanie za pomocą ADT
- Inteligentne konstruktory
- Newtype
- Komponowanie domen