Custom class clusters in Swift

前端 未结 7 2019
灰色年华
灰色年华 2020-12-02 00:04

This is a relatively common design pattern:

https://stackoverflow.com/a/17015041/743957

It allows you to return a subclass from your init calls.

7条回答
  •  情话喂你
    2020-12-02 00:23

    The "swifty" way of creating class clusters would actually be to expose a protocol instead of a base class.

    Apparently the compiler forbids static functions on protocols or protocol extensions.

    Until e.g. https://github.com/apple/swift-evolution/pull/247 (factory initializers) is accepted and implemented, the only way I could find to do this is the following:

    import Foundation
    
    protocol Building {
        func numberOfFloors() -> Int
    }
    
    func createBuilding(numberOfFloors numFloors: Int) -> Building? {
        switch numFloors {
        case 1...4:
            return SmallBuilding(numberOfFloors: numFloors)
        case 5...20:
            return BigBuilding(numberOfFloors: numFloors)
        case 21...200:
            return SkyScraper(numberOfFloors: numFloors)
        default:
            return nil
        }
    }
    
    private class BaseBuilding: Building {
        let numFloors: Int
    
        init(numberOfFloors:Int) {
            self.numFloors = numberOfFloors
        }
    
        func numberOfFloors() -> Int {
            return self.numFloors
        }
    }
    
    private class SmallBuilding: BaseBuilding {
    }
    
    private class BigBuilding: BaseBuilding {
    }
    
    private class SkyScraper: BaseBuilding {
    }
    

    .

    // this sadly does not work as static functions are not allowed on protocols.
    //let skyscraper = Building.create(numberOfFloors: 200)
    //let bigBuilding = Building.create(numberOfFloors: 15)
    //let smallBuilding = Building.create(numberOfFloors: 2)
    
    // Workaround:
    let skyscraper = createBuilding(numberOfFloors: 200)
    let bigBuilding = createBuilding(numberOfFloors: 15)
    let smallBuilding = createBuilding(numberOfFloors: 2)
    

提交回复
热议问题