[JAVA] Entwerfen Sie ein Muster, um es mit dem Swift-Iterator-Muster zu versuchen, das Array und Dictionary unterstützt

Lehrbuch: Eine Einführung in Entwurfsmuster, die in der Java-Sprache gelernt wurden

Ich kaufte "Einführung in Designmuster, die in Java gelernt wurden [^ 1]" von Professor Hiroshi Yuki, der für "Math Girl" [^ 2] berühmt ist. Da dies eine großartige Gelegenheit ist, werde ich mir Notizen machen, während ich sie mit meinem üblichen Swift implementiere. Dieser Artikel wurde unter Bezugnahme auf "Kapitel 1 Iterator Zählen nacheinander" erstellt.

Ich habe irgendwie die Freude am Iteratormuster erkannt!

Als ich das Iterator-Muster zum ersten Mal berührte (es war ein JavaScript-Iterator), hatte ich keine Ahnung, worüber ich mich freute. Dieses Mal habe ich das Gefühl, dass ich die Freude am Iterator-Muster irgendwie erkannt habe, als ich meine Hände bewegte, um es konkret umzusetzen, und den Quellcode von Swifts "Sequenz" und "Karte" betrachtete. Ich hoffe, es wird für diejenigen hilfreich sein, die ähnliche Gefühle haben!

Was ist das Iteratormuster?

Ein Entwurfsmuster, das beim Scannen einer ganzen Sammlung von Dingen nacheinander verwendet wird, z. B. Array und Wörterbuch. Es ist ein etwas langes Zitat, aber in "Einführung in in Java-Sprache erlernte Entwurfsmuster [^ 1]" wird es wie folgt erklärt.

Wenn i in i ++ der for-Anweisung um 1 erhöht wird, bedeutet dies, dass die gesamten Elemente des Arrays arr von Anfang an in der richtigen Reihenfolge gescannt werden. Im Entwurfsmuster wird die Funktion der hier verwendeten Variablen i abstrahiert und verallgemeinert. Iteratormuster Wir nennen es>. Das Iterator-Muster dient zur Verarbeitung, wenn viele Dinge gesammelt werden, zeigt auf sie in der richtigen Reihenfolge und scannt das Ganze. Das englische Wort iterate bedeutet, etwas zu "wiederholen". [^ 3]

Zeichen im Iteratormuster

Iterator-Schnittstelle

Die Schnittstelle des Typs, der das Element scannt. Es scheint, dass es verschiedene Schulen gibt, aber das folgende Protokoll kann als einfach angesehen werden.

protocol MyIteratorProtocol {
    //Art des Elements, das vom Array usw. gehalten wird.
    associatedtype Element
    //Eine Methode, die zurückgibt, wenn das nächste Element vorhanden ist
    func hasNext() -> Bool
    //Eine Methode, die während eines Scans das nächste Element zurückgibt
    mutating func next() -> Element?
}

Aggregierte Schnittstelle

Es ist eine Schnittstelle eines Typs, die eine Sammlung von "etwas" wie ein Array oder ein Wörterbuch enthält und über eine Methode zum Generieren eines Iterators verfügt.

protocol AggregateProtocol {
    //Art des Elements, das vom Array usw. gehalten wird.
    associatedtype Element
    //Der von der Iteratormethode zurückgegebene Iteratortyp Element muss übereinstimmen
    associatedtype Iterator: MyIteratorProtocol where Iterator.Element == Element
    //Methode zum Generieren eines Iterators
    func iterator() -> Iterator
}

ConcreteIterator / ConcreteAggregate

Dies sind konkrete Typen, die die Iterator-Schnittstelle und die Aggregat-Schnittstelle implementieren (konform).

Spezifisches Beispiel: Versuchen Sie, das Iteratormuster zu implementieren

Hier werden wir als Beispiel den BirdCage-Typ implementieren, der eine Reihe von Bird-Typen enthält, und seinen Iterator, den BirdCageIterator.

Bird

Eine Struktur, die nur den Namen enthält.

Bird.swift


struct Bird {
    let name: String
}

BirdCage

Definiert eine Struktur, die eine Reihe von Vögeln enthält. Implementieren Sie die Iteratormethode, indem Sie den zugehörigen Typalias so einstellen, dass er dem Aggregatprotokoll entspricht. Der Einfachheit halber behalten wir das Bird-Set selbst als Array bei.

BirdCage.swift


struct BirdCage: AggregateProtocol {
    //Legen Sie einen bestimmten Typ für AssociatedType fest
    typealias Element = Bird
    typealias Iterator = BirdCageIterator
    
    //Implementieren Sie eine Methode, die einen Iterator zurückgibt
    func iterator() -> Iterator {
        BirdCageIterator(birds: birds)
    }
    
    //Hier behalten wir die Menge der Einfachheit halber als Array bei
    private var birds: [Bird] = []
    
    //Methode, um Vogel in Vogelkäfig zu setzen
    mutating func put(bird: Bird) {
        birds.append(bird)
    }
    
    //Geben Sie den Index an und sehen Sie sich den Vogel an
    func peek(birdOf index: Int) -> Bird? {
        index < birds.count ? birds[index] : nil
    }
}

BirdCateIterator

Definiert einen Iterator für BirdCate. Implementieren Sie die Methode hasNext / next, indem Sie den Alias "AssociatedType" so einstellen, dass er dem MyIteratorProtocol entspricht.

BirdCateIterator.swift


struct BirdCageIterator: MyIteratorProtocol {
    //
    typealias Element = Bird

    //
    private let birds: [Bird]
    private var index: Int = 0
    
    init(birds: [Bird]) {
        self.birds = birds
    }
    
    func hasNext() -> Bool {
        index < birds.count
    }
    
    //
    mutating func next() -> Bird? {
        let bird = index < birds.count ? birds[index] : nil
        index += 1
        return bird
    }
}

Wenn die Methode aufgerufen wird, die die Menge zum Scannen in einem Array enthält, erweitern Sie ihren eigenen Index um eins. Definieren und rufen Sie eine Funktion auf, die jedes Element der zu verwendenden Menge druckt. Der Punkt besteht darin, die Funktion mit Typparametern wie "Aggregate: AggregateProtocol" zu definieren. Auf diese Weise implementierte Funktionen können für alle im Iterator-Muster implementierten Typen verwendet werden (Typen, die dem "AggregateProtocol" entsprechen).

func printElements<Aggregate: AggregateProtocol>(of aggregate: Aggregate) {
    var iterator = aggregate.iterator()
    while iterator.hasNext() {
        let element = iterator.next()
        print(String(describing: element!))
    }
}

var cage = BirdCage()
cage.put(bird: Bird(name: "Budgerigar"))
cage.put(bird: Bird(name: "Cockatiel"))
cage.put(bird: Bird(name: "Parakeet"))
cage.put(bird: Bird(name: "Parrot"))

printElements(of: cage)

// Bird(name: "Budgerigar")
// Bird(name: "Cockatiel")
// Bird(name: "Parakeet")
// Bird(name: "Parrot")

Was macht Sie mit dem Iterator-Muster glücklich?

Kann unabhängig von der spezifischen Implementierung verwendet werden (Details)

Die zuvor erwähnte Funktion "printElements" ist nicht für den konkreten Typ "BirdCage" implementiert, sondern für "Aggregate" general "basierend auf" Aggregate Protocol ". Unabhängig davon, wie der spezifische "BirdCage" oder "BirdCageIterator" die "Iterator" - oder "next" -Methode implementiert, kann "printElements" das Argument "aggregate: Aggregate" verwenden. Ich kann es schaffen

Verwenden Sie printElements bequem

Um diesen Vorteil zu nutzen und "printElements" bequemer zu verwenden, definieren Sie "printElements" in der Erweiterung von "AggregateProtocol".

AggregateProtocol.swift


extension AggregateProtocol {
    func printEelements() {
        var iterator = self.iterator()
        while iterator.hasNext() {
            let element = iterator.next()
            print(String(describing: element!))
        }
    }
}

var cage = BirdCage()
cage.put(bird: Bird(name: "Budgerigar"))
cage.put(bird: Bird(name: "Cockatiel"))

//Sie können printElements von jeder Struktur aus aufrufen, die dem Aggregate Protocol entspricht!
cage.printElements()

Das Iteratormuster wird auch in Array, Dictionary und String verwendet

Schnelles Standard-Iterator-Protokoll

Tatsächlich hat Swift ein Standard-Iterator-Protokoll [^ 4].

public protocol IteratorProtocol {
    associatedtype Element
    mutating func next() -> Element?
}

Sequenzprotokoll im Iteratormuster implementiert

Und das "Sequence" -Protokoll, dem verschiedene Strukturen wie Array, Dictionary und String entsprechen, verwendet intern das "Iterator Protocol" [^ 5].

public protocol Sequence {
    associatedtype Element
    associatedtype Iterator: IteratorProtocol where Iterator.Element == Element
    __consuming func makeIterator() -> Iterator
    ...
}

Die Definition dieses Teils ist das in diesem Artikel selbst erstellte "Aggregate Protocol". Genau dieses "Sequenz" -Protokoll wird unter Verwendung des Iterator-Musters implementiert.

Iterator wird auch zum Implementieren der Karte verwendet

Beispielsweise ist die in Array bekannte "map" -Methode tatsächlich in der Erweiterung des "Sequence" -Protokolls implementiert. Daher können Sie die "map" -Methode nicht nur für Array und Range, sondern auch für Dictionary und String aufrufen.

[1, 2, 3].map { $0 + 1 }
(0...2).map { $0 * 2 }
["key1": 1, "key2": 2].map { (k, i) in i }
"Hello, world!".map { $0.uppercased() }

Und innerhalb der map -Methode wird der Iterator verwendet [^ 6]. Die interne Implementierung von Array, Dictionary, Range und String sowie die jeweils definierte Implementierung von Iterator sollten unterschiedlich sein, aber die "map" -Methode kann in einer Implementierung über die Schnittstelle von "IteratorProtocol" implementiert werden.

extension Sequence {
    ...
    @inlinable
    public func map<T>(
      _ transform: (Element) throws -> T
    ) rethrows -> [T] {
        let initialCapacity = underestimatedCount
        var result = ContiguousArray<T>()
        result.reserveCapacity(initialCapacity)

        var iterator = self.makeIterator()

        // Add elements up to the initial capacity without checking for regrowth.
        for _ in 0..<initialCapacity {
            result.append(try transform(iterator.next()!))
        }
        // Add remaining elements, if any.
        while let element = iterator.next() {
            result.append(try transform(element))
        }
        return Array(result)
    }
}

abschließend

Haben Sie die Freude am Iteratormuster gespürt? Bleib dran für das nächste Muster!

Umgebung

Referenz

[^ 1]: Einführung in Entwurfsmuster, die in der erweiterten und überarbeiteten Java-Sprache gelernt wurden [^ 2]: Ab dem 1. September 2020 ist die Kindle-Version während des Sommerschlussverkaufs zum halben Preis erhältlich! [^ 3]: Ergänzende überarbeitete Ausgabe Einführung in in Java gelernte Entwurfsmuster Kapitel 1 Iterator Zählen nacheinander

Recommended Posts

Entwerfen Sie ein Muster, um es mit dem Swift-Iterator-Muster zu versuchen, das Array und Dictionary unterstützt
Versuchen Sie, Ruby und Java in Dapr zu integrieren
Einführung in Entwurfsmuster (Einführung)
Einführung in Entwurfsmuster (Builder)
Einführung in Entwurfsmuster (Composite)
Einführung in Designmuster (Fliegengewicht)
Einführung in Entwurfsmuster Prototyp
Einführung in Entwurfsmuster (Iterator)
Einführung in Entwurfsmuster (Strategie)
[Rails] Wie man Kaminari mit Slim einführt und das Design ändert
Führen Sie logstash mit Docker aus und versuchen Sie, Daten in Elastic Cloud hochzuladen
Entwerfen Sie Muster für häufig verwendete Java-Bibliotheken - Fabrikmuster
Versuchen Sie, PostgreSQL-Arrays mit JDBC zu bearbeiten
Einführung in Entwurfsmuster (Factory-Methode)
Einführung in Design Patterns (Abstract Factory)
Java, Arrays für Anfänger
Wichtiges Entwurfsmuster zur Verbesserung der Wartbarkeit