Наследование позволяет нам абстрагировать общие параметры класса для того, чтобы чтобы избежать множественного повторения логики и облегчить классы.
Помимо обычный классов в Scala существует абстрактный вид классов(abstract class), отличие от обычный классов в том, что мы не может создать экземпляр такого класса, они созданы лишь для последующего наследования другими классами:
abstract class A {def a: String}
class D extends A {override def a: String = ???}
Как видите, после наследования абстрактного класса(ключевое слово extends), мы обязаны имплементировать все методы, существующие в абстрактном классе(ключевое слово override). Что нам даст такой подход, спросите вы? Тут в игру входит полиморфизм: теперь мы можем принимать в качестве аргуметов функций/создавать массивы/ возвращать значения и пр. класса А, содержащие любые из классов, наследующих этот класс. Т.е. при вызове метода def s(a:A) в качестве аргумента можно подсунуть экземпляр класса D.
def s(a:A) = a match {
case c: D => println("it's D")
}
s(new D)
Не используя паттерн-матчинг мы можем обращаться лишь к методам, присутствующим только в классе А, однако с матчем - ко всем методам класса D.
Помимо абстрактных классов так существуют трейты, эдакие интерфейсы с логикой, и в отличие от абстрактных классов, наследовать трейты можно не единожды, а множественно(ключевое слово with):
trait Z{def a:String = "Z"}
trait Q{def a:String = "Q"}
class F extends A with Z with Q{
override def a: String = super.a}
println(new F().a)
Как Вы можете заметить, при имплементации метода а() мы вызывает super.a, super - это способ обращения к продительскому классу, т.е. мы вызываем метод родительских классов. Но в абстрактном классе, как и в трейдах - все три метода названы одинаково, как же всё не ломается, как компилятор понимает, куда смотреть? Не вдаваясть глубоко в подробности, следует запомнить, что преобладающим методом будет тот, чей владелец наследован последним, в данном случае выведется Q.
sealed trait L{} - ещё одно крайне полезное обозначение, sealed значит то, что никакой класс вне пакета не сможет быть унаследован от этого трейта, однако принимать и работать с классами, наследующих его они могут. Удобно, когда вы уверенны в том, что все классы, наследующие один трейт точно находятся в одном месте, не так ли?
Наследование и полиморфизм - мощные инструменты, учитесь их использовать, и ваш код станет чище и гибче!