15

これは比較的一般的な設計パターンです。

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

呼び出しからサブクラスを返すことができますinit

Swift を使用して同じことを達成するための最良の方法を見つけようとしています。

Swiftで同じことを達成するためのより良い方法がある可能性が非常に高いことを私は知っています. ただし、私のクラスは、私が制御できない既存の Obj-C ライブラリによって初期化される予定です。したがって、このように動作し、Obj-C から呼び出せるようにする必要があります。

任意のポインタは非常に高く評価されます。

4

7 に答える 7

1

init()Objective C のように値を返さないため-init、ファクトリ メソッドを使用するのが最も簡単なオプションのようです。

private1 つのトリックは、次のようにイニシャライザを としてマークすることです。

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

于 2015-09-13T14:05:00.320 に答える
0

実際にクラスター パターンは、ランタイム関数を使用して 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)
于 2014-06-07T10:36:24.180 に答える
0

コンパイラの癖を利用できますself- プロトコル拡張で割り当てることが許可されています - https://forums.swift.org/t/assigning-to-self-in-protocol-extensions/4942

したがって、次のようなものを配置できます。

/// The sole purpose of this protocol is to allow reassigning `self`
fileprivate protocol ClusterClassProtocol { }

extension ClusterClassProtocol {
    init(reassigningSelfTo other: Self) {
        self = other
    }
}

/// This is the base class, the one that gets circulated in the public space
class ClusterClass: ClusterClassProtocol {
    
    convenience init(_ intVal: Int) {
        self.init(reassigningSelfTo: IntChild(intVal))
    }
    
    convenience init(_ stringVal: String) {
        self.init(reassigningSelfTo: StringChild(stringVal))
    }
}

/// Some private subclass part of the same cluster
fileprivate class IntChild: ClusterClass {
    init(_ intVal: Int) { }
}

/// Another private subclass, part of the same cluster
fileprivate class StringChild: ClusterClass {
    init(_ stringVal: String) { }
}

では、これを試してみましょう。

print(ClusterClass(10))    // IntChild
print(ClusterClass("abc")) // StringChild

これは Objective-C と同じように機能し、一部のクラス ( NSStringNSArray、 などNSDictionary) は、初期化時に指定された値に基づいて異なるサブクラスを返します。

于 2020-11-03T15:55:48.653 に答える