Skip to content

Polish translation of Tour of Scala: Mixins #1221

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Jan 19, 2019
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
74 changes: 53 additions & 21 deletions _pl/tour/mixin-class-composition.md
Original file line number Diff line number Diff line change
@@ -1,20 +1,43 @@
---
layout: tour
title: Kompozycja domieszek
title: Kompozycja klas przez domieszki

discourse: false

partof: scala-tour

num: 6
num: 7
language: pl
next-page: higher-order-functions
previous-page: tuples
---

W przeciwieństwie do języków, które wspierają jedynie pojedyncze dziedziczenie, Scala posiada bardziej uogólniony mechanizm ponownego wykorzystania klas. Scala umożliwia wykorzystanie _nowych elementów klasy_ (różnicy w stosunku do klasy bazowej) w definicji nowej klasy. Wyraża się to przy pomocy _kompozycji domieszek_.
Domieszka (ang. mixin) to cecha (trait), która używana jest do komponowania klas.

Rozważmy poniższe uogólnienie dla iteratorów:
{% scalafiddle %}
```tut
abstract class A {
val message: String
}
class B extends A {
val message = "Jestem instancją klasy B"
}
trait C extends A {
def loudMessage = message.toUpperCase()
}
class D extends B with C

val d = new D
println(d.message) // wyświetli "Jestem instancją klasy B"
println(d.loudMessage) // wyświetli "JESTEM INSTANCJĄ KLASY B"
```
{% endscalafiddle %}

Klasa `D` posiada nadklasę `B` oraz domieszkę `C`.
Klasy mogą mieć tylko jedną nadklasę, ale wiele domieszek (używając kolejno słów kluczowych `extends`, a następnie `with`).
Domieszki i nadklasy mogą posiadać tą samą nadklasę (typ bazowy).

Spójrzmy teraz na trochę ciekawszy przykład zawierający klasę abstrakcyjną.

```tut
abstract class AbsIterator {
Expand All @@ -24,35 +47,44 @@ abstract class AbsIterator {
}
```

Następnie rozważmy klasę domieszkową, która doda do klasy `AbsIterator` metodę `foreach` wykonującą podaną funkcję dla każdego elementu zwracanego przez iterator. Aby zdefiniować klasę domieszkową, użyjemy słowa kluczowego `trait`:
Klasa ta zawiera abstrakcyjny typ `type T` oraz standardowe metody iteracyjne `hasNext` i `next`.

```tut
trait RichIterator extends AbsIterator {
def foreach(f: T => Unit) { while (hasNext) f(next()) }
class StringIterator(s: String) extends AbsIterator {
type T = Char
private var i = 0
def hasNext = i < s.length
def next() = {
val ch = s charAt i
i += 1
ch
}
}
```

Oto przykład konkretnego iteratora, który zwraca kolejne znaki w podanym łańcuchu znaków:
Klasa `StringIterator` przyjmuje parametr typu `String`, może być ona użyta do iterowania po typach String (np. aby sprawdzić czy String zawiera daną literę).

Stwórzmy teraz cechę, która również rozszerza `AbsIterator`.

```tut
class StringIterator(s: String) extends AbsIterator {
type T = Char
private var i = 0
def hasNext = i < s.length()
def next() = { val ch = s charAt i; i += 1; ch }
trait RichIterator extends AbsIterator {
def foreach(f: T => Unit): Unit = while (hasNext) f(next())
}
```

Chcielibyśmy także połączyć funkcjonalność `StringIterator` oraz `RichIterator` w jednej klasie. Z pojedynczym dziedziczeniem czy też samymi interfejsami jest to niemożliwe, gdyż obie klasy zawierają implementacje metod. Scala pozwala na rozwiązanie tego problemu z użyciem _kompozycji domieszek_. Umożliwia ona ponowne wykorzystanie różnicy definicji klas, tzn. wszystkich definicji, które nie zostały odziedziczone. Ten mechanizm pozwala nam na połączenie `StringIterator` z `RichIterator`, tak jak w poniższym przykładzie - gdzie chcielibyśmy wypisać w kolumnie wszystkie znaki z danego łańcucha:
Cecha `RichIterator` implementuje metodę `foreach`, która z kolei wywołuje przekazaną przez parametr funkcję `f: T => Unit` na kolejnym elemencie (`f(next())`) tak długo, jak dostępne są kolejne elementy (`while (hasNext)`).
Ponieważ `RichIterator` jest cechą, nie musi implementować abstrakcyjnych składników klasy `AbsIterator`.

Spróbujmy teraz połączyć funkcjonalności `StringIterator` oraz `RichIterator` w jednej klasie.

```tut
object StringIteratorTest {
def main(args: Array[String]) {
class Iter extends StringIterator("Scala") with RichIterator
val iter = new Iter
iter foreach println
}
object StringIteratorTest extends App {
class RichStringIter extends StringIterator("Scala") with RichIterator
val richStringIter = new RichStringIter
richStringIter foreach println
}
```

Klasa `iter` w funkcji `main` jest skonstruowana wykorzystując kompozycję domieszek `StringIterator` oraz `RichIterator` z użyciem słowa kluczowego `with`. Pierwszy rodzic jest nazywany _klasą bazową_ `Iter`, podczas gdy drugi (i każdy kolejny) rodzic jest nazywany _domieszką_.
Nowo powstała `RichStringIter` posiada `StringIterator` jako nadklasę oraz `RichIterator` jako domieszkę.

Mając do dyspozycji jedynie pojedyncze dziedziczenie, nie byli byśmy w stanie osiągnąć takiego stopnia elastyczności.