What is polymorphism?
Trong quá trình nghiên cứu về Scalaz và TypeClasses mình thấy cần phải nói chi tiết hơn về Polymorphism, tham khảo trên @wikipedia thì có ba loại Polymorphism lần lượt là: Ad-hoc Polymorphism, Parametric Polymorphism và Subtype Polymorphism. Với các ví dụ cụ thể bằng ngôn ngữ Scala, hy vọng sẽ giúp các bạn hiểu rõ hơn.
Ad-hoc Polymorphism
Tuỳ thuộc vào type của tham số mà các cài đặt khác nhau của method được gọi, ví dụ chúng ta có hai cài đặt của method plus: Một là cộng 2 số nguyên và một là công 2 chuỗi ( 2 plus 1 là 3 nhưng “2” plus “1” là “21”). Method Overidding là một vị dụ cho Ad-hoc Polymorphism.
Trong scala chúng ta có hai cách để thể hiện Ad-hoc Polymorphism thông qua: Implicit conversion và Type Classese
Implicit conversion
Đầu tiên, chúng ta xây dựng một trait Plusable :
trait PlusAble[A] {
def plus(a: A): A
}
Tiếp theo chúng ta sẽ có hai cài đặt của Plusable trait, một cho kiểu Int và một cho kiểu String:
class PlusAbleInt(i: Int) extends PlusAble[Int] {
override def plus(a: Int): Int = i + a
}
class PlusAbleString(s: String) extends PlusAble[String] {
override def plus(a: String): String = s.concat(a)
}
Phần còn lại chúng ta sẽ khai báo implicit conversion:
implicit def toPlusable(i: Int) = new PlusAbleInt(i)
implicit def toPlusable(s: String) = new PlusAbleString(s)
và
def plusItems[A](a: A, b: A)(implicit evidence: A => PlusAble[A]) =
a plus b
Hàm plusItems truyền vào hai tham số kiểu A và thông qua hàm plus để thực hiện cộng. Kiểu A có thể là Int hay String, và cũng không cần quan tâm hàn plus hoạt động như nào.
Type Classes
Type Classes là một khái niệm khá thú vị, mình sẽ nói về nó ở một bài viết khác, trước tiên chúng ta sẽ cùng nhau viết lại đoạn chương trình trên.
Hàm plusItems không sử dụng implicit conversion nữa mà thay vào đó chúng ta sử dụng một implicit class instance:
trait PlusAble[A] {
def plus(a: A, b: A): A
}
object PlusAble {
implicit val plusAbleInt = new PlusAble[Int] {
override def plus(a: Int, b: Int): Int = a + b
}
implicit val plusAbleString = new PlusAble[String] {
override def plus(a: String, b: String): String = a.concat(b)
}
}
def plusItems[A](a: A, b: A)(implicit evidence: PlusAble[A]) =
evidence.plus(a, b)
val res1 = plusItems(1, 3)
Tuyệt!, các bạn có thể copy và chạy thử, với Type Classes chúng ta có thể dễ dàng mở rộng mà không cần động đến source code hiện tại, chúng ta có thể dễ dàng thêm mới một cài đặt cho PlusAble với type không phải là Int hay String.
Trên đây là ví dụ về Ad-hoc Polymophism, có thể phần nò giúp bạn hiểu rõ hơn về nó.
Parametric Polymorphism
Giả sử chúng ta có một List của A, A có thể là Int, String, Double… hàm head lấy ra phần tử đầu tiên của List đó.
def head[A](xs: List[A]): A = xs(0)
head("Apple" :: "Orange" :: Nil) //> Apple
head(1 :: 2 :: 3 :: Nil) //> 1
Hàm head() không quan tâm đến A là kiểu gì, nó trả ra phần tử đầu tiên của List[A]. Parametric Polymorphism cũng giống như Generics trong Java.
Subtype Polymorphism
Subtype cho phép một function viết để thực hiện một task vụ thực hiện lời gọi đến một method của một đối tượng có kiểu T, nhưng nó đồng thời cũng hoạt động đối với đội tượng có kiểu S là con của kểu T (S <: T).
Hãy xem ví dụ dưới đây: Chúng ta có Trait Animal là cha của class Cat và Dog:
trait Animal {
def talk: String;
}
class Cat extends Animal {
override def talk(): String =
"Meow"
}
class Dog extends Animal {
override def talk(): String =
"Woof"
}
def letsHear(animal: Animal) = animal.talk()
letsHear(new Cat) //> Meow
letsHear(new Dog) //> Woof
hàm letshear có thể thực hiện với đối tượng Animal đồng thời nó cũng có thể thực hiện với đối tượng Cat và Dog.
OK! mình đã tổng hợp lại ba loại Polymorphism, mình sẽ nhắc lại nó trong các bài viêt tiếp theo với các ví dụ cụ thể.
Tham khảo:
http://eed3si9n.com/learning-scalaz/polymorphism.html
https://en.wikipedia.org/wiki/Polymorphism_(computer_science)