Adakah situasi di mana Anda harus memilih kelas non-case?
Martin Odersky memberi kita titik awal yang baik dalam kursusnya Prinsip-Prinsip Pemrograman Fungsional dalam Skala (Kuliah 4.6 - Pencocokan Pola) yang dapat kita gunakan ketika kita harus memilih antara kelas dan kelas kasus. Bab 7 Scala By Example berisi contoh yang sama.
Katakanlah, kami ingin menulis penerjemah untuk ekspresi aritmatika. Untuk menjaga kesederhanaan pada awalnya, kami membatasi diri kami hanya pada angka dan + operasi. Ekspresi seperti itu dapat direpresentasikan sebagai hierarki kelas, dengan kelas dasar abstrak Ekspr sebagai root, dan dua subkelas Number dan Sum. Kemudian, ekspresi 1 + (3 + 7) akan direpresentasikan sebagai
Jumlah baru (Nomor baru (1), Jumlah baru (Nomor baru (3), Nomor baru (7)))
abstract class Expr {
def eval: Int
}
class Number(n: Int) extends Expr {
def eval: Int = n
}
class Sum(e1: Expr, e2: Expr) extends Expr {
def eval: Int = e1.eval + e2.eval
}
Selain itu, menambahkan kelas Prod baru tidak memerlukan perubahan apa pun pada kode yang sudah ada:
class Prod(e1: Expr, e2: Expr) extends Expr {
def eval: Int = e1.eval * e2.eval
}
Sebaliknya, menambahkan metode baru membutuhkan modifikasi semua kelas yang ada.
abstract class Expr {
def eval: Int
def print
}
class Number(n: Int) extends Expr {
def eval: Int = n
def print { Console.print(n) }
}
class Sum(e1: Expr, e2: Expr) extends Expr {
def eval: Int = e1.eval + e2.eval
def print {
Console.print("(")
print(e1)
Console.print("+")
print(e2)
Console.print(")")
}
}
Masalah yang sama diselesaikan dengan kelas kasus.
abstract class Expr {
def eval: Int = this match {
case Number(n) => n
case Sum(e1, e2) => e1.eval + e2.eval
}
}
case class Number(n: Int) extends Expr
case class Sum(e1: Expr, e2: Expr) extends Expr
Menambahkan metode baru adalah perubahan lokal.
abstract class Expr {
def eval: Int = this match {
case Number(n) => n
case Sum(e1, e2) => e1.eval + e2.eval
}
def print = this match {
case Number(n) => Console.print(n)
case Sum(e1,e2) => {
Console.print("(")
print(e1)
Console.print("+")
print(e2)
Console.print(")")
}
}
}
Menambahkan kelas Prod baru membutuhkan kemungkinan mengubah semua pencocokan pola.
abstract class Expr {
def eval: Int = this match {
case Number(n) => n
case Sum(e1, e2) => e1.eval + e2.eval
case Prod(e1,e2) => e1.eval * e2.eval
}
def print = this match {
case Number(n) => Console.print(n)
case Sum(e1,e2) => {
Console.print("(")
print(e1)
Console.print("+")
print(e2)
Console.print(")")
}
case Prod(e1,e2) => ...
}
}
Transkrip dari videolecture 4.6 Pencocokan Pola
Kedua desain ini baik-baik saja dan memilih di antara keduanya terkadang merupakan masalah gaya, namun demikian ada beberapa kriteria yang penting.
Salah satu kriterianya adalah, apakah Anda lebih sering membuat subkelas ekspresi baru atau lebih sering membuat metode baru? Jadi, ini adalah kriteria yang melihat perpanjangan masa depan dan kemungkinan perpanjangan sistem Anda.
Jika apa yang Anda lakukan kebanyakan membuat subclass baru, maka sebenarnya solusi dekomposisi berorientasi objek lebih unggul. Alasannya adalah sangat mudah dan perubahan yang sangat lokal untuk hanya membuat subclass baru dengan metode eval , dimana seperti dalam solusi fungsional, Anda harus kembali dan mengubah kode di dalam metode eval dan menambahkan kasus baru untuk itu.
Di sisi lain, jika yang Anda lakukan adalah membuat banyak metode baru, tetapi hierarki kelas itu sendiri akan dijaga agar relatif stabil, maka pencocokan pola sebenarnya menguntungkan. Karena, sekali lagi, setiap metode baru dalam solusi pencocokan pola hanyalah perubahan lokal , baik Anda meletakkannya di kelas dasar, atau bahkan mungkin di luar hierarki kelas. Sedangkan metode baru seperti show dalam dekomposisi berorientasi objek akan membutuhkan incrementasi baru pada setiap sub kelas. Jadi akan ada lebih banyak bagian, Yang harus Anda sentuh.
Jadi masalah ekstensibilitas ini dalam dua dimensi, di mana Anda mungkin ingin menambahkan kelas baru ke hierarki, atau Anda mungkin ingin menambahkan metode baru, atau mungkin keduanya, telah dinamai masalah ekspresi .
Ingat: kita harus menggunakan ini sebagai titik awal dan bukan sebagai satu-satunya kriteria.