Вопрос

Это относительно распространенный шаблон проектирования:

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

Это позволяет вам возвращать подкласс из вашего init звонки.

Я пытаюсь найти наилучший метод достижения того же результата с помощью Swift.

Я точно знаю, что весьма вероятно, что существует лучший метод достижения того же самого с помощью Swift.Однако мой класс будет инициализирован существующей библиотекой Obj-C, над которой у меня нет контроля.Так что это действительно должно работать таким образом и быть вызываемым из Obj-C.

Любые указания были бы очень признательны.

Это было полезно?

Решение

Я не верю, что этот шаблон может быть напрямую поддерживается в SWIFT, потому что инициаторы не возвращают значение, поскольку они делают в объективном C - так что вы не получаете возможность вернуть альтернативный экземпляр объекта.

Вы можете использовать тип типа в качестве объекта завод - довольно натурный пример -

class Vehicle
{
    var wheels: Int? {
      get {
        return nil
      }
    }

    class func vehicleFactory(wheels:Int) -> Vehicle
    {
        var retVal:Vehicle

        if (wheels == 4) {
            retVal=Car()
        }
        else if (wheels == 18) {
            retVal=Truck()
        }
        else {
            retVal=Vehicle()
        }

        return retVal
    }

}

class Car:Vehicle
{
    override var wheels: Int {
      get {
       return 4
      }
    }
}

class Truck:Vehicle
{
    override var wheels: Int {
      get {
          return 18
       }
     }
}
.

main.swift

let c=Vehicle.vehicleFactory(4)     // c is a Car

println(c.wheels)                   // outputs 4

let t=Vehicle.vehicleFactory(18)    // t is a truck

println(t.wheels)                   // outputs 18
.

Другие советы

«Swifty» способ создания кластеров класса на самом деле будет подвергать протоколу вместо базового класса.

Видимо, компилятор запрещает статические функции на протоколах или расширении протокола.

до e.g. https://github.com/apple/sswift-evolution/pull/247 (Фабричные инициализаторы) принимаются и реализованы, единственный способ найти это следующее:

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)
.

С тех пор как init() не возвращает значения типа -init действительно ли в Objective C использование заводского метода кажется самым простым вариантом.

Один из трюков заключается в том, чтобы пометить ваши инициализаторы как private, вот так:

class Person : CustomStringConvertible {
    static func person(age: UInt) -> Person {
        if age < 18 {
            return ChildPerson(age)
        }
        else {
            return AdultPerson(age)
        }
    }

    let age: UInt
    var description: String { return "" }

    private init(_ age: UInt) {
        self.age = age
    }
}

extension Person {
    class ChildPerson : Person {
        let toyCount: UInt

        private override init(_ age: UInt) {
            self.toyCount = 5

            super.init(age)
        }

        override var description: String {
            return "\(self.dynamicType): I'm \(age). I have \(toyCount) toys!"
        }
    }

    class AdultPerson : Person {
        let beerCount: UInt

        private override init(_ age: UInt) {
            self.beerCount = 99

            super.init(age)
        }

        override var description: String {
            return "\(self.dynamicType): I'm \(age). I have \(beerCount) beers!"
        }
    }
}

Это приводит к следующему поведению:

Person.person(10) // "ChildPerson: I'm 10. I have 5 toys!"
Person.person(35) // "AdultPerson: I'm 35. I have 99 beers!"
Person(35) // 'Person' cannot be constructed because it has no accessible initializers
Person.ChildPerson(35) // 'Person.ChildPerson' cannot be constructed because it has no accessible initializers

Это не совсем так приятно, как Objective C, поскольку private означает, что все подклассы должны быть реализованы в одном и том же исходном файле, и в этом есть незначительная разница в синтаксисе Person.person(x) (или Person.create(x) или что-то еще) вместо того, чтобы просто Person(x), но, практически говоря, это работает так же.

Чтобы иметь возможность создавать экземпляры буквально как Person(x), ты мог бы повернуть Person в прокси-класс, который содержит частный экземпляр фактического базового класса и пересылает все в него.Без переадресации сообщений это работает для простых интерфейсов с несколькими свойствами / методами, но становится громоздким для чего-либо более сложного: P

Я думаю, что на самом деле шаблон кластера может быть реализован в Swift с использованием функций времени выполнения.Основной точкой является замена класса вашего нового объекта с подклассом при инициализации.Код ниже работает нормально, хотя я думаю, что больше внимания следует уделять инициализации подкласса.

class MyClass
{
    var name: String?

    convenience init(type: Int)
    {
        self.init()

        var subclass: AnyClass?
        if type == 1
        {
            subclass = MySubclass1.self
        }
        else if type == 2
        {
            subclass = MySubclass2.self
        }

        object_setClass(self, subclass)
        self.customInit()
    }

    func customInit()
    {
        // to be overridden
    }
}

class MySubclass1 : MyClass
{
    override func customInit()
    {
        self.name = "instance of MySubclass1"
    }
}

class MySubclass2 : MyClass
{
    override func customInit()
    {
        self.name = "instance of MySubclass2"
    }
}

let myObject1 = MyClass(type: 1)
let myObject2 = MyClass(type: 2)
println(myObject1.name)
println(myObject2.name)
.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top