Az opaque típusok egy enkapszulációs technika az Elmben.
Egyesek információelrejtésnek vagy az implementációs részletek elrejtésének is nevezik.
Gyakran használják az érvényesítés kikényszerítésére is, a Parse, dont validate mintát követve.
Például lehet egy EmailAddress opaque típusod, amely csak érvényes e-mail-címeket tartalmazhat (ellentétben a String-gel, amely bármit tartalmazhat).
A custom type-oknak egy vagy több változatuk van, és a fordító automatikusan létrehoz egy-egy függvényt minden változat létrehozásához, a változat nevének felhasználásával. Ez az egyetlen módja annak, hogy custom type-okat létrehozzunk. A fordító ezen változatok destrukturálását is lehetővé teszi.
type Maybe a
= Nothing --> Variant implies a 'Nothing' function, with type 'Maybe a', and destructuring of 'Nothing'
| Just a --> Variant implies a 'Just' function, with type 'a -> Maybe a', and destructuring of 'Just _'
Alapértelmezés szerint mindez a fájlon / modulon belül marad, és az exposing kulcsszóval választjuk ki, mit exportálunk.
Opaque típus létrehozásához egyszerűen csak nem exportálod a változatokat.
Amikor ezt teszed, szinte mindig szükség van egy másik módra a változatok létrehozásához és eléréséhez, méghozzá saját függvények exportálásával. Ezek a saját függvények lehetővé teszik, hogy valamilyen logikát alkalmazz a változatok létrehozásakor és elérésekor. Ez elrejti a modul belső implementációs részleteit, és azt jelenti, hogy az implementációs részleteket tetszés szerint módosíthatod, amíg az exportált függvények ugyanazok maradnak.
Az opaque típusok talán leggyakoribb felhasználása az érvényesítés kikényszerítése a Parse, dont validate mintával.
Ebben a mintában exportálsz egy függvényt, amely egy nálad kevésbé strukturált / típusbiztos bemenetet kap, például egy String-et, majd ezt egy strukturáltabb típussá alakítja, például EmailAddress-dé, és vagy visszaadja a típust, vagy hibát ad vissza (általában Maybe-t vagy Result-ot).
Például az alábbi kódban a külső modulok csak a parseEmailAddress függvénnyel hozhatnak létre EmailAddress típust, így amikor az EmailAddress típussal dolgozol, biztos lehetsz benne, hogy érvényes.
module EmailAddress exposing ( EmailAddress, parseEmailAddress, getEmailAddress )
-- The `EmailAddress` custom type has one variant, also called `EmailAddress`
-- When a custom type has one variant, it is idiomatic to use the same name for both.
type EmailAddress =
EmailAddress String
-- create an EmailAddress variant
parseEmailAddress: String -> Maybe EmailAddress
parseEmailAddress candidateEmailAddress =
if isValidEmailAddress candidateEmailAddress then
Just (EmailAddress candidateEmailAddress)
else
Nothing
-- get an EmailAddress variant
getEmailAddress: EmailAddress -> String
getEmailAddress ( EmailAddress emailAdress ) =
emailAdress
isValidEmailAddress: String -> bool
-- ...
Ebben a feladatban egy általános (varázslatos!) SecureTreasureChest-et fogsz írni, hogy némi kincset tárolj benne.
A szemfüles tanulók észrevették, hogy a korábbi TreasureChest nem volt annyira biztonságos!
Ha a getTreasure függvényt használtad, meg kellett adnod a jelszót, de a TreasureChest típust egyszerűen destrukturálva így is megszerezhetted a kincset, anélkül hogy ismerted volna a jelszót.
Sőt, ami még rosszabb: ugyanígy magát a jelszót is kiolvashattad!
Javítsuk ki ezt egy opaque típus használatával.
Definiálj egy Password egyedi típust egyetlen változattal.
A változathoz tartozzon egy String érték, a jelszó.
A Password típust tedd közzé, a változatot viszont ne.
Ettől a Password opaque típus lesz, és azt jelenti, hogy többé nem tudod destrukturálással megszerezni a jelszót.
Azt, hogy egy típus opaque-e vagy sem, nem lehet tesztelni, ezért éles kódban a elm-review (egy statikus elemzőeszköz) segítségével kényszerítheted ki.
Definiálj és tegyél közzé egy createPassword függvényt típusdefinícióval, amely egy String-et vár és egy Maybe Password-t ad vissza.
Az Owasp azt javasolja, hogy a jelszavak legalább 8 karakter hosszúak legyenek, ezért a Parse, don't validate mintát használjuk ennek az invariánsnak a kikényszerítésére.
Ha a jelszó rövidebb 8 karakternél, a createPassword Nothing-ot adjon vissza, egyébként pedig Just Password-t.
A SecureTreasureChest típust tedd közzé, a változatát viszont ne.
Ettől a SecureTreasureChest opaque típus lesz, és azt jelenti, hogy többé nem tudod destrukturálással megszerezni sem a jelszót, sem a kincset.
Ez a függvény két paramétert vegyen át, és legyen típusdefiníciója.
Password (a jelszónak)A függvény egy SecureTreasureChest-et adjon vissza.
Tedd közzé ezt a függvényt, hogy más modulok is létre tudjanak hozni SecureTreasureChest példányokat.
Ez a függvény két paramétert vegyen át, és legyen típusdefiníciója.
String (a jelszónak)SecureTreasureChest generikus egyedi típusA függvény hasonlítsa össze a megadott jelszót a SecureTreasureChest-ben lévő Password-dal.
A függvény egy Maybe-t adjon vissza.
Ha a jelszavak megegyeznek, akkor a Just-ot add vissza a SecureTreasureChest-ben lévő generikus értékkel (a kinccsel!).
Ha a jelszavak nem egyeznek meg, akkor a Nothing-ot add vissza.
Tedd közzé ezt a függvényt, hogy más modulok is ki tudják venni a kincset a SecureTreasureChest-ből, feltéve hogy a helyes jelszót adják meg.
Iratkozz fel az Exercism-re, hogy megtanuld és elsajátítsd a(z) Elm nyelvet 28 fogalom110 feladat segítségével, valódi emberi mentorálással, mindez ingyen.