16.5. Dostęp chroniony

Oprócz modyfikatora private istnieje też modyfikator protected, który dotyczy definicji znajdujących się wewnątrz klas i pozwala na to, aby modyfikowana definicja mogła być użyta w tej klasie, jej klasach pochodnych oraz obiektach towarzyszących tych klas. Ten modyfikator może być użyty, podobnie jak private, w trzech różnych formach. Jeśli zamienilibyśmy modyfikatory private na protected w przykładach do tej pory pokazanych w tym rozdziale, to działanie zaprezentowanych przykładów nie zmieniłoby się. Przykłady, które nie kompilowały się z modyfikatorem private, nie kompilowałyby się nadal z modyfikatorem protected. Przykłady, które działały z modyfikatorem private, działałyby również z modyfikatorem protected. Z tego względu nie będziemy powtarzać tutaj powyższych przykładów zmieniając jedynie modyfikator na protected. Czytelnik jeśli chce, może tego spróbować samodzielnie. Do tej pory jednak przykłady z tego rozdziału nie obejmowały dziedziczenia. Teraz przejdziemy do przykładów, które zawierają elementy dziedziczenia. W tych przykładach będzie można zaobserwować różnice między modyfikatorami private i protected. Przyjrzyjmy się zatem dziedziczeniu i porównajmy działanie tych modyfikatorów.

Plik Protected1.scala:
class Greeting(greeting: String) {
  private def speak = println(greeting)
  private[this] def speak2 = println(greeting + " " + greeting)
}
object Hello extends Greeting("Hello") {
  def talk = speak
  def talk2 = speak2
}

W przykładzie z pliku Protected1.scala obiekt Hello nie kompiluje się, gdyż próbuje uzyskać dostęp do prywatnych składowych swojej klasy nadrzędnej. W tym przykładzie ani modyfikator private, ani private[this] nie pozwala na dostęp do składowych z klasy podrzędnej.

$ scalac Protected1.scala
Protected1.scala:6: error: not found: value speak
  def talk = speak
             ^
Protected1.scala:7: error: not found: value speak2
  def talk2 = speak2
              ^
two errors found

Wymiana w klasie Greeting modyfikatorów private na protected zmienia sytuację. Poprawiony kod znajduje się w pliku Protected2.scala.

Plik Protected2.scala:
class Greeting(greeting: String) {
  protected def speak = println(greeting)
  protected[this] def speak2 = println(greeting + " " + greeting)
}
object Hello extends Greeting("Hello") {
  def talk = speak
  def talk2 = speak2
}

Teraz kod kompiluje się i może być wykonany. Obiekt Hello dziedziczy metody z klasy Greeting i ma do nich dostęp.

scala> Hello.talk
Hello

scala> Hello.talk2
Hello Hello

Przykłady z plików Protected3.scala i Protected4.scala ilustrują różnicę między między działaniem modyfikatora protected, a protected[this], czyli między dostępem chronionym, a chronionym w ramach obiektu.

Plik Protected3.scala:
class Greeting(greeting: String) {
  protected def speak = println(greeting)
}
class Hello(name: String) extends Greeting("Hello "+name) {
  def talkTo(other: Hello) {
    this.speak
    other.speak
  }
}

W przykładzie z pliku Protected3.scala, w klasie Greeting jest zdefiniowana chroniona metoda speak. Dziedzicząca po Greeting klasa Hello wywołuje, w metodzie talkTo, metodę speak na dwóch obiektach, najpierw na swoim własnym obiekcie, a później na obiekcie przekazanym w parametrze other.

scala> val peter = new Hello("Peter")
peter: Hello = Hello@c4ddae

scala> val john = new Hello("John")
john: Hello = Hello@f6d34c

scala> peter talkTo john
Hello Peter
Hello John

Wywołanie metody talkTo udaje się. Metody speak w obu obiektach są dostępne. Sytuacja zmieni się, gdy klasie Greeting modyfikator protected zmieni się na protected[this]. Zmodyfikowana definicja znajduje się w pliku Protected4.scala.

Plik Protected4.scala:
class Greeting(greeting: String) {
  protected[this] def speak = println(greeting)
}
class Hello(name: String) extends Greeting("Hello "+name) {
  def talkTo(other: Hello) {
    this.speak 
    other.speak 
  }
}

Teraz dostęp do metody speak jest bardziej ograniczony. Kompilator nie pozwala na dostęp do metody speak obiektu other, przekazanego w parametrze metody talkTo (wiersz ). Natomiast wywołanie this.speak (wiersz ) nie powoduje błędu kompilacji.

$ scalac Protected4.scala
Protected4.scala:7: error: value speak is not a member of Hello
    other.speak
          ^
one error found

Język programowania Scala Wydanie 2. Copyright © Grzegorz Balcerek 2016

Licencja Creative Commons

Ten utwór jest dostępny na licencji Creative Commons Uznanie autorstwa-Na tych samych warunkach 4.0 Międzynarodowe.

Oracle and Java are registered trademarks of Oracle and/or its affiliates. Other names may be trademarks of their respective owners.