The Iterator pattern provides a mechanism for traversing collections of objects without revealing their internal representation. Often this pattern is used instead of an array of objects to not only provide access to elements, but also provide some logic.
This pattern is used when:
The pattern operates with four entities:
It should be mentioned, that aggregate is optional.
The Python implementation is very short and simple, because Iterator type is included into standard library and supports inheritance.
import random
from collections.abc import Iterator
class PacketIterator(Iterator):
'''Represents iterator'''
def __init__(self) -> None:
self.__packets: list[bytearray] = []
self.__c = 0
def append(self, packet: bytearray):
self.__packets.append(packet)
def __next__(self) -> str:
if self.__c >= len(self.__packets):
raise StopIteration
p = self.__packets[self.__c]
self.__c += 1
return p.decode()
class Network:
'''Represents aggregate'''
def __iter__(self):
p = PacketIterator()
for i in range(random.randint(1, 20)):
p.append(bytearray(f"somepacket_{random.random() * 100}".encode()))
return p
def main():
network = Network()
for packet in network:
print(packet)
if __name__ == '__main__':
main()
package main
import (
"fmt"
"math/rand"
"time"
)
// Iterator provides a iterator interface.
type Iterator interface {
Next() bool
Value() any
}
// Aggregate provides a collection interface.
type Aggregate interface {
Iterator() Iterator
}
var _ Iterator = &PacketIterator{}
// Packet represents network packet.
type Packet []byte
type PacketIterator struct {
Packets []Packet
c int
}
// Next shows that iterator is not empty.
func (pi *PacketIterator) Next() bool {
return pi.c < len(pi.Packets)
}
// Value returns value at current iteration counter.
func (pi *PacketIterator) Value() any {
v := string(pi.Packets[pi.c])
pi.c++
return v
}
var _ Aggregate = &Network{}
// Network represents network.
type Network struct {
r *rand.Rand
}
// Iterator returns packet iterator.
func (n *Network) Iterator() Iterator {
j := n.r.Int() % 20
packets := make([]Packet, j)
for i := 0; i < j; i++ {
packets[i] = []byte(fmt.Sprintf("somepacket %v", n.r.Int63()))
}
return &PacketIterator{packets, 0}
}
func main() {
network := Network{rand.New(rand.NewSource(time.Now().UnixNano()))}
packetIterator := network.Iterator()
for packetIterator.Next() {
v := packetIterator.Value()
fmt.Println(v)
}
}