2013-01-14 35 views
18

tôi cần hai trường hợp có quyền truy cập vào từng tư nhân khác. tôi tự nhiên nghĩ về một đối tượng đồng hành cấp quyền truy cập vào một trường hợp duy nhất và duy nhất của lớp đồng hành của nó. bản thân lớp tôi đã tạo riêng tư, vì vậy người dùng không thể chỉ tạo các cá thể bằng cách sử dụng new.đối tượng đồng hành với một lớp riêng tư: tại sao nó không hợp lệ?

object A { 
    def apply = dual 
    lazy val dual = new A 
} 

private class A { 
    //some irrelevant logic... 
} 

mã này không biên dịch. Tôi nhận được: lớp A thoát khỏi phạm vi xác định của nó như là một phần của loại A lỗi, mà tôi không thực sự hiểu. cách khắc phục hiện tại của tôi là xác định đặc điểm với mọi tuyên bố phương thức mà lớp nên có và làm cho class A mở rộng đặc điểm đó, trong khi kép thuộc loại đặc điểm và không phải là loại class A.

vấn đề lý thuyết tôi đang thiếu ở đây là gì? tại sao điều này là forbiden?

+8

hehehe truy cập vào từng cá nhân khác –

+2

@ AK4749, sau tất cả, đó là bạn đồng hành của chúng tôi mà chúng tôi đang nói đến. Nó không giống như lớp học chỉ là cho phép _anyone_ để truy cập vào tư nhân của cô ... Mặc dù khi _reflection _... –

Trả lời

29

Giải pháp của Paolo rất tốt (+1), nhưng anh ấy không giải thích được thông báo lỗi, vì vậy hãy để tôi thử điều đó. Vấn đề xuất phát từ thực tế là mọi phương thức đều cần kiểu trả về. Định nghĩa ban đầu của bạn là applydual trả về một đối tượng là class A, do đó kiểu trả về ngầm của cả hai là A. Điều đó ngụ ý rằng A phải được hiển thị cho khách hàng - làm cách nào khác họ có thể gọi chức năng hoặc truy cập vào val? Hơn nữa, như cả hai - và đối tượng cha mẹ của họ quá - là công khai, họ có thể nhìn thấy trên toàn cầu. Tuy nhiên, bạn khai báo A private có nghĩa là nó không được hiển thị bên ngoài gói của nó. Vì vậy, có một xung đột mà không thể được giải quyết bởi trình biên dịch.

Quy tắc chung là tất cả thông số và kiểu trả về của hàm/thành viên phải có (ít nhất) phạm vi hiển thị giống như chính thành viên giới thiệu *. Do đó, một cách tầm thường để giải quyết vấn đề này là giảm mức độ hiển thị của applydual thành private. Điều này sẽ thỏa mãn trình biên dịch, nhưng không phải bạn :-)

Giải pháp của bạn xung quanh vấn đề bằng cách thay đổi kiểu trả về tĩnh thành một đặc điểm public, do đó có khả năng hiển thị giống như các thành viên đề cập đến nó. Loại động của đối tượng được trả về vẫn là class A, tuy nhiên, điều này không cần hiển thị đối với khách hàng. Đây là một ví dụ kinh điển về nguyên tắc "program to interfaces, not implementations".

Lưu ý rằng để áp dụng nguyên tắc này để đầy đủ mức độ, người ta có thể biến class A thành một lớp bên trong private của object A, do đó làm cho nó innaccessible ngay cả đối với các lớp khác trong cùng một gói:

trait A { 
    //... 
} 

object A { 
    def apply: A = dual 
    lazy val dual: A = new AImpl 

    private class AImpl extends A { 
     //some irrelevant logic... 
    } 

} 

* Để được pedantic, lớp kèm theo/đối tượng có thể làm giảm khả năng hiển thị của các thành viên của nó, giống như ở đây:

private class Holder { 
    def member = new Hidden 
} 

private class Hidden 

nơi memberpublic nhưng lớp kèm theo của nó là private, ẩn các thành viên của nó một cách hiệu quả khỏi thế giới bên ngoài. Vì vậy, trình biên dịch phát ra không có khiếu nại ở đây.

+0

đây là một câu trả lời rất tốt –

+0

thực sự! một câu trả lời rất hay ..! cảm ơn! –

23

Tôi nghĩ bạn không muốn có một lớp học riêng tư, mà là một lớp học với một nhà xây dựng tư nhân.

class A private() 
object A { 
    def apply = dual 
    lazy val dual = new A 
} 

Bây giờ lớp học của bạn "hiển thị" với mã bên ngoài, nhưng chỉ đối tượng đồng hành mới có thể tạo các thể hiện của nó.

+0

cảm ơn! ngớ ngẩn tôi ... đôi khi, những vấn đề khó hiểu nhất, thực sự khá ngớ ngẩn và đơn giản. –

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