koncepcja kontroli dostępu pozwala nam ograniczyć dostęp do typów, funkcji i innych deklaracji za pomocą innego kodu. Swift oferuje pięć różnych poziomów Kontroli dostępu, a pełne ich wykorzystanie może mieć kluczowe znaczenie w pisaniu programów, które mają wyraźnie oddzielone obawy i solidną strukturę.

kiedy zdefiniujemy dowolny nowy typ, właściwość lub funkcję w Swift, będzie ona miała domyślnie poziom dostępu internal. Oznacza to, że będzie on widoczny dla wszystkich innych kodów znajdujących się w tym samym module — takich jak aplikacja, rozszerzenie systemu, framework lub pakiet Swift.

jako przykład, powiedzmy, że budujemy aplikację zakupową i że zdefiniowaliśmy klasę o nazwie PriceCalculator, która pozwala nam obliczyć całkowitą cenę dla tablicy produktów:

ponieważ obecnie nie określamy żadnego jawnego poziomu dostępu, Nasza klasa PriceCalculator (i jej metoda calculatePrice) będzie dostępna z dowolnego miejsca w naszej aplikacji. Jeśli jednak chcemy udostępnić naszą nową klasę innym modułom (możemy, na przykład, zaimplementować ją w ramach, które dzielimy między naszą główną aplikacją a rozszerzeniem lub towarzyszącą aplikacją Apple Watch), będziemy musieli uczynić ją public, aby była widoczna w tych zewnętrznych kontekstach:

Jednak powyższa zmiana nie wystarczy. Chociaż jesteśmy teraz w stanie znaleźć naszą klasę poza modułem, w którym jest zdefiniowana, nie możemy utworzyć jej instancji — ponieważ jej (niejawny) inicjalizator jest, jak każdy inny kod, domyślnie internal. Aby to naprawić, zdefiniujmy inicjalizator public, który zostawimy pusty, ponieważ nie ma w nim żadnej rzeczywistej pracy do zrobienia:

public class PriceCalculator { public init() {} ...}

jesteśmy teraz w stanie znaleźć, zainicjować i wywołać nasz PriceCalculator zarówno wewnątrz, jak i na zewnątrz jego modułu — fantastycznie. Ale powiedzmy teraz, że chcemy go podklasować, aby go zmodyfikować lub dodać do niego nową funkcjonalność. Chociaż jest to obecnie możliwe w ramach własnego modułu, jest to ponownie coś, co jest zabronione poza nim.

aby to zmienić, będziemy musieli użyć obecnie najbardziej otwartego poziomu kontroli dostępu Swift, który jest odpowiednio nazwany open:

open class PriceCalculator { ...}

Dzięki powyższej zmianie możemy teraz tworzyć niestandardowe podklasy PriceCalculator w dowolnym miejscu – które mogą mieć nowe inicjalizatory, nowe właściwości i nowe metody. Oto jak możemy użyć tego do zaimplementowania DiscountedPriceCalculator, co pozwala nam zastosować daną discount do wszystkich obliczeń cenowych:

powyżej definiujemy zupełnie nową metodę obliczania ceny, ale prawdopodobnie bardziej odpowiednie byłoby nadpisanie i zmodyfikowanie istniejącej metody calculatePrice, którą odziedziczyliśmy z naszej klasy bazowej. W ten sposób nie byłoby zamieszania wokół metody wywołania, i moglibyśmy utrzymać nasze dwie klasy spójne.

aby móc to zrobić, ponownie musimy oznaczyć pierwotną deklarację-tym razem naszą calculatePrice deklarację metody-jako open:

open class PriceCalculator { public init() {} open func calculatePrice(for products: ) -> Int { ... }}

mając powyższe na miejscu, możemy teraz dowolnie nadpisać calculatePrice, zamiast tworzyć osobną metodę:

więc to jest internal, public i open — które są używane do stopniowego otwierania deklaracji do użytku publicznego i modyfikacji. Ale możemy oczywiście pójść w drugą stronę i ukryć części naszego kodu przed odkryciem i użyciem. Na początku może wydawać się wątpliwe, jaka jest wartość w robieniu tego, ale może to naprawdę pomóc nam uczynić nasze API znacznie bardziej wąskim i skoncentrowanym — co z kolei może ułatwić zrozumienie, Testowanie i używanie.

przejdźmy teraz do drugiej strony spektrum poziomu dostępu i przyjrzyjmy się najbardziej restrykcyjnemu poziomowi — private. Każdy typ, właściwość lub metoda oznaczona jako private będzie widoczna tylko w obrębie własnego typu (który zawiera również rozszerzenia dla tego typu zdefiniowanego w tym samym pliku).

Wszystko, co powinno być uważane za prywatny szczegół implementacji danego typu, powinno być prawdopodobnie oznaczone jako private. Na przykład, nasza nieruchomość discount z naszego kalkulatora cenowego była tak naprawdę przeznaczona tylko do użytku w swojej klasie — więc zróbmy to, aby ta nieruchomość była prywatna:

class DiscountedPriceCalculator: PriceCalculator { private let discount: Int ...}

nasza poprzednia implementacja będzie nadal działać dokładnie tak samo jak poprzednio, ponieważ discount pozostanie całkowicie widoczna w naszej klasie DiscountedPriceCalculator. Jeśli jednak chcemy nieco rozszerzyć tę widoczność, aby uwzględnić również inne typy zdefiniowane w tym samym pliku, musielibyśmy użyć

class DiscountedPriceCalculator: PriceCalculator { fileprivate let discount: Int ...}

Dzięki powyższej zmianie możemy teraz uzyskać dostęp do naszej właściwości discount z powiązanego kodu zdefiniowanego w tym samym pliku — takiego jak to rozszerzenie na UIAlertController, które pozwala nam łatwo pokazać opis ceny dla tablicy produktów w alercie:

jeśli chodzi o wolne funkcje, typy i rozszerzenia, private i fileprivate działają dokładnie tak samo. Różnią się one tylko wtedy, gdy są stosowane do deklaracji zdefiniowanych w obrębie typu.

podsumowując, są to pięć poziomów Kontroli dostępu, które obecnie oferuje Swift:

  • private zachowuje własność lub funkcję prywatną w obrębie typu zamykającego, w tym wszelkie rozszerzenia tego typu zdefiniowane w tym samym pliku. Po zastosowaniu do typu, funkcji lub rozszerzenia najwyższego poziomu, działa tak samo jak fileprivate.
  • fileprivate sprawia, że deklaracja jest widoczna w całym pliku, w którym jest zdefiniowana, ukrywając ją przed wszystkimi innymi kodami.
  • internal jest domyślnym poziomem dostępu i sprawia, że deklaracja jest widoczna w całym module, w którym jest zdefiniowana.
  • public ujawnia funkcję, Typ, rozszerzenie lub właściwość poza modułem.
  • open umożliwia podklasę klasy i nadpisanie funkcji lub właściwości poza modułem.

ogólnie rzecz biorąc, często najlepiej zacząć od najbardziej restrykcyjnego poziomu dostępu, jaki dana deklaracja może mieć praktycznie, a następnie otworzyć rzeczy później, jeśli zajdzie taka potrzeba. W ten sposób ograniczamy możliwości interakcji między naszymi różnymi typami i funkcjami, co z początku może wydawać się złą rzeczą, ale często jest naprawdę niezbędne do budowy systemów, które można utrzymać i dobrze ustrukturyzować.

Dzięki za przeczytanie! 🚀

(zauważ, że ten artykuł nie wszedł w modyfikatory dostępu specyficzne dla mutacji, takie jak private(set). Te zostaną omówione w kolejnym artykule podstawy w przyszłości.

Wspieraj Swift by Sundell sprawdzając tego sponsora:

Instabug: Rozwiązuj błędy, awarie i inne problemy znacznie szybciej, korzystając ze szczegółowych śladów stosu, dzienników sieciowych i zdarzeń interfejsu użytkownika, które Instabug automatycznie dołącza do każdego zgłoszenia błędu. Używany zarówno przeze mnie, jak i tysiące zespołów programistycznych iOS na całym świecie. Wypróbuj go za darmo i Zintegruj z jednym wierszem kodu.

Dodaj komentarz

Twój adres e-mail nie zostanie opublikowany.