Hàm Swift so với thuộc tính được tính


26

Nói rằng tôi có một lớp học Eventnhư sau:

class Event {
    private var attendees: [Person] = []

    // Case 1
    //*******
    // Should I use a func…
    func countOfAttendees() -> Int {
        return attendees.count
    }

    // …or a var
    var countOfAttendees: Int {
        return attendees.count
    }

    // Case 2
    //*******
    // Should I use a func…
    func countOfPaidAttendees() -> Int {
        return attendees.filter({$0.hasPaid}).count
    }

    // …or a var
    var countOfPaidAttendees: Int {
        return attendees.filter({$0.hasPaid}).count
    }
}

Có phải là cách tốt nhất để sử dụng các hàm hoặc thuộc tính được tính trong 2 trường hợp được chỉ ra ở trên?


2
stackoverflow.com/questions/24035276/ cấp ... Tóm lại: 'Hãy để các hàm của bạn là các hàm và các thuộc tính của bạn là các thuộc tính.'
Robert Harvey

Câu trả lời:


14

Thực hiện theo Nguyên tắc truy cập thống nhất ,

Tất cả các dịch vụ được cung cấp bởi một mô-đun nên có sẵn thông qua một ký hiệu thống nhất, không phản bội cho dù chúng được thực hiện thông qua lưu trữ hoặc thông qua tính toán

Đối với tôi, điều này có nghĩa là tôi không viết các hàm không có đối số và trả về giá trị. Tôi luôn luôn sử dụng các thuộc tính tính toán. Bằng cách đó, nếu sau này tôi quyết định thay đổi thuộc tính được tính thành thuộc tính được lưu trữ, tôi có thể làm như vậy mà không cần phải loại bỏ các dấu ngoặc ở mọi nơi trong ứng dụng của mình và không có phương thức "getter" riêng biệt chỉ trả về giá trị của một lưu trữ tài sản, có vẻ khá lãng phí IMHO.

Và nếu tôi thay đổi một thuộc tính được lưu trữ thành một thuộc tính được tính toán, tôi không phải thêm parens vào cuối của nó và ở mọi nơi mà nó được sử dụng trong ứng dụng.


Ban đầu tôi đã đi với câu trả lời phức tạp của @ Anton, nhưng trong thực tế tôi nhận ra rằng đây là cách tôi thực hiện nó theo các thuộc tính theo mặc định.
Ashley Mills

17

Tôi muốn nói rằng nó phụ thuộc vào độ phức tạp của tính toán so với tần suất sử dụng.

  • Nếu đó là O(1)/ *, sau đó sử dụng tài sản tính toán.
  • Nếu đó là O(N)+/ rare-use, sau đó sử dụng chức năng.
  • Nếu đó là O(N)+/ frequent-use, hãy nghĩ xem trong tương lai bạn có thể quyết định sử dụng bộ nhớ đệm hoặc các kỹ thuật "thông minh" khác để bù đắp cho sự phức tạp hay không, nếu "có" thì hãy sử dụng thuộc tính, nếu "không-không-không, thì chỉ là nặng" .

2
Thật buồn cười khi tôi bắt đầu thực hiện nó bằng cách sử dụng lý do tương tự. Nếu bạn "có thể" tạo cho nó ấn tượng là một tài sản, ngay cả khi bạn phải thực hiện một xử lý nhẹ, miễn là nó không thay đổi đối tượng, hãy biến nó thành một tài sản.
Doanh số Dielson

9

Gần đây tôi đã bắt đầu học Kotlin và họ có một kinh nghiệm tuyệt vời về việc khi nào nên sử dụng các thuộc tính được tính toán:

Hàm vs Thuộc tính

Trong một số trường hợp, các hàm không có đối số có thể thay thế được với các thuộc tính chỉ đọc. Mặc dù ngữ nghĩa là tương tự nhau, nhưng có một số quy ước về phong cách khi nào nên thích cái này hơn cái khác.

Thích một thuộc tính hơn một hàm khi thuật toán cơ bản:

  • không ném
  • có độ phức tạp O (1)
  • là giá rẻ để tính toán (hoặc được tính trong lần chạy đầu tiên)
  • trả về kết quả tương tự trên các yêu cầu

- https://kotlinlang.org/docs/reference/coding-conventions.html


'Không ném' cũng rất quan trọng đối với Swift vì các thuộc tính không thể ném (chưa?)
alejandromp

"có độ phức tạp O (1)" đã bị xóa khỏi tài liệu
Mahmoud Shahoud

7

Trong Swift, các hàm không có tham số và thuộc tính được tính có các khả năng gần như giống nhau (có thể có một sự khác biệt là hàm không có tham số cũng là một bao đóng, trong khi thuộc tính được tính toán thì không).

Sự khác biệt là về mặt ngữ nghĩa. Nếu mã của bạn thực hiện một hành động và trả về ví dụ mô tả về kết quả của hành động đó, thì tôi sẽ sử dụng một hàm. Nếu mã của bạn tính toán một thuộc tính nhưng theo quan điểm của người dùng thì đây có thể là một thuộc tính được lưu trữ hoặc có thể là một thuộc tính được lưu trữ yêu cầu cập nhật một số giá trị được lưu trong bộ nhớ cache trước, sau đó tôi sẽ sử dụng một thuộc tính được tính toán.

Một sự khác biệt lớn: Điều gì xảy ra nếu bạn gọi hàm hoặc thuộc tính được tính hai lần? Đối với một tài sản được tính toán, tôi hy vọng rằng x = property; y = property có hành vi chính xác giống như x = property; y = x ngoại trừ nó có thể chạy chậm hơn một chút. Đối với các chức năng, tôi sẽ không ngạc nhiên nếu hành vi khác nhau.


4

Sử dụng countOfAttendeescountOfPaidAttendees().


Biến được tính là biến trả về giá trị được tính mỗi lần truy cập. Đó là, nó không lưu trữ một giá trị. Trong nội bộ nó được thực hiện như là một chức năng.

Sự khác biệt với một chức năng là gì?

  • Về mặt ngữ nghĩa, một biến là trạng thái, một hàm là một hành động.
  • Một chức năng điều chỉnh truy cập vào lưu trữ riêng. Một biến được tính toán có thể làm tương tự theo cách nhỏ gọn hơn. Ví dụ .
  • Một biến được tính toán có thể được sử dụng với KVO, được chuyển dưới dạng #keypath và có các phương tiện để quan sát: will Set, did Set.

Bạn nên sử dụng một biến khi

  • nó không ném
  • nó trả về một tài sản đơn giản
  • nó không có tác dụng phụ hay động từ trong tên của nó
  • đó là O (1), nghĩa là, nó không phải chịu một chi phí đáng kể. Trong ví dụ của bạn, nó sẽ là O (n).
  • nó là bình thường Nhiều lệnh giống nhau trả về cùng một giá trị hoặc đặt đối tượng về cùng một trạng thái.

Những lý do không liên quan để thích một biến hơn một hàm

  • Một biến được tính toán giúp bạn không phải gõ (). Tuy nhiên, sự rõ ràng quan trọng hơn sự ngắn gọn, vì vậy đây là một lập luận yếu.
  • Một biến chỉ đọc có thể được ghi đè là đọc / ghi. Một hàm chỉ ra nó luôn luôn chỉ đọc. Tuy nhiên, Apple sử dụng các thuộc tính cho các biến chỉ đọc như mảng.count. Khi nghi ngờ tìm kiếm sự nhất quán với nền tảng.

Tài nguyên

Từ  WWDC 2014 - 204 Có gì mới trong Ca cao  > 24:40 Khi nào nên sử dụng @property

Sử dụng thuộc tính cho bất cứ điều gì liên quan đến giá trị hoặc trạng thái của một đối tượng hoặc mối quan hệ của nó với các đối tượng khác. Ứng cử viên xấu:

  • Các phương thức làm việc: tải, phân tích cú pháp, chuyển đổi, tầm. Họ có động từ trong tên của nó.
  • Trình tạo: init, copy, liệt kê, lỗi. Những phương pháp này không phải là idempotent.
  • Các phương thức thay đổi trạng thái: nextObject.

Từ  Phong cách Swift của Erica Sadun  > Thuộc tính được tính toán so với Phương thức

Một thuộc tính thể hiện chất lượng vốn có của một thể hiện, trong khi một phương thức thực hiện một hành động.

  • Các phương thức có tham số; tài sản không. Thích phương pháp cho bất kỳ cuộc gọi với tác dụng phụ. Nếu một phương thức làm một cái gì đó (ví dụ, nó tải, phân tích cú pháp, bật hoặc in) hoặc có một tên động từ, thì nó không phải là một thuộc tính.
  • Thích các thuộc tính cho các giá trị đơn giản mà bạn có thể nhận và / hoặc đặt.
  • Các thuộc tính phải thể hiện chất lượng nội tại ngữ nghĩa của một thể hiện loại.
  • Thuộc tính cho phép bạn thêm người quan sát thông qua will Set và did Set. Không giống như các thuộc tính được lưu trữ, các thuộc tính loại được lưu trữ phải luôn được cung cấp một giá trị mặc định.

Từ  quy ước mã hóa Kotlin> chức năng so với thuộc tính . Xem câu trả lời của Daniel ở trên .

Các tài nguyên khác không có thông tin liên quan:


3

Tôi sẽ sử dụng một func. Lập trình hướng đối tượng hoạt động tốt mà không cần tính toán. Bởi vì bạn đang nhận lại một giá trị đã được tính toán / lọc, một số có thể lập luận rằng một thuộc tính được tính toán cảm thấy đúng. Nhưng đây là khiếu nại của tôi, nếu bạn làm điều đó thì khả năng đọc sẽ bị ảnh hưởng, bởi vì nó cảm thấy như một giá trị.

Trong bối cảnh này, sẽ không có ý nghĩa gì khi cố gắng gán giá trị được tính toán (và may mắn là IDE giúp chúng ta tránh điều này) nhưng nếu tôi cố gắng gán một cái gì đó được tính toán nhưng trông giống như một giá trị thì sao?

event.countOfAttendees = 0; // not possible

Trong khi sử dụng func, người gọi biết rằng bạn không trực tiếp xử lý một giá trị:

event.countOfAttendees()

Tôi nghĩ rằng nếu nó là một đối tượng hành vi thì nó sẽ trông giống như nó hành xử chứ không phải trông giống như một cấu trúc dữ liệu. Nếu đối tượng của bạn bị câm và không có bất kỳ hành vi nào thì tại sao phải cố gắng gói gọn nó? Trong trường hợp đó, bạn cũng có thể có người tham dự được công khai

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.