سؤال

هذا هو نمط تصميم شائع نسبيا:

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

انها تسمح لك للعودة فئة فرعية من الخاص بك init المكالمات.

أحاول معرفة أفضل طريقة لتحقيق نفس الشيء باستخدام سويفت.

وأنا أعلم أنه من المحتمل جدا أن هناك طريقة أفضل لتحقيق نفس الشيء مع سويفت.ومع ذلك ، سيتم تهيئة صفي من قبل مكتبة أوبج-ج القائمة التي ليس لدي السيطرة على.لذلك تحتاج إلى العمل بهذه الطريقة وتكون قابلة للاستدعاء من أوبج-سي.

أي مؤشرات سيكون موضع تقدير كبير جدا.

هل كانت مفيدة؟

المحلول

لا أعتقد أن هذا النمط يمكن دعمه مباشرة في سويفت ، لأن إنيتياليسرز لا ترجع قيمة كما تفعل في الهدف ج - لذلك لا تحصل على فرصة لإرجاع مثيل كائن بديل.

يمكنك استخدام طريقة الكتابة كمصنع كائن-مثال مفتعل إلى حد ما هو -

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
       }
     }
}

الرئيسية.سويفت

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

نصائح أخرى

الطريقة" السريعة " لإنشاء مجموعات الصف ستكون في الواقع لفضح بروتوكول بدلا من فئة أساسية.

يبدو أن المترجم يحظر الوظائف الثابتة على البروتوكولات أو ملحقات البروتوكول.

حتى على سبيل المثال. https://github.com/apple/swift-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 هل في الهدف ج ، يبدو أن استخدام طريقة المصنع هو الخيار الأسهل.

إحدى الحيل هي وضع علامة على أدوات التهيئة الخاصة بك على أنها 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

إنه ليس لطيفا تماما مثل الهدف ج ، منذ ذلك الحين private يعني أنه يجب تنفيذ جميع الفئات الفرعية في نفس الملف المصدر ، وهناك اختلاف بسيط في بناء الجملة Person.person(x) (أو Person.create(x) أو أيا كان) بدلا من ببساطة Person(x), ، ولكن من الناحية العملية ، فإنه يعمل نفسه.

لتكون قادرة على إنشاء مثيل حرفيا كما Person(x), ، هل يمكن أن تتحول Person إلى فئة وكيل تحتوي على مثيل خاص للفئة الأساسية الفعلية وإعادة توجيه كل شيء إليها.بدون إعادة توجيه الرسائل ، يعمل هذا مع واجهات بسيطة ذات خصائص / طرق قليلة ولكنه يصبح غير عملي لأي شيء أكثر تعقيدا: ص

أعتقد في الواقع يمكن تنفيذ نمط الكتلة في سويفت باستخدام وظائف وقت التشغيل.النقطة الرئيسية هي استبدال فئة الكائن الجديد بفئة فرعية عند التهيئة.يعمل الرمز أدناه بشكل جيد على الرغم من أنني أعتقد أنه يجب إيلاء المزيد من الاهتمام لتهيئة الفئة الفرعية.

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