0Pricing
Scala for Backend Engineering & Functional Programming · درس

الوراثة وتعدد الأشكال

استكشف مبادئ البرمجة كائنية التوجه، مثل الوراثة والفئات المجرّدة وتعدد الأشكال في Scala

الوراثة وتعدد الأشكال درس مجاني في Scala for Backend Engineering & Functional Programming على CoddyKit. هذا هو الدرس 2 من أصل 2. يمكنك قراءة الدرس كاملاً أدناه مجاناً — ثم تمرن عليه مباشرة في المتصفح باستخدام محرر أكواد مدمج ومدرس ذكاء اصطناعي متاح 24/7. هذا الدرس جزء من مسار التعلم في Scala for Backend Engineering & Functional Programming، وتقدمك يتزامن عبر الويب وتطبيق CoddyKit. تتضمن دورة Scala for Backend Engineering & Functional Programming 2 دروس في المجموع.

بعض أجزاء هذا الدرس لم تُترجم بعد وتظهر باللغة الإنجليزية.

What is Inheritance?

Inheritance is a fundamental concept in Object-Oriented Programming (OOP) that allows a new class to inherit properties and behaviors (methods) from an existing class.

Think of it as a 'parent-child' relationship. The 'child' class (subclass) reuses code from the 'parent' class (superclass), saving time and ensuring consistency.

  • Promotes code reuse.
  • Establishes an 'is-a' relationship (e.g., a Dog is an Animal).
  • Helps organize code into a hierarchy.

Your First Base Class

Let's define a simple Animal class. This will be our base class, also known as a superclass or parent class. It has a basic behavior: to speak.

Run the code to see our generic animal in action!

class Animal {
  val name: String = "Generic Animal"
  def speak(): Unit = {
    println(s"$name makes a sound.")
  }
}

object Main {
  def main(args: Array[String]): Unit = {
    val myAnimal = new Animal()
    myAnimal.speak()
  }
}

Extending with `extends`

Now, let's create a more specific animal, a Dog. A Dog is an Animal, so it can inherit from the Animal class using the extends keyword.

We can also override the speak method to give Dog its own unique sound. Notice the override keyword.

class Animal {
  val name: String = "Generic Animal"
  def speak(): Unit = {
    println(s"$name makes a sound.")
  }
}

class Dog extends Animal {
  override val name: String = "Dog"
  override def speak(): Unit = {
    println(s"$name barks!")
  }
}

object Main {
  def main(args: Array[String]): Unit = {
    val myAnimal = new Animal()
    val myDog = new Dog()
    myAnimal.speak() // Generic Animal makes a sound.
    myDog.speak()    // Dog barks!
  }
}

The Power of `override`

The override keyword is crucial in Scala for several reasons:

  • Clarity: It explicitly tells other developers that this method or field is replacing one from a superclass.
  • Safety: The compiler checks if you are actually overriding an existing member. If you make a typo or the superclass method changes, the compiler will alert you.
  • Intent: It clearly states your intention to specialize or change inherited behavior.

Always use override when redefining inherited members!

Polymorphism: Many Forms

Polymorphism means 'many forms'. In OOP, it allows objects of different classes to be treated as objects of a common superclass.

This means you can have a variable of type Animal that holds a Dog object, a Cat object, or any other subclass of Animal. When you call a method on that variable, the correct method for the actual object's type is executed.

  • Enables flexible and extensible code.
  • Allows a single interface for different data types.
  • Achieved through method overriding.

Polymorphism in Practice

Let's see polymorphism in action. We'll create a Cat class similar to Dog. Then, we can put different types of animals into a list of their common supertype, Animal, and call their speak method.

Notice how each animal speaks in its own unique way, even though they are all treated as Animal types in the list.

class Animal {
  val name: String = "Generic Animal"
  def speak(): Unit = {
    println(s"$name makes a sound.")
  }
}

class Dog extends Animal {
  override val name: String = "Dog"
  override def speak(): Unit = {
    println(s"$name barks!")
  }
}

class Cat extends Animal {
  override val name: String = "Cat"
  override def speak(): Unit = {
    println(s"$name meows!")
  }
}

object Main {
  def main(args: Array[String]): Unit = {
    val animals: List[Animal] = List(
      new Animal(),
      new Dog(),
      new Cat()
    )

    animals.foreach(_.speak())
  }
}

Introducing Abstract Classes

Sometimes, you want a base class that defines a common interface but doesn't provide a complete implementation for some of its members. This is where abstract classes come in.

An abstract class:

  • Cannot be instantiated directly (you can't create an object of an abstract class).
  • Can contain abstract methods (methods without an implementation) and concrete methods (methods with an implementation).
  • Serves as a blueprint that its subclasses must complete.

Building Abstract Blueprints

Let's define an abstract class Shape. Every shape has an area, but the formula for calculating it differs for each specific shape (circle, rectangle, etc.).

So, we declare area as an abstract method. Notice it has no body (no = { ... }). Subclasses will be responsible for providing its implementation.

abstract class Shape {
  def area: Double // Abstract method, no implementation
  
  def describe(): Unit = {
    println("This is a geometric shape.")
  }
}

// You cannot do: new Shape() - it's abstract!

object Main {
  def main(args: Array[String]): Unit = {
    println("Abstract class Shape defined.")
    println("Cannot instantiate Shape directly.")
  }
}

Concrete Implementations

Now, let's create concrete subclasses like Circle and Rectangle that extend our abstract class Shape. These subclasses must provide an implementation for the abstract area method.

They also inherit the concrete describe() method from Shape.

abstract class Shape {
  def area: Double
  def describe(): Unit = {
    println("This is a geometric shape.")
  }
}

class Circle(radius: Double) extends Shape {
  override def area: Double = math.Pi * radius * radius
}

class Rectangle(width: Double, height: Double) extends Shape {
  override def area: Double = width * height
}

object Main {
  def main(args: Array[String]): Unit = {
    val circle = new Circle(5)
    val rectangle = new Rectangle(4, 6)

    println(s"Circle area: ${circle.area}")
    circle.describe()
    println(s"Rectangle area: ${rectangle.area}")
    rectangle.describe()
  }
}

Inheritance & Polymorphism Check

Which of the following statements about inheritance and polymorphism in Scala are TRUE?

Recap: Inheritance & Polymorphism

Great job! In this lesson, we explored core OOP concepts in Scala:

  • Inheritance: How subclasses reuse code and define an 'is-a' relationship with superclasses using extends.
  • override Keyword: Essential for explicitly redefining inherited methods and fields, ensuring type safety and clarity.
  • Polymorphism: The ability to treat objects of different subclasses as objects of a common superclass, enabling flexible and extensible code.
  • Abstract Classes: Blueprints that can't be instantiated directly, used to define common interfaces and abstract members that subclasses must implement.

These concepts are vital for building well-structured and maintainable Scala applications!

الأسئلة الشائعة

هل درس «الوراثة وتعدد الأشكال» مجاني؟

نعم — نص درس «الوراثة وتعدد الأشكال» كامل متاح مجاناً هنا على الويب. لتمرينه بشكل تفاعلي (محرر أكواد مدمج ومدرس ذكاء اصطناعي متاح 24/7) وفتح باقي دورة Scala for Backend Engineering & Functional Programming، انتقل إلى CoddyKit PRO. تتضمن دورة Scala for Backend Engineering & Functional Programming 2 دروس في المجموع.

ماذا ستتعلم في «الوراثة وتعدد الأشكال»؟

استكشف مبادئ البرمجة كائنية التوجه، مثل الوراثة والفئات المجرّدة وتعدد الأشكال في Scala تتمرن على Scala for Backend Engineering & Functional Programming مع أكواد عملية تشغلها مباشرة في المتصفح، ومدرس ذكاء اصطناعي متاح 24/7 يجيب على أسئلتك أثناء عملك.

هل أحتاج إلى خبرة سابقة لأبدأ Scala for Backend Engineering & Functional Programming؟

لا تُشترط خبرة سابقة. Scala for Backend Engineering & Functional Programming على CoddyKit منظم للمبتدئين حتى المتقدمين، لذا يمكنك البدء من هنا أو من البداية والتقدم بسرعتك الخاصة. هذا هو الدرس 2 من أصل 2.

كم من الوقت يستغرق درس «الوراثة وتعدد الأشكال»؟

معظم دروس CoddyKit تستغرق حوالي 5–10 دقائق. كل منها موجز وتفاعلي، لذا تحرز تقدماً مستمراً وتستأنف من حيث توقفت عبر الويب والتطبيق.

هل يمكنني كتابة وتشغيل أكواد في درس Scala for Backend Engineering & Functional Programming هذا؟

نعم. كل درس في Scala for Backend Engineering & Functional Programming يتضمن محرر أكواد مدمج، لذا تكتب وتشغل أكواداً حقيقية مباشرة في متصفحك وتحصل على تعليقات فورية من الذكاء الاصطناعي — بدون إعداد محلي.

جميع الدروس في هذه الدورة

  1. الفئات والكائنات وحزم البرمجيات
  2. الوراثة وتعدد الأشكال
← العودة إلى Scala for Backend Engineering & Functional Programming