2011-01-13 35 views
21

Ok, tôi sẽ giải thích tại sao tôi hỏi câu hỏi này. Tôi bắt đầu đọc mã nguồn Lift 2.2 những ngày này. Thật tốt nếu bạn tình cờ đọc mã nguồn nâng trước.Tại sao mọi người định nghĩa lớp, đặc điểm, đối tượng bên trong một đối tượng khác trong Scala?

Trong thang máy, tôi thấy rằng, xác định lớp bên trong và đặc điểm bên trong được sử dụng rất nhiều.

đối tượng Menu có 2 đặc điểm bên trong và 4 lớp bên trong. đối tượng Loc có 18 lớp bên trong, 5 đặc điểm bên trong, 7 đối tượng bên trong.

Có rất nhiều mã viết như thế này. Tôi muốn biết tại sao tác giả viết như thế này.

  • Có phải vì đó là tác giả của sở thích cá nhân hoặc sử dụng mạnh mẽ tính năng ngôn ngữ ?
  • Có sự giao dịch nào cho loại này sử dụng không?

Trả lời

18

Trước 2.8, bạn phải chọn giữa các gói và đối tượng. Vấn đề với các gói là chúng không thể chứa các phương thức hoặc các vals. Vì vậy, bạn phải đặt tất cả những người bên trong một đối tượng khác, mà có thể nhận được vụng về. Quan sát:

object Encrypt { 
    private val magicConstant = 0x12345678 
    def encryptInt(i: Int) = i^magicConstant 
    class EncryptIterator(ii: Iterator[Int]) extends Iterator[Int] { 
    def hasNext = ii.hasNext 
    def next = encryptInt(ii.next) 
    } 
} 

Bây giờ bạn có thể import Encrypt._ và truy cập vào các phương pháp encryptInt cũng như lớp EncryptIterator. Tiện dụng!

Ngược lại,

package encrypt { 
    object Encrypt { 
    private[encrypt] val magicConstant = 0x12345678 
    def encryptInt(i: Int) = i^magicConstant 
    } 
    class EncryptIterator(ii: Iterator[Int]) extends Iterator[Int] { 
    def hasNext = ii.hasNext 
    def next = Encrypt.encryptInt(ii.next) 
    } 
} 

Nó không phải là một sự khác biệt rất lớn , nhưng nó làm cho việc nhập khẩu sử dụng cả hai encrypt._encrypt.Encrypt._ hoặc phải tiếp tục viết Encrypt.encryptInt hơn và hơn. Tại sao không chỉ sử dụng một đối tượng thay vào đó, như trong mẫu đầu tiên? (Thực sự không có hình phạt hiệu suất nào, vì các lớp lồng nhau không thực sự là các lớp bên trong Java dưới mui xe; chúng chỉ là các lớp thông thường theo như JVM biết, nhưng với các tên lạ mắt cho bạn biết chúng được lồng nhau.)

Trong 2.8, bạn có thể ăn bánh của bạn và ăn nó: gọi vật là vật thể gói và trình biên dịch sẽ viết lại mã cho bạn để nó trông giống như ví dụ thứ hai dưới mui xe (ngoại trừ đối tượng Encrypt thực sự được gọi là package nội bộ) , nhưng hoạt động giống như ví dụ đầu tiên về không gian tên - các vals và defs ngay tại đó mà không cần nhập thêm.

Vì vậy, các dự án đã bắt đầu trước 2,8 thường sử dụng các đối tượng để gửi kèm nhiều thứ như thể chúng là một gói. Post-2.8, một trong những động cơ chính đã bị loại bỏ. (Nhưng chỉ để được rõ ràng, sử dụng một đối tượng vẫn không bị tổn thương, nó là nhiều hơn mà nó là khái niệm gây hiểu nhầm hơn là nó có một tác động tiêu cực đến hiệu suất hoặc whatnot.)

(PS Xin vui lòng, không cố gắng để thực sự mã hóa bất cứ điều gì theo cách ngoại trừ ví dụ hoặc một trò đùa!)

+0

Lớp lồng trong một đối tượng có giống hệt với lớp bên trong tĩnh của Java không? Nếu tôi đặt 100 lớp bên trong, hoặc 100 đối tượng bên trong trong một đối tượng đồng hành, trình biên dịch sẽ xử lý chúng như thế nào? Tuyệt đối không có hình phạt về hiệu suất? – Sawyer

+1

Một lớp lồng nhau 'Bar' bên trong một lớp hoặc đối tượng' Foo' được thực hiện không phải là một lớp bên trong mà là một lớp _outer_ với tên 'Foo $ Bar', và chỉ khi nó thực sự cần sử dụng lớp cha của nó thì nó sẽ có (trường sắp xếp ẩn) trỏ đến phụ huynh. Trình biên dịch thay vì JVM thi hành rằng bạn sử dụng đúng cách này và trong trường hợp của một đối tượng, nó biết chỉ có một đối tượng để nó không cần phải bận tâm lưu trữ trường đó. –

3

Có thể là cả hai. Trong số những thứ khác, một thể hiện của một lớp bên trong/đặc điểm có quyền truy cập vào các biến của cha mẹ của nó. Các lớp bên trong phải được tạo ra với một cá thể cha, đó là một thể hiện của kiểu bên ngoài.

Trong các trường hợp khác, đó có thể chỉ là cách nhóm các thứ liên quan chặt chẽ, như trong ví dụ object của bạn. Lưu ý rằng đặc tính LocParam được niêm phong, có nghĩa là tất cả các lớp con phải nằm trong cùng một đơn vị/tệp biên dịch.

+0

Sử dụng đối tượng cho những thứ liên quan đến nhóm không cảm thấy tốt với tôi, tôi nghĩ rằng đó là cách sử dụng của gói. – Sawyer

+0

@ Zwcat: Có rất nhiều sự thật với những gì bạn nói. Tuy nhiên, như một vấn đề thuận tiện, nó có thể ít rắc rối hơn để có tất cả những điều nhỏ nhặt này trong một tệp chứ không phải trong quá nhiều tệp trong cùng một thư mục. Sử dụng từ khóa kín làm cho nó cần thiết để đặt chúng trong cùng một tập tin và gói chúng trong một đối tượng có chứa sẽ có vẻ ít lộn xộn. – sblundy

2

sblundy có câu trả lời hợp lý. Một điều cần thêm là chỉ với Scala 2.8 bạn có các đối tượng gói cho phép bạn nhóm những thứ tương tự trong một không gian tên gói mà không tạo ra một đối tượng hoàn toàn riêng biệt. Vì lý do đó, tôi sẽ cập nhật đề xuất Mô-đun nâng của tôi để sử dụng đối tượng gói thay vì một đối tượng đơn giản.

Các vấn đề liên quan