2015-05-12 17 views
5

Ok vì vậy tôi có một loạt các hàm trợ giúp trong dự án của tôi mà ban đầu tôi có trong một lớp có tên là Animate. Tôi đã tự hỏi những lợi ích của việc khai báo func vc class func là gì.Lợi ích của việc sử dụng lớp func vs func và không khai báo lớp

Cho phép sử dụng như một lớp dụ:

class Animate{ 
    func moveView(...){ 
     ... 
    } 
} 

Vì vậy, tôi tin rằng nếu tôi có một func lớp I không cần phải nhanh chóng lớp như vậy.

Animate.moveView(...)

Và nếu tôi chỉ cần khai báo hàm với func nó sẽ là:

Animate().moveView(...)

Tuy nhiên nếu tôi không khai báo các tập tin như là một lớp ở tất cả như vậy:

func moveView(...){ 
    ... 
} 

Khi tôi gọi chức năng, nó chỉ là:

moveView(...) 

Không có dấu hiệu cho thấy mã nguồn đến từ đâu và nó có thể được sử dụng như thế này ở bất kỳ đâu trong dự án.

Ưu và nhược điểm của ba cách này là gì? Không tuyên bố một lớp thực hành xấu? Hoặc, có một số trường hợp cạnh rằng điều này là rất hữu ích? Ví dụ trong tình huống của tôi, tôi không cần một lớp vì tôi chỉ tạo các hàm trợ giúp và không phải là một đối tượng.

Cảm ơn trước vì đã có thông tin chi tiết về điều này!

+0

trừ khi finc ở mvc địa phương, tôi thích các lớp học vì bạn biết họ đến từ đâu. hãy thử gỡ lỗi mã của người khác mà nó là một mashup và bạn không có đầu mối. –

Trả lời

9

Ok. Các phương thức thể hiện so với các phương thức lớp so với các phương thức toàn cầu.

(Phương pháp hạn và chức năng được hoán đổi. Phương pháp ngụ ý một chức năng được thực hiện bởi một đối tượng, vì vậy tôi có xu hướng thích các phương pháp hạn với chức năng hạn.)

Một phương pháp dụ là một phương pháp được thực hiện bởi các phiên bản của một lớp. Bạn phải có một cá thể của lớp đó để nói chuyện để gọi một phương thức cá thể.

Phương pháp thể hiện có quyền truy cập vào các biến mẫu của đối tượng mà chúng thuộc về, do đó đối tượng có thể lưu thông tin trạng thái giữa các cuộc gọi. (Trong lớp mạng, bạn có thể tạo nhiều đối tượng tải xuống, mỗi đối tượng quản lý tệp tải xuống riêng lẻ của một tệp khác từ một URL khác nhau và mỗi tệp có thể có một đại biểu khác nhau thông báo khi tải xuống hoàn tất)

được gọi bởi chính lớp đó, chứ không phải bởi một cá thể. Điều này có thể làm cho nó đơn giản để gọi các hàm trợ giúp mà không cần phải quản lý một đối tượng để làm việc đó cho bạn. Vì các phương thức lớp không nói đến một cá thể của lớp, chúng không thể bảo toàn thông tin trạng thái khác nhau cho mỗi đối tượng. Bạn có thể có một lớp tiện ích thực hiện các hàm địa phương hóa trên các chuỗi ví dụ. Quá trình bản địa hóa là khép kín. Bạn gọi một hàm lớp và truyền vào một chuỗi và ngôn ngữ mà bạn muốn nó được bản địa hóa, và nó đưa bạn trở lại kết quả. Không cần phải giữ trạng thái giữa các cuộc gọi. Cuộc gọi như vậy có thể trông giống như

let frenchString = 
    LocalizationUtils.localizeString("English String", 
    toLanguage: "French") 

Chức năng toàn cầu không thuộc bất kỳ lớp cụ thể nào. Chúng là toàn cầu cho toàn bộ mô-đun mà chúng được định nghĩa. Chúng tương tự như các hàm lớp, ngoại trừ chúng không dành riêng cho một lớp cụ thể.

+0

Vì vậy, theo ý kiến ​​của bạn, chức năng toàn cầu có mùi mã và tôi chỉ nên sử dụng các phương thức lớp thay thế? – Boid

+0

Không, cả 3 đều có vị trí của mình. Các hàm lớp có lợi thế là tạo ra một "không gian tên" rõ ràng cho các hàm để nhóm chúng lại với nhau một cách hợp lý. Quá tải toán tử trong Swift là một ví dụ về các hàm toàn cầu. Nếu bạn định nghĩa một toán tử "+" cho một lớp, nó phải là một hàm toàn cục để bạn có thể gọi nó trong bất kỳ ngữ cảnh nào. –

3

Tôi đồng ý với (và upvoted) câu trả lời của @ Duncan C, nhưng chỉ nghĩ rằng tôi sẽ ném vào một vài ưu/nhược điểm khác.

Tôi có xu hướng thích các chức năng toàn cầu so với các phương thức lớp vì các hàm toàn cục không làm lộn xộn các lớp của tôi. Tôi muốn giữ cho lớp học của tôi nạc và mỏng. Các chức năng toàn cầu có thể được lưu giữ trong một tệp riêng biệt mà tôi có thể sao chép và dán hoặc nhập vào một dự án cụ thể khi tôi cần chúng. Vì vậy, tôi có thể có một tập tin trong dự án của tôi được gọi là AnimateHelperFunctions đó chỉ là chức năng toàn cầu liên quan đến lớp đó. Một dự án cụ thể có thể chỉ cần một vài trong số họ, hoặc hầu hết trong số họ, hoặc những dự án cộng thêm một vài điều mà tôi khám phá ra tôi cần. Tôi có thể xóa những cái mà tôi không sử dụng trong một dự án cụ thể từ tệp để giữ cho tệp đó gọn gàng và cắt gọn. Tôi chỉ nghĩ rằng các chức năng toàn cục có nhiều mô-đun hơn và khuyến khích tôi đưa ra các nhiệm vụ đơn lẻ cho một chức năng duy nhất - một chức năng trợ giúp toàn cầu tốt thực hiện một điều và hoàn toàn có thể được trừu tượng hóa hoặc sử dụng chung và được sử dụng trong các ngữ cảnh khác. Bạn có thể có một dự án đôi khi bạn nhận ra bạn không cần lớp - bạn chỉ cần hàm trợ giúp của nó, và nó ở đó.

Tôi thích một trăm chức năng toàn cầu đơn giản mà tôi có thể chọn và chọn từ một lớp học cồng kềnh khổng lồ. Bạn có thể thực hiện nhiều điều tương tự với các phần mở rộng, tất nhiên, và ở một mức độ nào đó là vấn đề về hương vị, vì có rất ít sự khác biệt (bất kỳ?) Giữa các phương thức lớp và chức năng toàn cầu ngoại trừ việc sử dụng lớp phương pháp bạn phải kéo dọc theo toàn bộ lớp.

Không giống như tình trạng toàn cầu, không có bất kỳ mối nguy hiểm nào trong một chức năng toàn cầu. Chắc chắn, bất cứ ai cũng có thể gọi nó, nhưng điều này cũng đúng với các phương thức lớp, và hàm toàn cầu chỉ có thể hoạt động trên các đối số mà bạn truyền cho nó.

+0

Cảm ơn thông tin bổ sung :) – Boid

+0

Với tôi, có vẻ như bạn cần áp dụng tâm lý OOP nhiều hơn. Nó không phải là điểm chính của bạn là sai, nhưng một dự án OOP thiết kế tốt sẽ trông sạch hơn 100 lần và dễ dàng hơn để làm việc thông qua sau đó cùng một dự án với tất cả các chức năng toàn cầu cực kỳ sạch sẽ và hoàn hảo. Tôi có một dự án tôi tự quản lý với hơn 300 tệp và 200.000 dòng mã. Mỗi khi tôi thực hiện tái cấu trúc nghiêm túc, dự án luôn trông đẹp hơn, và nó trở nên OOP nhiều hơn. Tôi có 0 chức năng toàn cầu. Tôi có một vài chức năng tĩnh. Nếu tôi muốn tạo ra một hàm toàn cầu, nó gần như luôn luôn tốt hơn như một phần mở rộng cho một kiểu chung. – Sethmr

1

Đối với tôi, tôi sử dụng các phương pháp static hoặc class để kiểm soát thuộc tính cấp lớp hoặc nếu tôi phải trả về các phiên bản tùy chỉnh của số class hoặc sturct cụ thể đó. Ví dụ, ví dụ như tôi có dưới đây struct.

struct Person { 
    let firstName: String 
    let lastName: String 
} 

Bây giờ nếu tôi viết một số trường hợp kiểm tra, nơi mà tôi cần dụ Person 's khởi tạo với một tên cụ thể John trong nhiều lớp học thử nghiệm của tôi, tôi có thể tạo ra một helper static phương pháp.

extension Person { 
    static func john() -> Person { 
     return Person(firstName: "John", lastName: "Appleseed") 
    } 
} 

let john = Person.john() // I could also create a static property instead, but its a matter of personal choice and situation. 

Trong trường hợp trên, tôi có thể đã thực hiện john như chức năng toàn cầu cũng nhưng đối với tôi, nó sẽ rất mơ hồ và không thể đọc được.

Một địa điểm khác tôi có thể nghĩ ra nơi tôi thích phương pháp tĩnh đang trả về số lượng trường hợp cho số enum.

enum Mood { 
    case happy 
    case angry 
    case lazy 
    case high 

    static func count() -> Int { 
     return 4 
    } 
} 

Có những nơi, nơi tôi sử dụng các chức năng toàn cầu. Tôi sử dụng chức năng toàn cục để ghi nhật ký.

func log(screenEvent name: String) { 
    let tracker = GAI.sharedInstance().defaultTracker 
    tracker.set(kGAIScreenName, value: screenName) 
    let builder = GAIDictionaryBuilder.createScreenView() 
    tracker.send(builder.build() as [NSObject : AnyObject]) 
} 

Bên trong, phương pháp này là sử dụng một sharedInstance, tạo ra một phương pháp toàn cầu làm cho nó dễ dàng truy cập ở khắp mọi nơi trong các dự án giống như một hàm print mà các bản ghi đầu ra trong giao diện điều khiển, nhưng điều này là đăng nhập vào một số dịch vụ tùy chỉnh.

Một số chức năng toàn cầu khác mà tôi thường đưa vào dự án của mình là người trợ giúp GCD.

func delay(delay:Double, closure: dispatch_block_t) { 
    dispatch_after(
     dispatch_time(
      DISPATCH_TIME_NOW, 
      Int64(delay * Double(NSEC_PER_SEC)) 
     ), 
     dispatch_get_main_queue(), closure) 
} 


func backgroundTask(closure: dispatch_block_t) { 
    dispatch_async(dispatch_get_global_queue(QOS_CLASS_DEFAULT, 0), closure) 
} 

func mainThreadTask(closure: dispatch_block_t) { 
    dispatch_async(dispatch_get_main_queue(), closure) 
} 

Chức năng này không cần bất kỳ thông tin nào về lớp học để làm cho chúng trở nên toàn cầu thay vì gói chúng trong lớp.

Về phương thức instance, như được trả lời bởi @ Duncan C, chúng được gọi trên các trường hợp, khi bạn muốn duy trì trạng thái. Dưới đây ví dụ cho thấy cách sử dụng của cả hai phương pháp tĩnh và dụ.

enum TapType { 
    case water 
    case beer 
} 

struct Tap { 
    let tapType: TapType 

    //static method 
    static func unlimitedBeer() -> Tap { 
     let beer = Tap(tapType: .beer) 
     beer.turnOn(forDuration: Float.greatestFiniteMagnitude) 
     return beer 
    } 

    //instance method: will do operation on a particular instance of `Tap`. 
    func turnOn(forDuration duration: Float) { 
     //implementation 
    } 
} 

let unlimitedBeer = Tap.unlimitedBeer() 

Bạn luôn có thể sử dụng convenience initiliser để initilise một đối tượng với hành vi tùy chỉnh, nhưng một lần nữa, một vấn đề của sự lựa chọn. Trong ví dụ trên, tôi không thể nghĩ ra bất kỳ convenience bộ tạo hóa đơn nào cung cấp cho tôi bia không giới hạn.

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