[JAVA] Modèle de conception à essayer avec le modèle Swift-Iterator qui prend en charge Array et Dictionary

Manuel: une introduction aux modèles de conception appris dans le langage Java

J'ai acheté "Introduction aux modèles de conception appris en langage Java [^ 1]" par le professeur Hiroshi Yuki, qui est célèbre pour "Math Girl" [^ 2]. Puisque c'est une excellente opportunité, je vais prendre des notes d'étude tout en l'implémentant avec mon Swift habituel. Cet article a été créé en référence au "Chapitre 1 Iterator Counting One by One".

J'ai en quelque sorte réalisé la joie du modèle Iterator!

Quand j'ai touché pour la première fois au modèle Iterator (c'était un Iterator JavaScript), je n'avais aucune idée de ce qui me plaisait. Cette fois, je sens que j'ai en quelque sorte réalisé la joie du motif Iterator en déplaçant mes mains pour l'implémenter concrètement et en regardant le code source de la «séquence» et de la «carte» de Swift. J'espère que cela sera utile pour ceux qui ont des sentiments similaires!

Quel est le modèle Iterator?

Un modèle de conception utilisé lors de l'analyse d'une collection entière d'éléments en séquence, tels que Array et Dictionary. C'est une citation un peu longue, mais dans "Introduction aux modèles de conception appris en langage Java [^ 1]", il est expliqué comme suit.

Si i est incrémenté de 1 dans i ++ de l'instruction for, cela signifie que tous les éléments du tableau arr sont balayés dans l'ordre depuis le début. Dans le modèle de conception, la fonction de la variable i utilisée ici est abstraite et généralisée. Modèle d'itérateur Nous l'appelons>. Le modèle Iterator est destiné au traitement lorsque beaucoup de choses sont rassemblées, en les pointant dans l'ordre et en scannant le tout. Le mot anglais iterate signifie «répéter» quelque chose. [^ 3]

Caractères dans le modèle Iterator

Interface d'itérateur

L'interface du type qui analyse l'élément. Il semble qu'il existe différentes écoles, mais les protocoles suivants peuvent être considérés comme simples.

protocol MyIteratorProtocol {
    //Type d'élément détenu par le tableau, etc.
    associatedtype Element
    //Une méthode qui renvoie si l'élément suivant est présent
    func hasNext() -> Bool
    //Une méthode qui renvoie l'élément suivant lors d'un scan
    mutating func next() -> Element?
}

Interface agrégée

C'est une interface d'un type qui contient une collection de "quelque chose" comme un tableau ou un dictionnaire, et a une méthode pour générer un itérateur.

protocol AggregateProtocol {
    //Type d'élément détenu par le tableau, etc.
    associatedtype Element
    //Le type Iterator renvoyé par la méthode iterator, l'élément doit correspondre
    associatedtype Iterator: MyIteratorProtocol where Iterator.Element == Element
    //Méthode pour générer un itérateur
    func iterator() -> Iterator
}

ConcreteIterator / ConcreteAggregate

Ce sont des types concrets qui implémentent (conformes) l'interface Iterator et l'interface Aggregate.

Exemple spécifique: essayez d'implémenter le modèle Iterator

Ici, à titre d'exemple, nous allons implémenter le type BirdCage qui contient un ensemble de types Bird et son Iterator, le BirdCageIterator.

Bird

Une structure qui contient juste le nom.

Bird.swift


struct Bird {
    let name: String
}

BirdCage

Définit une structure qui contient un ensemble d'oiseaux. Implémentez la méthode d'itérateur en définissant l'alias associatedType pour se conformer au protocole d'agrégation. Pour plus de simplicité, nous garderons l'Oiseau défini comme un tableau.

BirdCage.swift


struct BirdCage: AggregateProtocol {
    //Définir un type spécifique pour associatedType
    typealias Element = Bird
    typealias Iterator = BirdCageIterator
    
    //Implémenter une méthode qui retourne un itérateur
    func iterator() -> Iterator {
        BirdCageIterator(birds: birds)
    }
    
    //Ici, nous conservons l'ensemble sous forme de tableau pour plus de simplicité
    private var birds: [Bird] = []
    
    //Méthode pour mettre l'oiseau en cage à oiseaux
    mutating func put(bird: Bird) {
        birds.append(bird)
    }
    
    //Spécifiez l'index et regardez l'oiseau
    func peek(birdOf index: Int) -> Bird? {
        index < birds.count ? birds[index] : nil
    }
}

BirdCateIterator

Définit un itérateur pour BirdCate. Implémentez la méthode hasNext / next en définissant l'alias associatedType pour se conformer à MyIteratorProtocol.

BirdCateIterator.swift


struct BirdCageIterator: MyIteratorProtocol {
    //Définir un type spécifique pour associatedType
    typealias Element = Bird

    //Tenez un tableau d'ensembles à analyser
    private let birds: [Bird]
    private var index: Int = 0
    
    init(birds: [Bird]) {
        self.birds = birds
    }
    
    func hasNext() -> Bool {
        index < birds.count
    }
    
    //Lorsque la méthode est appelée, avancez votre index d'une unité
    mutating func next() -> Bird? {
        let bird = index < birds.count ? birds[index] : nil
        index += 1
        return bird
    }
}

Essayez d'utiliser

Définissez et appelez une fonction qui imprime chaque élément de l'ensemble. Le but est de définir la fonction avec des paramètres de type comme ʻAggregate: AggregateProtocol. Les fonctions implémentées de cette manière peuvent être utilisées pour tous les types implémentés dans le modèle Iterator (types conformes à ʻAggregateProtocol).

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

Qu'est-ce qui vous satisfait du modèle Iterator?

Peut être utilisé indépendamment de l'implémentation spécifique (détails)

La fonction printElements mentionnée plus haut n'est pas implémentée pour le type BirdCage concret, mais pour le "ʻAggregate general" qui est conforme au "" Aggregate Protocol ". Ainsi, quelle que soit la manière dont le spécifique BirdCage ou BirdCageIterator implémente la méthode ʻiterator ou next, printElements peut utiliser l'argument ʻaggregate: Aggregate. Je peux le faire.

Utilisez printElements facilement

Pour profiter de cet avantage et utiliser printElements plus facilement, définissez printElements dans l'extension de ʻ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"))

//Vous pouvez appeler printElements à partir de n'importe quelle structure conforme au protocole d'agrégation!
cage.printElements()

Le modèle Iterator est également utilisé dans Array, Dictionary et String

Protocole d'itérateur standard Swift

En fait, Swift est livré en standard avec ʻIterator Protocol` [^ 4].

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

Protocole de séquence implémenté dans le modèle Iterator

Et le protocole Sequence, auquel se conforment diverses structures comme Array, Dictionary et String, utilise ʻIterator Protocol` en interne [^ 5].

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

La définition de cette partie est le ʻAggregate Protocol` lui-même créé dans cet article. Exactement ce protocole "Séquence" est implémenté en utilisant le modèle Iterator.

Iterator est également utilisé pour implémenter la carte

Par exemple, la méthode map, familière avec Array, est en fait implémentée dans l'extension du protocole Sequence. Par conséquent, vous pouvez appeler la méthode map non seulement pour Array et Range, mais aussi pour Dictionary et String.

[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() }

Et à l'intérieur de la méthode map, l'itérateur est utilisé [^ 6]. L'implémentation interne de Array, Dictionary, Range et String et l'implémentation d'itérateur défini dans chacun devraient être différentes, mais la méthode map peut être implémentée dans une implémentation via l'interface de ʻIterator Protocol`.

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

en conclusion

Avez-vous ressenti la joie du modèle Iterator? Restez à l'écoute pour le prochain modèle!

environnement

référence

[^ 1]: Introduction aux modèles de conception appris dans le langage Java augmenté et révisé [^ 2]: Depuis le 1er septembre 2020, la version Kindle est à moitié prix pendant les soldes d'été! [^ 3]: Édition révisée supplémentaire Introduction aux modèles de conception appris en langage Java Chapitre 1 Itérateur comptage un par un

Recommended Posts

Modèle de conception à essayer avec le modèle Swift-Iterator qui prend en charge Array et Dictionary
Essayez d'intégrer Ruby et Java avec Dapr
Introduction aux modèles de conception (introduction)
Introduction aux modèles de conception (Builder)
Introduction aux modèles de conception (composite)
Introduction aux modèles de conception (poids mouche)
Introduction au prototype de modèles de conception
Introduction aux modèles de conception (Iterator)
Introduction aux modèles de conception (stratégie)
[Rails] Comment introduire le kaminari avec Slim et changer le design
Exécutez logstash avec Docker et essayez de télécharger des données sur Elastic Cloud
Modèles de conception à utiliser avec les bibliothèques Java fréquemment utilisées - Modèle d'usine
Essayez de manipuler les tableaux PostgreSQL avec JDBC
Introduction aux modèles de conception (méthode d'usine)
Introduction aux modèles de conception (Abstract Factory)
Java, des tableaux pour débuter avec les débutants
Modèle de conception important pour améliorer la maintenabilité