Scala - Eigenschaften

Ein Merkmal kapselt Methoden- und Felddefinitionen, die dann durch Mischen in Klassen wiederverwendet werden können. Im Gegensatz zur Klassenvererbung, bei der jede Klasse nur von einer Oberklasse erben muss, kann eine Klasse eine beliebige Anzahl von Merkmalen einmischen.

Merkmale werden verwendet, um Objekttypen zu definieren, indem die Signatur der unterstützten Methoden angegeben wird. Mit Scala können Merkmale auch teilweise implementiert werden, aber Merkmale haben möglicherweise keine Konstruktorparameter.

Eine Merkmalsdefinition sieht genauso aus wie eine Klassendefinition, außer dass das Schlüsselwort verwendet wird trait. Das Folgende ist die grundlegende Beispielsyntax des Merkmals.

Syntax

trait Equal {
   def isEqual(x: Any): Boolean
   def isNotEqual(x: Any): Boolean = !isEqual(x)
}

Dieses Merkmal besteht aus zwei Methoden isEqual und isNotEqual. Hier haben wir keine Implementierung für isEqual angegeben, wenn eine andere Methode implementiert ist. Untergeordnete Klassen, die ein Merkmal erweitern, können die nicht implementierten Methoden implementieren. Ein Merkmal ist also dem, was wir haben, sehr ähnlichabstract classes in Java.

Nehmen wir ein Beispiel für ein Merkmal Equal enthalten zwei Methoden isEqual() und isNotEqual(). Das MerkmalEqual enthalten eine implementierte Methode, das heißt isEqual() also wenn benutzerdefinierte Klasse Point erweitert das Merkmal Equal, Umsetzung zu isEqual() Methode in Point Klasse sollte zur Verfügung gestellt werden.

Hier müssen zwei wichtige Scala-Methoden bekannt sein, die im folgenden Beispiel verwendet werden.

  • obj.isInstanceOf [Point] Um zu überprüfen, ob der Typ von obj und der Punkt gleich sind, ist dies nicht der Fall.

  • obj.asInstanceOf [Point] bedeutet genaues Casting, indem der Objektobjekttyp verwendet wird und dasselbe Objekt wie der Punkttyp zurückgegeben wird.

Versuchen Sie das folgende Beispielprogramm, um Merkmale zu implementieren.

Beispiel

trait Equal {
   def isEqual(x: Any): Boolean
   def isNotEqual(x: Any): Boolean = !isEqual(x)
}

class Point(xc: Int, yc: Int) extends Equal {
   var x: Int = xc
   var y: Int = yc
   
   def isEqual(obj: Any) = obj.isInstanceOf[Point] && obj.asInstanceOf[Point].x == y
}

object Demo {
   def main(args: Array[String]) {
      val p1 = new Point(2, 3)
      val p2 = new Point(2, 4)
      val p3 = new Point(3, 3)

      println(p1.isNotEqual(p2))
      println(p1.isNotEqual(p3))
      println(p1.isNotEqual(2))
   }
}

Speichern Sie das obige Programm in Demo.scala. Die folgenden Befehle werden zum Kompilieren und Ausführen dieses Programms verwendet.

Befehl

\>scalac Demo.scala
\>scala Demo

Ausgabe

true
false
true

Werteklassen und universelle Merkmale

Werteklassen sind neue Mechanismen in Scala, um die Zuweisung von Laufzeitobjekten zu vermeiden. Es enthält einen primären Konstruktor mit genau einemvalParameter. Es enthält nur Methoden (def), die nicht für var, val, verschachtelte Klassen, Merkmale oder Objekte zulässig sind. Die Wertklasse kann nicht um eine andere Klasse erweitert werden. Dies kann möglich sein, indem Sie Ihre Wertklasse mit AnyVal erweitern. Die Typensicherheit von benutzerdefinierten Datentypen ohne Laufzeitaufwand.

Nehmen wir ein Beispiel für Werteklassen wie Gewicht, Größe, E-Mail, Alter usw. Für all diese Beispiele ist es nicht erforderlich, Speicher in der Anwendung zuzuweisen.

Eine Werteklasse, die Merkmale nicht erweitern darf. Damit Wertklassen Merkmale erweitern können,universal traits eingeführt werden, die sich für Any.

Beispiel

trait Printable extends Any {
   def print(): Unit = println(this)
}
class Wrapper(val underlying: Int) extends AnyVal with Printable

object Demo {
   def main(args: Array[String]) {
      val w = new Wrapper(3)
      w.print() // actually requires instantiating a Wrapper instance
   }
}

Speichern Sie das obige Programm in Demo.scala. Die folgenden Befehle werden zum Kompilieren und Ausführen dieses Programms verwendet.

Befehl

\>scalac Demo.scala
\>scala Demo

Ausgabe

Sie erhalten den Hash-Code der Wrapper-Klasse.

Wrapper@13

Wann sollten Eigenschaften verwendet werden?

Es gibt keine feste Regel, aber hier sind einige Richtlinien zu beachten -

  • Wenn das Verhalten nicht wiederverwendet wird, machen Sie es zu einer konkreten Klasse. Es ist schließlich kein wiederverwendbares Verhalten.

  • Wenn es in mehreren nicht verwandten Klassen wiederverwendet werden kann, machen Sie es zu einem Merkmal. Nur Merkmale können in verschiedene Teile der Klassenhierarchie gemischt werden.

  • Wenn du möchtest inherit Verwenden Sie im Java-Code eine abstrakte Klasse.

  • Wenn Sie vorhaben, es in kompilierter Form zu verteilen, und Sie erwarten, dass externe Gruppen Klassen schreiben, die davon erben, können Sie eine abstrakte Klasse verwenden.

  • Wenn Effizienz sehr wichtig ist, tendieren Sie zur Verwendung einer Klasse.