Trong khi tìm kiếm một cái gì đó khác, khá ra khỏi sự trùng hợp ngẫu nhiên, tôi tình cờ gặp vài lời bình luận về cách thức thừa kế lớp vỏ não. Có điều này được gọi là ProductN
, wretches và vua, yêu tinh và pháp sư và làm thế nào một số loại tài sản rất mong muốn bị mất với trường hợp thừa kế các trường hợp. Vì vậy, những gì là sai trái với trường hợp thừa kế lớp?Lỗi * so * với trường hợp thừa kế lớp là gì?
Trả lời
Một từ: bình đẳng
case
lớp đi kèm với việc thực hiện cung cấp của equals
và hashCode
. Mối quan hệ tương đương, được gọi là equals
hoạt động như thế này (nghĩa là phải có các thuộc tính sau):
- Đối với tất cả
x
;x equals x
làtrue
(phản xạ) - Đối với
x
,y
,z
; nếux equals y
vày equals z
thìx equals z
(chuyển tiếp) - Đối với
x
,y
; nếux equals y
sau đóy equals x
(đối xứng)
Ngay sau khi bạn cho phép bình đẳng trong một hệ thống phân cấp thừa kế, bạn có thể phá vỡ 2 và 3. Đây là trivially chứng minh bằng ví dụ sau:
case class Point(x: Int, y: Int)
case class ColoredPoint(x: Int, y: Int, c: Color) extends Point(x, y)
Sau đó, chúng tôi có :
Point(0, 0) equals ColoredPoint(0, 0, RED)
Nhưng không
ColoredPoint(0, 0, RED) equals Point(0, 0)
Bạn có thể tranh luận rằng tất cả các cấu trúc phân lớp có thể có vấn đề này và điều này là đúng. Nhưng các trường hợp đặc biệt tồn tại để đơn giản hóa bình đẳng từ góc nhìn của nhà phát triển (trong số các lý do khác), do đó, để chúng hoạt động không trực quan sẽ là định nghĩa của một mục tiêu riêng!
Cũng có những lý do khác; đáng chú ý là thực tế là copy
did not work as expected và interaction with the pattern matcher.
Điều đó không đúng. Và điều này còn tệ hơn là nói dối.
Như đã đề cập bởi aepurniet trong bất kỳ trường hợp lớp người kế đó co lại một khu vực xác định phải xác định lại sự bình đẳng vì khớp mẫu phải làm việc chính xác như bình đẳng (nếu cố gắng để phù hợp với Point
như ColoredPoint
thì nó sẽ không xuất hiện kể từ khi color
là không tồn tại).
Điều đó cung cấp cho sự hiểu biết về mức độ bình đẳng của phân cấp lớp vỏ có thể được triển khai.
case class Point(x: Int, y: Int)
case class ColoredPoint(x: Int, y: Int, c: Color) extends Point(x, y)
Point(0, 0) equals ColoredPoint(0, 0, RED) // false
Point(0, 0) equals ColoredPoint(0, 0, null) // true
ColoredPoint(0, 0, RED) equals Point(0, 0) // false
ColoredPoint(0, 0, null) equals Point(0, 0) // true
Cuối cùng, bạn có thể đáp ứng các yêu cầu của mối quan hệ bình đẳng ngay cả đối với người kế thừa trường hợp (không ghi đè bình đẳng).
case class ColoredPoint(x: Int, y: Int, c: String)
class RedPoint(x: Int, y: Int) extends ColoredPoint(x, y, "red")
class GreenPoint(x: Int, y: Int) extends ColoredPoint(x, y, "green")
val colored = ColoredPoint(0, 0, "red")
val red1 = new RedPoint(0, 0)
val red2 = new RedPoint(0, 0)
val green = new GreenPoint(0, 0)
red1 equals colored // true
red2 equals colored // true
red1 equals red2 // true
colored equals green // false
red1 equals green // false
red2 equals green // false
def foo(p: GreenPoint) = ???
Và còn một chút công phu nữa :)? –
Có vẻ như sự tương đương không đối xứng như vậy sẽ là một điều hữu ích trong mô hình OO, theo cách tương tự ở cấp độ kiểu 'Màu 'là một' Điểm 'nhưng không ngược lại. Có thể phải gọi nó là một cái gì đó khác hơn là 'bằng' mặc dù ... có lẽ 'subEquals'? –
@LuigiPlinge có lẽ 'canReplace',' supersedes', 'chỉ định' hoặc' ghi đè' cho mối quan hệ ngược lại? Bất cứ điều gì để chỉ ra '> =' -ness (hoặc '>:' nếu bạn thích) của nó. Nó có vẻ dễ dàng hơn nhiều cho tôi để đặt tên nó về '> =' chứ không phải là '<='. –