2011-10-06 27 views
5

Giả sử chúng ta có một lớp học như thế này:Thực thi mã trong constructor quá tải trước khi gọi này()

import java.net.URL 
import xml._ 

class SearchData(xml: Node) { 
    def this(url: URL) = this (XML.load(url)) 
} 

và chúng tôi muốn thực hiện một số mã trước khi gọi this (XML.load(url)) - nói thử nghiệm nó với try. Một hy vọng rằng viết một cái gì đó như thế này sẽ làm việc:

class SearchData(xml: Node) { 
    def this(url: URL) { 
    try { 
     this (XML.load(url)) 
    } catch { 
     case _ => this(<results/>) 
    } 
    } 
} 

nhưng nó sẽ không, bởi vì Scala yêu cầu bạn thực hiện cuộc gọi đến this() báo cáo kết quả đầu tiên trong constructor quá tải và trong trường hợp này try trở thành báo cáo kết quả đầu tiên .

Vậy giải pháp cho vấn đề này là gì?

Trả lời

6
def this(url: Url) = this(try {XML.load(url)} catch {case _ => <results/>}) 

Tổng quát hơn, việc đánh giá của các đối số có thể xảy ra trước khi cuộc gọi constructor, vì vậy bạn làm điều đó ở đó (một khối trong scala là một biểu hiện, nhưng viết một thói quen, thường bằng văn bản trong đối tượng đồng , nếu nó sẽ quá dài). Những gì bạn không thể làm là có mã này chọn phương thức khởi tạo khác mà bạn gọi. Nhưng vì tất cả chúng đều phải đi đến điểm chính, bạn không mất nhiều. Ngoài ra, bạn cần hàm tạo khác mà bạn gọi để có ít nhất một đối số. Nếu có nhiều nhà xây dựng, là chính nên thường không phải là một mà không có một cuộc tranh cãi (xem Scala problem optional constructor)

+0

Một giải pháp tốt cho vấn đề công bố, nhưng nó không phải là chung . Có lẽ đó là lỗi của tôi mà tôi tuyên bố một vấn đề tầm thường. Dù sao hãy kiểm tra http://stackoverflow.com/questions/7680442/executing-code-in-overloaded-constructor-prior-to-calling-this/7687567#7687567 có phần nào đó giải quyết được giải pháp của bạn –

5

Một phương thức factory trong đối tượng đồng:

object SearchData { 
    def apply(xml: Node) = new SearchData(xml) //Added to provide uniform factories 
    def apply(url: URL) = { 
    try { 
     new SearchData(XML.load(url)) 
    } catch { 
     case _ => new SearchData(<results/>) 
    } 
    } 
} 

//Example 
val sd = SearchData(new URL("http://example.com/")) 

Không chỉ nó đơn giản hóa thiết kế, nhưng bạn có thể tha từ khóa new.

+1

Tôi không thấy nó đơn giản như thế nào thiết kế. Nó cũng buộc bạn hoặc đưa ra các mâu thuẫn bằng cách xây dựng các đối tượng cả khi có và không có từ khóa 'mới' phụ thuộc vào kịch bản hoặc vi phạm quy tắc DRY và tạo bí danh đồng hành cho tất cả các nhà xây dựng trong các lớp của bạn. luôn luôn. Và bạn vẫn sẽ phải xây dựng các lớp thư viện với 'new'. –

+0

Thực ra, mẫu này khá phổ biến trong thư viện scala và được tự động triển khai cho các lớp chữ hoa chữ thường. Vì vậy, _inconsistency_ đã có. Cộng với những hạn chế mạnh mẽ mà nhà xây dựng nói quá nhiều cho khách hàng hầu hết thời gian, cụ thể là loại chính xác của kết quả và thực tế là nó mới được tạo ra.Một nhà máy không phải là giá trị làm tất cả các thời gian, nhưng họ thường là thuận tiện và trong khi nó làm phiền tôi, tôi sẽ không dừng lại ở sự mâu thuẫn. Tôi nhớ Delphi một cách trìu mến nơi các hàm tạo và các hàm tĩnh được gọi giống như cách của trình khách. –

+0

Tôi đồng ý với bạn hoàn toàn. Trên thực tế trong [Kotlin] (http://confluence.jetbrains.net/display/Kotlin/Classes+and+Inheritance), họ giải quyết vấn đề này bằng cách loại bỏ từ khóa 'mới'. Thật lạ lùng với tôi rằng những kẻ Scala không thấy vấn đề ở đây. –

3

Trong khi giải pháp của didierd giải quyết được vấn đề được khai báo và có phần gần với vấn đề này, nó vẫn không giải quyết được sự cố khi bạn phải thực hiện một số câu lệnh trước khi gọi this. Cái này cung cấp một cách tiếp cận chung cho tất cả các kịch bản:

class SearchData(xml: Node) { 
    def this(url: URL) = this { 
    println(url) 
    try { 
     XML.load(url) 
    } catch { 
     case _ => <results/> 
    } 
    } 
} 

Bí quyết ở đây là this được cho ăn với kết quả của thực hiện một chức năng ẩn danh trong cơ thể trong đó bạn được phép làm bất cứ điều gì.

Nhưng này chỉ hoạt động khi bạn có một nhà xây dựng chính đơn lập luận - trong các tình huống khác mà bạn sẽ phải giới thiệu một Tuple workaround dựa trên:

class SearchData(xml: Node, valid: Boolean) { 
    def this(url: URL) = this { 
    println(url) 
    try { 
     (XML.load(url), true) 
    } catch { 
     case _ => (<results/>, false) 
    } 
    } 
    def this(t: (Node, Boolean)) = this(t._1, t._2) 
} 
+0

Tôi cho rằng nhận xét của tôi đã đề cập đến trường hợp đầu tiên của bạn với println. Nhưng bạn thực hiện một điểm rất tốt với trường hợp thứ hai. –

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