2015-12-10 16 views
5

Tôi biết mẫu này có tên, không nhớ nó là gì. Về cơ bản có một phương thức trả về một điều thoáng qua/trampoline điều khiển bản gốc thông qua một API. Mediator có thể?Không thể triển khai mẫu thiết kế này trong Swift?

Tôi đã cố gắng để thực hiện điều đó trong một ví dụ đơn giản trong Swift sân chơi:

struct Count { 
    var value = 0 

    func adjuster() -> Adjuster { 
     return Adjuster(target:self) 
    } 
} 

struct Adjuster { 
    var target:Count 

    func increment(delta:Int) { 
     self.target.value = self.target.value + delta 
    } 
} 

var f = Count() 

f.adjuster().increment(13) 

Điều đầu tiên này không có gì helpfully nói với tôi rằng phương pháp increment cần phải được đánh dấu mutating. Đó là một chút không rõ ràng với tôi tại sao. Tôi sẽ nhận được lý do tại sao nếu nó đã được biến đổi var riêng của nó, nhưng không phải là var khác. Oh well. Vì vậy, tôi để cho IDE chèn đột biến cho tôi. Nhưng sau đó nó có vấn đề với trường hợp "thử nghiệm" dòng cuối cùng. Lỗi này tạo ra lỗi này:

...: error: cannot use mutating member on immutable value: function call returns immutable value 
f.adjuster().increment(13) 
~~^~~~~~~~~~ 

Tôi không hoàn toàn lúng túng sự cố ở đây. Nó cũng không cung cấp "sửa chữa nó" cho tôi. Vì vậy, những gì đang xảy ra ở đây? Làm thế nào để thực hiện mô hình này?

Trả lời

2

Bạn phải thay đổi struct thành class để làm cho nó hoạt động.

struct được sao chép theo giá trị, vì vậy trong dòng này

return Adjuster(target:self) 

Adjuster sẽ nhận được một bản sao mới của mục tiêu, và lưu nó. Trong phương thức increment, bạn đang cố gắng sửa đổi self.target.value, có nghĩa là bạn đang sửa đổi self.target, do đó, về cơ bản sửa đổi self.

Nhưng có vấn đề hơn, bởi vì struct là kiểu giá trị, vì vậy

var count: Count // count.value = 0 
var adjuster = count.adjuster() 
adjuster.increment(1) 

Bạn sẽ mong đợi count.value sẽ là 1, tuy nhiên điều này không phải là trường hợp. count.value sẽ vẫn là 0 và adjuster.target.count sẽ là 1.Giờ đây, mã của bạn bây giờ rất khó hiểu và bạn đang tự hỏi có gì sai.

Vấn đề thực sự là bạn đang triển khai mẫu thiết kế từ OOP với nguyên thủy cho mẫu thuần túy, vì vậy chúng không hoạt động tốt với nhau.

Nếu bạn đang buộc phải làm theo một số hướng dẫn thực hành tốt nhất và thích struct qua class, bạn cũng có thể sử dụng phương pháp chức năng để thay thế. tức là không có đột biến

struct Count { 
    let value = 0 
} 

func increment(count:Count, delta:Int) -> Count { 
    return Count(value:count.value + delta) 
} 
+1

Theo các dấu hiệu từ Apple (như rất nhiều cuộc đàm phán tại WWDC), tôi tiếp tục cố gắng làm những điều TheValueWay (tm). Và tôi cứ va vào những bức tường như thế này. Càng có nhiều điều xảy ra, tôi càng tin tưởng rằng các Viện nghiên cứu Pedantic đang tiếp quản Apple: (Dù sao thì, câu trả lời của bạn đã giúp tôi nhìn thấy vấn đề ngay lập tức, cảm ơn. –

3

Với struct (không giống như class) nếu phương pháp của bạn đột biến tài sản của mình (-ies), nó phải được đánh dấu bằng mutating từ khóa.

Trong trường hợp của bạn nó sẽ giống như thế:

mutating func increment(delta:Int) { ... } 

Từ documentation:

Structures and enumerations are value types. By default, the properties of a value type cannot be modified from within its instance methods.

However, if you need to modify the properties of your structure or enumeration within a particular method, you can opt in to mutating behavior for that method. The method can then mutate (that is, change) its properties from within the method, and any changes that it makes are written back to the original structure when the method ends.

"Tôi sẽ nhận được lý do tại sao nếu nó bị đột biến var riêng của nó, nhưng không phải là var của người khác . "

Lý do tại sao nó vẫn than phiền về "đột biến", mặc dù nó không phải là thuộc tính của riêng nó, mà là thuộc tính của một thuộc tính khác, là cả hai đều là loại giá trị. Điều này có nghĩa là nếu bạn thay đổi thuộc tính của Count trong phạm vi Adjuster, bạn vẫn sửa đổi Count (đó là một loại giá trị, không phải là một đối tượng). Do đó sự cần thiết cho mutating.

Tôi không thấy việc triển khai Foo, vì vậy tôi không thể nói chính xác tại sao thông báo lỗi cuối cùng, nhưng tôi đoán nó có cùng nguyên nhân gốc, nghĩa là các loại giá trị không phù hợp để thiết kế mẫu. Vì vậy, bạn có thể tốt hơn với các lớp học, không phải cấu trúc.

+0

Durh. Foo đáng lẽ phải là Count. Thay đổi rằng enroute của sao chép-dán. Đã sửa. –

+1

Ồ. Sau đó, nó thực sự là về sự khác biệt lớn b/w giá trị so với các loại tham chiếu. Chiến dịch loại giá trị của Apple không phải là một chén thánh thực sự. Trong tất cả mọi thứ trong quá khứ là các lớp/đối tượng, ngay cả những thứ tốt hơn là giá trị. Bây giờ chúng ta có giá trị, vì vậy bây giờ Apple đặt trọng tâm vào những giá trị đó. Tuy nhiên điều đó không làm cho các lớp/đối tượng đột nhiên vô dụng. Đặc biệt, các mẫu thiết kế là về lớp/đối tượng. Có lẽ, một số người khác có thể viết một cuốn sách khác về các mẫu thiết kế kiểu giá trị. – courteouselk

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