From 2ad340f4c35c2ae535a9b957c4b07cc0cc2dde97 Mon Sep 17 00:00:00 2001 From: Wolf Date: Fri, 28 Jun 2024 15:09:48 +0100 Subject: [PATCH] More patterns (#3) * more patterns * typo --- README.md | 9 + docs/Abstract-Factory.md | 262 +++++++++++++++++++++++++++++ docs/Bridge.md | 301 +++++++++++++++++++++++++++++++++ docs/Command.md | 3 +- docs/Interpreter.md | 302 ++++++++++++++++++++++++++++++++++ docs/Mediator.md | 179 ++++++++++++++++++++ docs/Memento.md | 347 +++++++++++++++++++++++++++++++++++++++ docs/Prototype.md | 137 ++++++++++++++++ docs/State.md | 245 +++++++++++++++++++++++++++ docs/Template-Method.md | 165 +++++++++++++++++++ docs/Visitor.md | 247 ++++++++++++++++++++++++++++ 11 files changed, 2196 insertions(+), 1 deletion(-) create mode 100644 docs/Abstract-Factory.md create mode 100644 docs/Bridge.md create mode 100644 docs/Interpreter.md create mode 100644 docs/Mediator.md create mode 100644 docs/Memento.md create mode 100644 docs/Prototype.md create mode 100644 docs/State.md create mode 100644 docs/Template-Method.md create mode 100644 docs/Visitor.md diff --git a/README.md b/README.md index aebd59f..3a73b19 100644 --- a/README.md +++ b/README.md @@ -55,7 +55,9 @@ which it occurs is essential for choosing the most appropriate design pattern, u | Pattern | Description | | ------------------------------------------------------------------ | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| [Abstract Factory Pattern](docs/Abstract-Factory.md) | The abstract factory pattern provides an interface for creating families of related or dependent objects without specifying their concrete classes. | | [Adapter Pattern](docs/Adapter.md) | The adapter pattern allows incompatible interfaces to work together by converting the interface of one class into another expected by the client. | +| [Bridge Pattern](docs/Bridge.md) | The bridge pattern decouples an abstraction from its implementation so that the two can vary independently. | | [Builder Pattern](docs/Builder.md) | The builder pattern simplifies the construction of complex objects by separating the construction process from the final representation. | | [Chain of Responsibility Pattern](docs/Chain-of-Responsibility.md) | The chain of responsibility pattern delegates commands to a chain of processing objects, allowing multiple objects a chance to handle the request. | | [Command Pattern](docs/Command.md) | The command pattern encapsulates a request as an object, allowing for parameterization, queuing, logging, and supporting undoable operations. | @@ -64,11 +66,18 @@ which it occurs is essential for choosing the most appropriate design pattern, u | [Facade Pattern](docs/Facade.md) | The facade pattern provides a simplified interface to a complex subsystem, making it easier for clients to interact with the system. | | [Factory Pattern](docs/Factory.md) | The factory pattern defines an interface for creating objects but allows subclasses to alter the type of objects that will be created. | | [Flyweight Pattern](docs/Flyweight.md) | The flyweight pattern reduces the cost of creating and managing a large number of similar objects by sharing as much data as possible. | +| [Interpreter Pattern](docs/Interpreter.md) | The interpreter pattern defines a grammatical representation for a language and provides an interpreter to deal with this grammar. | | [Iterator Pattern](docs/Iterator.md) | The iterator pattern provides a way to access elements of an aggregate object sequentially without exposing its underlying representation. | +| [Mediator Pattern](docs/Mediator.md) | The mediator pattern defines an object that encapsulates how a set of objects interact, promoting loose coupling. | +| [Memento Pattern](docs/Memento.md) | The memento pattern captures and externalizes an object's internal state without violating encapsulation, so the object can be restored to this state later. | | [Observer Pattern](docs/Observer.md) | The observer pattern defines a one-to-many dependency so that when one object changes state, all its dependents are notified and updated automatically. | +| [Prototype Pattern](docs/Prototype.md) | The prototype pattern creates new objects by copying an existing object, known as the prototype. | | [Proxy Pattern](docs/Proxy.md) | The proxy pattern provides a surrogate or placeholder for another object to control access to it, enhancing control over the underlying object. | | [Singleton Pattern](docs/Singleton.md) | The singleton pattern ensures a class has only one instance and provides a global point of access to it, managing shared resources efficiently. | +| [State Pattern](docs/State.md) | The state pattern allows an object to alter its behaviour when its internal state changes, appearing as if the object changed its class. | | [Strategy Pattern](docs/Strategy.md) | The strategy pattern defines a family of algorithms, encapsulates each one, and makes them interchangeable, allowing the algorithm to vary independently from the clients that use it. | +| [Template Method Pattern](docs/Template-Method.md) | The template method pattern defines the skeleton of an algorithm, deferring some steps to subclasses. | +| [Visitor Pattern](docs/Visitor.md) | The visitor pattern separates an algorithm from the objects on which it operates, allowing new operations to be added without modifying the objects. |

diff --git a/docs/Abstract-Factory.md b/docs/Abstract-Factory.md new file mode 100644 index 0000000..245f973 --- /dev/null +++ b/docs/Abstract-Factory.md @@ -0,0 +1,262 @@ +## Abstract Factory Pattern + +The abstract factory pattern is a creational design pattern that allows the creation of objects without specifying their exact class. It +provides an interface for creating families of related or dependent objects, ensuring that the created objects are compatible. This pattern +promotes consistency among products and is particularly useful when the system needs to be independent of how its products are created, +composed, and represented. + +### Go Example + +```go +package main + +import "fmt" + +// AbstractFactory +type ShoeFactory interface { + MakeShoe() Shoe +} + +// ConcreteFactory1 +type NikeFactory struct{} + +func (n *NikeFactory) MakeShoe() Shoe { + return &NikeShoe{} +} + +// ConcreteFactory2 +type AdidasFactory struct{} + +func (a *AdidasFactory) MakeShoe() Shoe { + return &AdidasShoe{} +} + +// AbstractProduct +type Shoe interface { + GetLogo() string +} + +// ConcreteProduct1 +type NikeShoe struct{} + +func (n *NikeShoe) GetLogo() string { + return "Nike" +} + +// ConcreteProduct2 +type AdidasShoe struct{} + +func (a *AdidasShoe) GetLogo() string { + return "Adidas" +} + +func main() { + nikeFactory := &NikeFactory{} + adidasFactory := &AdidasFactory{} + + nikeShoe := nikeFactory.MakeShoe() + adidasShoe := adidasFactory.MakeShoe() + + fmt.Println(nikeShoe.GetLogo()) // Output: Nike + fmt.Println(adidasShoe.GetLogo()) // Output: Adidas +} +``` + +### Perl Example + +```perl +package ShoeFactory; + +use strict; +use warnings; + +sub make_shoe { die "Abstract method" } + +package NikeFactory; +use parent 'ShoeFactory'; + +sub make_shoe { + return NikeShoe->new(); +} + +package AdidasFactory; +use parent 'ShoeFactory'; + +sub make_shoe { + return AdidasShoe->new(); +} + +package Shoe; + +sub get_logo { die "Abstract method" } + +package NikeShoe; +use parent 'Shoe'; + +sub new { bless {}, shift } + +sub get_logo { return "Nike" } + +package AdidasShoe; +use parent 'Shoe'; + +sub new { bless {}, shift } + +sub get_logo { return "Adidas" } + +package main; + +my $nike_factory = NikeFactory->new(); +my $adidas_factory = AdidasFactory->new(); + +my $nike_shoe = $nike_factory->make_shoe(); +my $adidas_shoe = $adidas_factory->make_shoe(); + +print $nike_shoe->get_logo(), "\n"; # Output: Nike +print $adidas_shoe->get_logo(), "\n"; # Output: Adidas +``` + +### Python Example + +```python +from abc import ABC, abstractmethod + +class Shoe(ABC): + @abstractmethod + def get_logo(self): + pass + +class NikeShoe(Shoe): + def get_logo(self): + return "Nike" + +class AdidasShoe(Shoe): + def get_logo(self): + return "Adidas" + +class ShoeFactory(ABC): + @abstractmethod + def make_shoe(self): + pass + +class NikeFactory(ShoeFactory): + def make_shoe(self): + return NikeShoe() + +class AdidasFactory(ShoeFactory): + def make_shoe(self): + return AdidasShoe() + +nike_factory = NikeFactory() +adidas_factory = AdidasFactory() + +nike_shoe = nike_factory.make_shoe() +adidas_shoe = adidas_factory.make_shoe() + +print(nike_shoe.get_logo()) # Output: Nike +print(adidas_shoe.get_logo()) # Output: Adidas +``` + +### Ruby Example + +```ruby +class Shoe + def get_logo + raise 'Abstract method' + end +end + +class NikeShoe < Shoe + def get_logo + 'Nike' + end +end + +class AdidasShoe < Shoe + def get_logo + 'Adidas' + end +end + +class ShoeFactory + def make_shoe + raise 'Abstract method' + end +end + +class NikeFactory < ShoeFactory + def make_shoe + NikeShoe.new + end +end + +class AdidasFactory < ShoeFactory + def make_shoe + AdidasShoe.new + end +end + +nike_factory = NikeFactory.new +adidas_factory = AdidasFactory.new + +nike_shoe = nike_factory.make_shoe +adidas_shoe = adidas_factory.make_shoe + +puts nike_shoe.get_logo # Output: Nike +puts adidas_shoe.get_logo # Output: Adidas +``` + +### Rust Example + +```rust +trait Shoe { + fn get_logo(&self) -> &str; +} + +struct NikeShoe; + +impl Shoe for NikeShoe { + fn get_logo(&self) -> &str { + "Nike" + } +} + +struct AdidasShoe; + +impl Shoe for AdidasShoe { + fn get_logo(&self) -> &str { + "Adidas" + } +} + +trait ShoeFactory { + fn make_shoe(&self) -> Box; +} + +struct NikeFactory; + +impl ShoeFactory for NikeFactory { + fn make_shoe(&self) -> Box { + Box::new(NikeShoe) + } +} + +struct AdidasFactory; + +impl ShoeFactory for AdidasFactory { + fn make_shoe(&self) -> Box { + Box::new(AdidasShoe) + } +} + +fn main() { + let nike_factory = NikeFactory; + let adidas_factory = AdidasFactory; + + let nike_shoe = nike_factory.make_shoe(); + let adidas_shoe = adidas_factory.make_shoe(); + + println!("{}", nike_shoe.get_logo()); // Output: Nike + println!("{}", adidas_shoe.get_logo()); // Output: Adidas +} +``` diff --git a/docs/Bridge.md b/docs/Bridge.md new file mode 100644 index 0000000..332a486 --- /dev/null +++ b/docs/Bridge.md @@ -0,0 +1,301 @@ +## Bridge Pattern + +The bridge pattern is a structural design pattern that decouples an abstraction from its implementation, allowing the two to vary independently. +This pattern involves an abstraction and an implementation class, with a bridge interface connecting them. By separating the abstraction from its +implementation, the bridge pattern promotes flexibility and extensibility, enabling different implementations to be swapped or extended without +affecting the abstraction. + +### Go Example + +```go +package main + +import "fmt" + +// Implementor +type Device interface { + On() + Off() +} + +// Concrete Implementor 1 +type TV struct{} + +func (t *TV) On() { + fmt.Println("TV is On") +} + +func (t *TV) Off() { + fmt.Println("TV is Off") +} + +// Concrete Implementor 2 +type Radio struct{} + +func (r *Radio) On() { + fmt.Println("Radio is On") +} + +func (r *Radio) Off() { + fmt.Println("Radio is Off") +} + +// Abstraction +type RemoteControl struct { + device Device +} + +func (r *RemoteControl) TurnOn() { + r.device.On() +} + +func (r *RemoteControl) TurnOff() { + r.device.Off() +} + +func main() { + tv := &TV{} + radio := &Radio{} + + tvRemote := &RemoteControl{device: tv} + radioRemote := &RemoteControl{device: radio} + + tvRemote.TurnOn() // Output: TV is On + tvRemote.TurnOff() // Output: TV is Off + radioRemote.TurnOn() // Output: Radio is On + radioRemote.TurnOff() // Output: Radio is Off +} +``` + +### Perl Example + +```perl +package Device; + +use strict; +use warnings; + +sub on { die "Abstract method" } +sub off { die "Abstract method" } + +package TV; +use parent 'Device'; + +sub on { + print "TV is On\n"; +} + +sub off { + print "TV is Off\n"; +} + +package Radio; +use parent 'Device'; + +sub on { + print "Radio is On\n"; +} + +sub off { + print "Radio is Off\n"; +} + +package RemoteControl; + +sub new { + my ($class, $device) = @_; + return bless { device => $device }, $class; +} + +sub turn_on { + my $self = shift; + $self->{device}->on(); +} + +sub turn_off { + my $self = shift; + $self->{device}->off(); +} + +package main; + +my $tv = TV->new(); +my $radio = Radio->new(); + +my $tv_remote = RemoteControl->new($tv); +my $radio_remote = RemoteControl->new($radio); + +$tv_remote->turn_on(); # Output: TV is On +$tv_remote->turn_off(); # Output: TV is Off +$radio_remote->turn_on(); # Output: Radio is On +$radio_remote->turn_off(); # Output: Radio is Off +``` + +### Python Example + +```python +class Device: + def on(self): + raise NotImplementedError + + def off(self): + raise NotImplementedError + +class TV(Device): + def on(self): + print("TV is On") + + def off(self): + print("TV is Off") + +class Radio(Device): + def on(self): + print("Radio is On") + + def off(self): + print("Radio is Off") + +class RemoteControl: + def __init__(self, device): + self.device = device + + def turn_on(self): + self.device.on() + + def turn_off(self): + self.device.off() + +tv = TV() +radio = Radio() + +tv_remote = RemoteControl(tv) +radio_remote = RemoteControl(radio) + +tv_remote.turn_on() # Output: TV is On +tv_remote.turn_off() # Output: TV is Off +radio_remote.turn_on() # Output: Radio is On +radio_remote.turn_off() # Output: Radio is Off +``` + +### Ruby Example + +```ruby +class Device + def on + raise 'Abstract method' + end + + def off + raise 'Abstract method' + end +end + +class TV < Device + def on + puts 'TV is On' + end + + def off + puts 'TV is Off' + end +end + +class Radio < Device + def on + puts 'Radio is On' + end + + def off + puts 'Radio is Off' + end +end + +class RemoteControl + def initialize(device) + @device = device + end + + def turn_on + @device.on + end + + def turn_off + @device.off + end +end + +tv = TV.new +radio = Radio.new + +tv_remote = RemoteControl.new(tv) +radio_remote = RemoteControl.new(radio) + +tv_remote.turn_on # Output: TV is On +tv_remote.turn_off # Output: TV is Off +radio_remote.turn_on # Output: Radio is On +radio_remote.turn_off # Output: Radio is Off +``` + +### Rust Example + +```rust +trait Device { + fn on(&self); + fn off(&self); +} + +struct TV; + +impl Device for TV { + fn on(&self) { + println!("TV is On"); + } + + fn off(&self) { + println!("TV is Off"); + } +} + +struct Radio; + +impl Device for Radio { + fn on(&self) { + println!("Radio is On"); + } + + fn off(&self) { + println!("Radio is Off"); + } +} + +struct RemoteControl { + device: Box, +} + +impl RemoteControl { + fn new(device: Box) -> Self { + RemoteControl { device } + } + + fn turn_on(&self) { + self.device.on(); + } + + fn turn_off(&self) { + self.device.off(); + } +} + +fn main() { + let tv = Box::new(TV); + let radio = Box::new(Radio); + + let tv_remote = RemoteControl::new(tv); + let radio_remote = RemoteControl::new(radio); + + tv_remote.turn_on(); // Output: TV is On + tv_remote.turn_off(); // Output: TV is Off + radio_remote.turn_on(); // Output: Radio is On + radio_remote.turn_off(); // Output: Radio is Off +} +``` diff --git a/docs/Command.md b/docs/Command.md index 2fc31d0..14750b2 100644 --- a/docs/Command.md +++ b/docs/Command.md @@ -104,7 +104,8 @@ my $light = Light->new(); my $light_on_command = LightOnCommand->new($light); my $remote = RemoteControl->new(); $remote->set_command($light_on_command); -$remote->press_button();``` +$remote->press_button(); +``` ### Python Example diff --git a/docs/Interpreter.md b/docs/Interpreter.md new file mode 100644 index 0000000..7c53b42 --- /dev/null +++ b/docs/Interpreter.md @@ -0,0 +1,302 @@ +## Interpreter Pattern + +The interpreter pattern is a behavioural design pattern that defines a grammatical representation for a language and provides an interpreter +to interpret sentences in the language. This pattern is useful for designing a language interpreter or compiler. It involves defining a +class hierarchy representing the grammar of the language and implementing an interpret method to process the language. The interpreter pattern +is particularly useful for simple languages or expressions that need to be evaluated dynamically. + +### Go Example + +```go +package main + +import ( + "fmt" + "strings" +) + +// Expression +type Expression interface { + Interpret(context string) bool +} + +// TerminalExpression +type TerminalExpression struct { + data string +} + +func (t *TerminalExpression) Interpret(context string) bool { + return strings.Contains(context, t.data) +} + +// OrExpression +type OrExpression struct { + expr1, expr2 Expression +} + +func (o *OrExpression) Interpret(context string) bool { + return o.expr1.Interpret(context) || o.expr2.Interpret(context) +} + +// AndExpression +type AndExpression struct { + expr1, expr2 Expression +} + +func (a *AndExpression) Interpret(context string) bool { + return a.expr1.Interpret(context) && a.expr2.Interpret(context) +} + +func main() { + robert := &TerminalExpression{data: "Robert"} + john := &TerminalExpression{data: "John"} + + isSingle := &OrExpression{expr1: robert, expr2: john} + + julie := &TerminalExpression{data: "Julie"} + married := &TerminalExpression{data: "Married"} + + isMarriedWoman := &AndExpression{expr1: julie, expr2: married} + + fmt.Println("John is single? ", isSingle.Interpret("John")) // Output: John is single? true + fmt.Println("Julie is a married woman? ", isMarriedWoman.Interpret("Married Julie")) // Output: Julie is a married woman? true +} +``` + +### Perl Example + +```perl +package Expression; + +sub interpret { + die "Abstract method"; +} + +package TerminalExpression; +use parent 'Expression'; + +sub new { + my ($class, $data) = @_; + return bless { data => $data }, $class; +} + +sub interpret { + my ($self, $context) = @_; + return index($context, $self->{data}) != -1; +} + +package OrExpression; +use parent 'Expression'; + +sub new { + my ($class, $expr1, $expr2) = @_; + return bless { expr1 => $expr1, expr2 => $expr2 }, $class; +} + +sub interpret { + my ($self, $context) = @_; + return $self->{expr1}->interpret($context) || $self->{expr2}->interpret($context); +} + +package AndExpression; +use parent 'Expression'; + +sub new { + my ($class, $expr1, $expr2) = @_; + return bless { expr1 => $expr1, expr2 => $expr2 }, $class; +} + +sub interpret { + my ($self, $context) = @_; + return $self->{expr1}->interpret($context) && $self->{expr2}->interpret($context); +} + +package main; + +my $robert = TerminalExpression->new("Robert"); +my $john = TerminalExpression->new("John"); + +my $is_single = OrExpression->new($robert, $john); + +my $julie = TerminalExpression->new("Julie"); +my $married = TerminalExpression->new("Married"); + +my $is_married_woman = AndExpression->new($julie, $married); + +print "John is single? ", $is_single->interpret("John") ? "true" : "false", "\n"; # Output: John is single? true +print "Julie is a married woman? ", $is_married_woman->interpret("Married Julie") ? "true" : "false", "\n"; # Output: Julie is a married woman? true +``` + +### Python Example + +```python +class Expression: + def interpret(self, context): + pass + +class TerminalExpression(Expression): + def __init__(self, data): + self.data = data + + def interpret(self, context): + return self.data in context + +class OrExpression(Expression): + def __init__(self, expr1, expr2): + self.expr1 = expr1 + self.expr2 = expr2 + + def interpret(self, context): + return self.expr1.interpret(context) or self.expr2.interpret(context) + +class AndExpression(Expression): + def __init__(self, expr1, expr2): + self.expr1 = expr1 + self.expr2 = expr2 + + def interpret(self, context): + return self.expr1.interpret(context) and self.expr2.interpret(context) + +robert = TerminalExpression("Robert") +john = TerminalExpression("John") + +is_single = OrExpression(robert, john) + +julie = TerminalExpression("Julie") +married = TerminalExpression("Married") + +is_married_woman = AndExpression(julie, married) + +print("John is single? ", is_single.interpret("John")) # Output: John is single? true +print("Julie is a married woman? ", is_married_woman.interpret("Married Julie")) # Output: Julie is a married woman? true +``` + +### Ruby Example + +```ruby +class Expression + def interpret(context) + raise 'Abstract method' + end +end + +class TerminalExpression < Expression + def initialize(data) + @data = data + end + + def interpret(context) + context.include?(@data) + end +end + +class OrExpression < Expression + def initialize(expr1, expr2) + @expr1 = expr1 + @expr2 = expr2 + end + + def interpret(context) + @expr1.interpret(context) || @expr2.interpret(context) + end +end + +class AndExpression < Expression + def initialize(expr1, expr2) + @expr1 = expr1 + @expr2 = expr2 + end + + def interpret(context) + @expr1.interpret(context) && @expr2.interpret(context) + end +end + +robert = TerminalExpression.new("Robert") +john = TerminalExpression.new("John") + +is_single = OrExpression.new(robert, john) + +julie = TerminalExpression.new("Julie") +married = TerminalExpression.new("Married") + +is_married_woman = AndExpression.new(julie, married) + +puts "John is single? #{is_single.interpret("John")}" # Output: John is single? true +puts "Julie is a married woman? #{is_married_woman.interpret("Married Julie")}" # Output: Julie is a married woman? true +``` + +### Rust Example + +```rust +trait Expression { + fn interpret(&self, context: &str) -> bool; +} + +struct TerminalExpression { + data: String, +} + +impl TerminalExpression { + fn new(data: &str) -> Self { + TerminalExpression { + data: data.to_string(), + } + } +} + +impl Expression for TerminalExpression { + fn interpret(&self, context: &str) -> bool { + context.contains(&self.data) + } +} + +struct OrExpression { + expr1: Box, + expr2: Box, +} + +impl OrExpression { + fn new(expr1: Box, expr2: Box) -> Self { + OrExpression { expr1, expr2 } + } +} + +impl Expression for OrExpression { + fn interpret(&self, context: &str) -> bool { + self.expr1.interpret(context) || self.expr2.interpret(context) + } +} + +struct AndExpression { + expr1: Box, + expr2: Box, +} + +impl AndExpression { + fn new(expr1: Box, expr2: Box) -> Self { + AndExpression { expr1, expr2 } + } +} + +impl Expression for AndExpression { + fn interpret(&self, context: &str) -> bool { + self.expr1.interpret(context) && self.expr2.interpret(context) + } +} + +fn main() { + let robert = Box::new(TerminalExpression::new("Robert")); + let john = Box::new(TerminalExpression::new("John")); + + let is_single = OrExpression::new(robert, john); + + let julie = Box::new(TerminalExpression::new("Julie")); + let married = Box::new(TerminalExpression::new("Married")); + + let is_married_woman = AndExpression::new(julie, married); + + println!("John is single? {}", is_single.interpret("John")); // Output: John is single? true + println!("Julie is a married woman? {}", is_married_woman.interpret("Married Julie")); // Output: Julie is a married woman? true +} +``` diff --git a/docs/Mediator.md b/docs/Mediator.md new file mode 100644 index 0000000..79fdfbb --- /dev/null +++ b/docs/Mediator.md @@ -0,0 +1,179 @@ +## Mediator Pattern + +The mediator pattern is a behavioural design pattern that defines an object, known as the mediator, which encapsulates how a set of objects +interact. This pattern promotes loose coupling by preventing objects from referring to each other explicitly. Instead, they communicate +through the mediator, which controls the interactions. The mediator pattern simplifies the maintenance and modification of interactions +between objects, making it easier to manage complex dependencies and enhance reusability. + +### Go Example + +```go +package main + +import "fmt" + +// Mediator +type Mediator interface { + ShowMessage(user *User, message string) +} + +// ConcreteMediator +type ChatRoom struct{} + +func (c *ChatRoom) ShowMessage(user *User, message string) { + fmt.Printf("%s: %s\n", user.GetName(), message) +} + +// Colleague +type User struct { + name string + mediator Mediator +} + +func (u *User) GetName() string { + return u.name +} + +func (u *User) SendMessage(message string) { + u.mediator.ShowMessage(u, message) +} + +func main() { + chatRoom := &ChatRoom{} + + user1 := &User{name: "Alice", mediator: chatRoom} + user2 := &User{name: "Bob", mediator: chatRoom} + + user1.SendMessage("Hi, Bob!") // Output: Alice: Hi, Bob! + user2.SendMessage("Hello, Alice!") // Output: Bob: Hello, Alice! +} +``` + +### Perl Example + +```perl +package Mediator; + +sub show_message { + die "Abstract method"; +} + +package ChatRoom; +use parent 'Mediator'; + +sub show_message { + my ($self, $user, $message) = @_; + print $user->get_name(), ": ", $message, "\n"; +} + +package User; + +sub new { + my ($class, $name, $mediator) = @_; + return bless { name => $name, mediator => $mediator }, $class; +} + +sub get_name { + my $self = shift; + return $self->{name}; +} + +sub send_message { + my ($self, $message) = @_; + $self->{mediator}->show_message($self, $message); +} + +package main; + +my $chat_room = ChatRoom->new(); + +my $user1 = User->new("Alice", $chat_room); +my $user2 = User->new("Bob", $chat_room); + +$user1->send_message("Hi, Bob!"); # Output: Alice: Hi, Bob! +$user2->send_message("Hello, Alice!"); # Output: Bob: Hello, Alice! +``` + +### Python Example + +```python +class ChatRoom: + @staticmethod + def show_message(user, message): + print(f"{user.name}: {message}") + +class User: + def __init__(self, name): + self.name = name + + def send_message(self, message): + ChatRoom.show_message(self, message) + +user1 = User("Alice") +user2 = User("Bob") + +user1.send_message("Hi, Bob!") # Output: Alice: Hi, Bob! +user2.send_message("Hello, Alice!") # Output: Bob: Hello, Alice! +``` + +### Ruby Example + +```ruby +class ChatRoom + def self.show_message(user, message) + puts "#{user.name}: #{message}" + end +end + +class User + attr_reader :name + + def initialize(name) + @name = name + end + + def send_message(message) + ChatRoom.show_message(self, message) + end +end + +user1 = User.new("Alice") +user2 = User.new("Bob") + +user1.send_message("Hi, Bob!") # Output: Alice: Hi, Bob! +user2.send_message("Hello, Alice!") # Output: Bob: Hello, Alice! +``` + +### Rust Example + +```rust +struct ChatRoom; + +impl ChatRoom { + fn show_message(user: &User, message: &str) { + println!("{}: {}", user.name, message); + } +} + +struct User<'a> { + name: &'a str, +} + +impl<'a> User<'a> { + fn new(name: &'a str) -> Self { + User { name } + } + + fn send_message(&self, message: &str) { + ChatRoom::show_message(self, message); + } +} + +fn main() { + let user1 = User::new("Alice"); + let user2 = User::new("Bob"); + + user1.send_message("Hi, Bob!"); // Output: Alice: Hi, Bob! + user2.send_message("Hello, Alice!"); // Output: Bob: Hello, Alice! +} +``` diff --git a/docs/Memento.md b/docs/Memento.md new file mode 100644 index 0000000..55d8c4d --- /dev/null +++ b/docs/Memento.md @@ -0,0 +1,347 @@ +## Memento Pattern + +The memento pattern is a behavioural design pattern that captures and externalizes an object's internal state without violating encapsulation, +allowing the object to be restored to this state later. This pattern is useful for implementing undo/redo functionality. It involves creating +a memento object that stores the state of the originator object and providing methods to save and restore the state. The memento pattern ensures +that the object's state can be rolled back or restored without exposing its internal structure. + +### Go Example + +```go +package main + +import "fmt" + +// Memento +type Memento struct { + state string +} + +// Originator +type Originator struct { + state string +} + +func (o *Originator) SetState(state string) { + o.state = state +} + +func (o *Originator) SaveStateToMemento() *Memento { + return &Memento{state: o.state} +} + +func (o *Originator) GetStateFromMemento(memento *Memento) { + o.state = memento.state +} + +func (o *Originator) GetState() string { + return o.state +} + +// Caretaker +type Caretaker struct { + mementoList []*Memento +} + +func (c *Caretaker) Add(memento *Memento) { + c.mementoList = append(c.mementoList, memento) +} + +func (c *Caretaker) Get(index int) *Memento { + return c.mementoList[index] +} + +func main() { + originator := &Originator{} + caretaker := &Caretaker{} + + originator.SetState("State1") + originator.SetState("State2") + caretaker.Add(originator.SaveStateToMemento()) + + originator.SetState("State3") + caretaker.Add(originator.SaveStateToMemento()) + + originator.SetState("State4") + fmt.Println("Current State: " + originator.GetState()) + + originator.GetStateFromMemento(caretaker.Get(0)) + fmt.Println("First saved State: " + originator.GetState()) + originator.GetStateFromMemento(caretaker.Get(1)) + fmt.Println("Second saved State: " + originator.GetState()) +} +``` + +### Perl Example + +```perl +package Memento; + +sub new { + my ($class, $state) = @_; + return bless { state => $state }, $class; +} + +sub get_state { + my $self = shift; + return $self->{state}; +} + +package Originator; + +sub new { + my $class = shift; + return bless { state => '' }, $class; +} + +sub set_state { + my ($self, $state) = @_; + $self->{state} = $state; +} + +sub save_state_to_memento { + my $self = shift; + return Memento->new($self->{state}); +} + +sub get_state_from_memento { + my ($self, $memento) = @_; + $self->{state} = $memento->get_state(); +} + +sub get_state { + my $self = shift; + return $self->{state}; +} + +package Caretaker; + +sub new { + my $class = shift; + return bless { memento_list => [] }, $class; +} + +sub add { + my ($self, $memento) = @_; + push @{$self->{memento_list}}, $memento; +} + +sub get { + my ($self, $index) = @_; + return $self->{memento_list}->[$index]; +} + +package main; + +my $originator = Originator->new(); +my $caretaker = Caretaker->new(); + +$originator->set_state("State1"); +$originator->set_state("State2"); +$caretaker->add($originator->save_state_to_memento()); + +$originator->set_state("State3"); +$caretaker->add($originator->save_state_to_memento()); + +$originator->set_state("State4"); +print "Current State: ", $originator->get_state(), "\n"; + +$originator->get_state_from_memento($caretaker->get(0)); +print "First saved State: ", $originator->get_state(), "\n"; +$originator->get_state_from_memento($caretaker->get(1)); +print "Second saved State: ", $originator->get_state(), "\n"; +``` + +### Python Example + +```python +class Memento: + def __init__(self, state): + self.state = state + +class Originator: + def __init__(self): + self.state = '' + + def set_state(self, state): + self.state = state + + def save_state_to_memento(self): + return Memento(self.state) + + def get_state_from_memento(self, memento): + self.state = memento.state + + def get_state(self): + return self.state + +class Caretaker: + def __init__(self): + self.memento_list = [] + + def add(self, memento): + self.memento_list.append(memento) + + def get(self, index): + return self.memento_list[index] + +originator = Originator() +caretaker = Caretaker() + +originator.set_state("State1") +originator.set_state("State2") +caretaker.add(originator.save_state_to_memento()) + +originator.set_state("State3") +caretaker.add(originator.save_state_to_memento()) + +originator.set_state("State4") +print("Current State:", originator.get_state()) + +originator.get_state_from_memento(caretaker.get(0)) +print("First saved State:", originator.get_state()) +originator.get_state_from_memento(caretaker.get(1)) +print("Second saved State:", originator.get_state()) +``` + +### Ruby Example + +```ruby +class Memento + attr_reader :state + + def initialize(state) + @state = state + end +end + +class Originator + attr_accessor :state + + def save_state_to_memento + Memento.new(@state) + end + + def get_state_from_memento(memento) + @state = memento.state + end +end + +class Caretaker + def initialize + @memento_list = [] + end + + def add(memento) + @memento_list << memento + end + + def get(index) + @memento_list[index] + end +end + +originator = Originator.new +caretaker = Caretaker.new + +originator.state = "State1" +originator.state = "State2" +caretaker.add(originator.save_state_to_memento) + +originator.state = "State3" +caretaker.add(originator.save_state_to_memento) + +originator.state = "State4" +puts "Current State: #{originator.state}" + +originator.get_state_from_memento(caretaker.get(0)) +puts "First saved State: #{originator.state}" +originator.get_state_from_memento(caretaker.get(1)) +puts "Second saved State: #{originator.state}" +``` + +### Rust Example + +```rust +struct Memento { + state: String, +} + +impl Memento { + fn new(state: String) -> Self { + Memento { state } + } + + fn get_state(&self) -> &str { + &self.state + } +} + +struct Originator { + state: String, +} + +impl Originator { + fn new() -> Self { + Originator { + state: String::new(), + } + } + + fn set_state(&mut self, state: String) { + self.state = state; + } + + fn save_state_to_memento(&self) -> Memento { + Memento::new(self.state.clone()) + } + + fn get_state_from_memento(&mut self, memento: &Memento) { + self.state = memento.get_state().to_string(); + } + + fn get_state(&self) -> &str { + &self.state + } +} + +struct Caretaker { + memento_list: Vec, +} + +impl Caretaker { + fn new() -> Self { + Caretaker { + memento_list: Vec::new(), + } + } + + fn add(&mut self, memento: Memento) { + self.memento_list.push(memento); + } + + fn get(&self, index: usize) -> &Memento { + &self.memento_list[index] + } +} + +fn main() { + let mut originator = Originator::new(); + let mut caretaker = Caretaker::new(); + + originator.set_state("State1".to_string()); + originator.set_state("State2".to_string()); + caretaker.add(originator.save_state_to_memento()); + + originator.set_state("State3".to_string()); + caretaker.add(originator.save_state_to_memento()); + + originator.set_state("State4".to_string()); + println!("Current State: {}", originator.get_state()); + + originator.get_state_from_memento(caretaker.get(0)); + println!("First saved State: {}", originator.get_state()); + originator.get_state_from_memento(caretaker.get(1)); + println!("Second saved State: {}", originator.get_state()); +} +``` diff --git a/docs/Prototype.md b/docs/Prototype.md new file mode 100644 index 0000000..5f85f95 --- /dev/null +++ b/docs/Prototype.md @@ -0,0 +1,137 @@ +## Prototype Pattern + +The prototype pattern is a creational design pattern that creates new objects by cloning an existing object, known as the prototype. This +pattern is useful when the cost of creating an object from scratch is more expensive than copying an existing instance. By using prototypes, +the system can create new objects efficiently and dynamically, promoting flexibility and reducing the need for subclassing. + +### Go Example + +```go +package main + +import "fmt" + +type Clonable interface { + Clone() Clonable +} + +type Person struct { + Name string + Age int +} + +func (p *Person) Clone() Clonable { + clone := *p + return &clone +} + +func main() { + original := &Person{"John", 25} + clone := original.Clone().(*Person) + + fmt.Println(original) // Output: &{John 25} + fmt.Println(clone) // Output: &{John 25} +} +``` + +### Perl Example + +```perl +package Person; + +use strict; +use warnings; + +sub new { + my ($class, $name, $age) = @_; + return bless { name => $name, age => $age }, $class; +} + +sub clone { + my $self = shift; + return bless { %$self }, ref($self); +} + +package main; + +my $original = Person->new("John", 25); +my $clone = $original->clone(); + +use Data::Dumper; +print Dumper($original); # Output: $VAR1 = { 'name' => 'John', 'age' => 25 }; +print Dumper($clone); # Output: $VAR1 = { 'name' => 'John', 'age' => 25 }; +``` + +### Python Example + +```python +import copy + +class Person: + def __init__(self, name, age): + self.name = name + self.age = age + + def clone(self): + return copy.deepcopy(self) + +original = Person("John", 25) +clone = original.clone() + +print(original.__dict__) # Output: {'name': 'John', 'age': 25} +print(clone.__dict__) # Output: {'name': 'John', 'age': 25} +``` + +### Ruby Example + +```ruby +class Person + attr_accessor :name, :age + + def initialize(name, age) + @name = name + @age = age + end + + def clone + Marshal.load(Marshal.dump(self)) + end +end + +original = Person.new("John", 25) +clone = original.clone + +puts original.inspect # Output: # +puts clone.inspect # Output: # +``` + +### Rust Example + +```rust +#[derive(Clone, Debug)] +struct Person { + name: String, + age: u32, +} + +impl Person { + fn new(name: &str, age: u32) -> Self { + Person { + name: name.to_string(), + age, + } + } + + fn clone_box(&self) -> Box { + Box::new(self.clone()) + } +} + +fn main() { + let original = Person::new("John", 25); + let clone = original.clone_box(); + + println!("{:?}", original); // Output: Person { name: "John", age: 25 } + println!("{:?}", clone); // Output: Person { name: "John", age: 25 } +} +``` diff --git a/docs/State.md b/docs/State.md new file mode 100644 index 0000000..0fe286a --- /dev/null +++ b/docs/State.md @@ -0,0 +1,245 @@ +## State Pattern + +The state pattern is a behavioural design pattern that allows an object to alter its behaviour when its internal state changes. This pattern +encapsulates state-specific behaviour within state objects, enabling the object to appear as if it changes its class when its state changes. +The state pattern promotes the open/closed principle, allowing new states to be added without modifying the existing code. It simplifies state +transitions and enhances code maintainability by organizing state-specific behaviour into separate classes. + +### Go Example + +```go +package main + +import "fmt" + +// State interface +type State interface { + Handle(context *Context) +} + +// Context struct +type Context struct { + state State +} + +func (c *Context) SetState(state State) { + c.state = state +} + +func (c *Context) Request() { + c.state.Handle(c) +} + +// ConcreteStateA struct +type ConcreteStateA struct{} + +func (s *ConcreteStateA) Handle(context *Context) { + fmt.Println("State A handling request and changing to State B") + context.SetState(&ConcreteStateB{}) +} + +// ConcreteStateB struct +type ConcreteStateB struct{} + +func (s *ConcreteStateB) Handle(context *Context) { + fmt.Println("State B handling request and changing to State A") + context.SetState(&ConcreteStateA{}) +} + +func main() { + context := &Context{state: &ConcreteStateA{}} + + context.Request() // Output: State A handling request and changing to State B + context.Request() // Output: State B handling request and changing to State A + context.Request() // Output: State A handling request and changing to State B + context.Request() // Output: State B handling request and changing to State A +} +``` + +### Perl Example + +```perl +package State; + +sub handle { + die "Abstract method"; +} + +package Context; + +sub new { + my ($class, $state) = @_; + return bless { state => $state }, $class; +} + +sub set_state { + my ($self, $state) = @_; + $self->{state} = $state; +} + +sub request { + my $self = shift; + $self->{state}->handle($self); +} + +package ConcreteStateA; +use parent 'State'; + +sub handle { + my ($self, $context) = @_; + print "State A handling request and changing to State B\n"; + $context->set_state(ConcreteStateB->new()); +} + +package ConcreteStateB; +use parent 'State'; + +sub handle { + my ($self, $context) = @_; + print "State B handling request and changing to State A\n"; + $context->set_state(ConcreteStateA->new()); +} + +package main; + +my $context = Context->new(ConcreteStateA->new()); + +$context->request(); # Output: State A handling request and changing to State B +$context->request(); # Output: State B handling request and changing to State A +$context->request(); # Output: State A handling request and changing to State B +$context->request(); # Output: State B handling request and changing to State A +``` + +### Python Example + +```python +from abc import ABC, abstractmethod + +class State(ABC): + @abstractmethod + def handle(self, context): + pass + +class Context: + def __init__(self, state): + self.state = state + + def set_state(self, state): + self.state = state + + def request(self): + self.state.handle(self) + +class ConcreteStateA(State): + def handle(self, context): + print("State A handling request and changing to State B") + context.set_state(ConcreteStateB()) + +class ConcreteStateB(State): + def handle(self, context): + print("State B handling request and changing to State A") + context.set_state(ConcreteStateA()) + +context = Context(ConcreteStateA()) + +context.request() # Output: State A handling request and changing to State B +context.request() # Output: State B handling request and changing to State A +context.request() # Output: State A handling request and changing to State B +context.request() # Output: State B handling request and changing to State A +``` + +### Ruby Example + +```ruby +class State + def handle(context) + raise 'Abstract method' + end +end + +class Context + attr_accessor :state + + def initialize(state) + @state = state + end + + def request + @state.handle(self) + end +end + +class ConcreteStateA < State + def handle(context) + puts 'State A handling request and changing to State B' + context.state = ConcreteStateB.new + end +end + +class ConcreteStateB < State + def handle(context) + puts 'State B handling request and changing to State A' + context.state = ConcreteStateA.new + end +end + +context = Context.new(ConcreteStateA.new) + +context.request # Output: State A handling request and changing to State B +context.request # Output: State B handling request and changing to State A +context.request # Output: State A handling request and changing to State B +context.request # Output: State B handling request and changing to State A +``` + +### Rust Example + +```rust +trait State { + fn handle(&self, context: &mut Context); +} + +struct Context { + state: Box, +} + +impl Context { + fn new(state: Box) -> Self { + Context { state } + } + + fn set_state(&mut self, state: Box) { + self.state = state; + } + + fn request(&mut self) { + self.state.handle(self); + } +} + +struct ConcreteStateA; + +impl State for ConcreteStateA { + fn handle(&self, context: &mut Context) { + println!("State A handling request and changing to State B"); + context.set_state(Box::new(ConcreteStateB)); + } +} + +struct ConcreteStateB; + +impl State for ConcreteStateB { + fn handle(&self, context: &mut Context) { + println!("State B handling request and changing to State A"); + context.set_state(Box::new(ConcreteStateA)); + } +} + +fn main() { + let mut context = Context::new(Box::new(ConcreteStateA)); + + context.request(); // Output: State A handling request and changing to State B + context.request(); // Output: State B handling request and changing to State A + context.request(); // Output: State A handling request and changing to State B + context.request(); // Output: State B handling request and changing to State A +} +``` diff --git a/docs/Template-Method.md b/docs/Template-Method.md new file mode 100644 index 0000000..b0b2504 --- /dev/null +++ b/docs/Template-Method.md @@ -0,0 +1,165 @@ +## Template Method Pattern + +The template method pattern is a behavioural design pattern that defines the skeleton of an algorithm in a base class, allowing subclasses to +redefine certain steps without changing the algorithm's structure. This pattern promotes code reuse by enabling common behaviour to be shared +across subclasses while allowing customization of specific steps. The template method pattern ensures that the overall algorithm remains +consistent, while subclasses provide the necessary variations, enhancing flexibility and maintainability. + +### Go Example + +```go +package main + +import "fmt" + +// AbstractClass +type AbstractClass interface { + PrimitiveOperation1() + PrimitiveOperation2() + TemplateMethod() +} + +// ConcreteClass +type ConcreteClass struct{} + +func (c *ConcreteClass) PrimitiveOperation1() { + fmt.Println("ConcreteClass: PrimitiveOperation1") +} + +func (c *ConcreteClass) PrimitiveOperation2() { + fmt.Println("ConcreteClass: PrimitiveOperation2") +} + +func (c *ConcreteClass) TemplateMethod() { + c.PrimitiveOperation1() + c.PrimitiveOperation2() +} + +func main() { + concrete := &ConcreteClass{} + concrete.TemplateMethod() +} +``` + +### Perl Example + +```perl +package AbstractClass; + +sub primitive_operation1 { die "Abstract method" } +sub primitive_operation2 { die "Abstract method" } + +sub template_method { + my $self = shift; + $self->primitive_operation1(); + $self->primitive_operation2(); +} + +package ConcreteClass; +use parent 'AbstractClass'; + +sub primitive_operation1 { + print "ConcreteClass: PrimitiveOperation1\n"; +} + +sub primitive_operation2 { + print "ConcreteClass: PrimitiveOperation2\n"; +} + +package main; + +my $concrete = ConcreteClass->new(); +$concrete->template_method(); +``` + +### Python Example + +```python +from abc import ABC, abstractmethod + +class AbstractClass(ABC): + @abstractmethod + def primitive_operation1(self): + pass + + @abstractmethod + def primitive_operation2(self): + pass + + def template_method(self): + self.primitive_operation1() + self.primitive_operation2() + +class ConcreteClass(AbstractClass): + def primitive_operation1(self): + print("ConcreteClass: PrimitiveOperation1") + + def primitive_operation2(self): + print("ConcreteClass: PrimitiveOperation2") + +concrete = ConcreteClass() +concrete.template_method() +``` + +### Ruby Example + +```ruby +class AbstractClass + def primitive_operation1 + raise 'Abstract method' + end + + def primitive_operation2 + raise 'Abstract method' + end + + def template_method + primitive_operation1 + primitive_operation2 + end +end + +class ConcreteClass < AbstractClass + def primitive_operation1 + puts 'ConcreteClass: PrimitiveOperation1' + end + + def primitive_operation2 + puts 'ConcreteClass: PrimitiveOperation2' + end +end + +concrete = ConcreteClass.new +concrete.template_method +``` + +### Rust Example + +```rust +trait AbstractClass { + fn primitive_operation1(&self); + fn primitive_operation2(&self); + + fn template_method(&self) { + self.primitive_operation1(); + self.primitive_operation2(); + } +} + +struct ConcreteClass; + +impl AbstractClass for ConcreteClass { + fn primitive_operation1(&self) { + println!("ConcreteClass: PrimitiveOperation1"); + } + + fn primitive_operation2(&self) { + println!("ConcreteClass: PrimitiveOperation2"); + } +} + +fn main() { + let concrete = ConcreteClass; + concrete.template_method(); +} +``` diff --git a/docs/Visitor.md b/docs/Visitor.md new file mode 100644 index 0000000..69ac0ca --- /dev/null +++ b/docs/Visitor.md @@ -0,0 +1,247 @@ +## Visitor Pattern + +The visitor pattern is a behavioural design pattern that separates an algorithm from the objects on which it operates. This pattern involves +creating a visitor class that implements operations to be performed on elements of an object structure. By accepting a visitor, each element +allows the visitor to perform the operation, decoupling the algorithm from the object structure. The visitor pattern makes it easy to add new +operations without modifying the objects, promoting flexibility and enhancing maintainability. It is particularly useful for operations that +need to be performed on a variety of objects with different interfaces. + + +### Go Example + +```go +package main + +import "fmt" + +// Element +type Element interface { + Accept(visitor Visitor) +} + +// ConcreteElementA +type ConcreteElementA struct{} + +func (e *ConcreteElementA) Accept(visitor Visitor) { + visitor.VisitConcreteElementA(e) +} + +// ConcreteElementB +type ConcreteElementB struct{} + +func (e *ConcreteElementB) Accept(visitor Visitor) { + visitor.VisitConcreteElementB(e) +} + +// Visitor +type Visitor interface { + VisitConcreteElementA(element *ConcreteElementA) + VisitConcreteElementB(element *ConcreteElementB) +} + +// ConcreteVisitor +type ConcreteVisitor struct{} + +func (v *ConcreteVisitor) VisitConcreteElementA(element *ConcreteElementA) { + fmt.Println("Visited ConcreteElementA") +} + +func (v *ConcreteVisitor) VisitConcreteElementB(element *ConcreteElementB) { + fmt.Println("Visited ConcreteElementB") +} + +func main() { + elements := []Element{&ConcreteElementA{}, &ConcreteElementB{}} + visitor := &ConcreteVisitor{} + + for _, element := range elements { + element.Accept(visitor) + } +} +``` + +### Perl Example + +```perl +package Element; + +sub accept { + die "Abstract method"; +} + +package ConcreteElementA; +use parent 'Element'; + +sub accept { + my ($self, $visitor) = @_; + $visitor->visit_concrete_element_a($self); +} + +package ConcreteElementB; +use parent 'Element'; + +sub accept { + my ($self, $visitor) = @_; + $visitor->visit_concrete_element_b($self); +} + +package Visitor; + +sub visit_concrete_element_a { die "Abstract method" } +sub visit_concrete_element_b { die "Abstract method" } + +package ConcreteVisitor; +use parent 'Visitor'; + +sub visit_concrete_element_a { + print "Visited ConcreteElementA\n"; +} + +sub visit_concrete_element_b { + print "Visited ConcreteElementB\n"; +} + +package main; + +my @elements = (ConcreteElementA->new(), ConcreteElementB->new()); +my $visitor = ConcreteVisitor->new(); + +for my $element (@elements) { + $element->accept($visitor); +} +``` + +### Python Example + +```python +class Element: + def accept(self, visitor): + pass + +class ConcreteElementA(Element): + def accept(self, visitor): + visitor.visit_concrete_element_a(self) + +class ConcreteElementB(Element): + def accept(self, visitor): + visitor.visit_concrete_element_b(self) + +class Visitor: + def visit_concrete_element_a(self, element): + pass + + def visit_concrete_element_b(self, element): + pass + +class ConcreteVisitor(Visitor): + def visit_concrete_element_a(self, element): + print("Visited ConcreteElementA") + + def visit_concrete_element_b(self, element): + print("Visited ConcreteElementB") + +elements = [ConcreteElementA(), ConcreteElementB()] +visitor = ConcreteVisitor() + +for element in elements: + element.accept(visitor) +``` + +### Ruby Example + +```ruby +class Element + def accept(visitor) + raise 'Abstract method' + end +end + +class ConcreteElementA < Element + def accept(visitor) + visitor.visit_concrete_element_a(self) + end +end + +class ConcreteElementB < Element + def accept(visitor) + visitor.visit_concrete_element_b(self) + end +end + +class Visitor + def visit_concrete_element_a(element) + raise 'Abstract method' + end + + def visit_concrete_element_b(element) + raise 'Abstract method' + end +end + +class ConcreteVisitor < Visitor + def visit_concrete_element_a(element) + puts 'Visited ConcreteElementA' + end + + def visit_concrete_element_b(element) + puts 'Visited ConcreteElementB' + end +end + +elements = [ConcreteElementA.new, ConcreteElementB.new] +visitor = ConcreteVisitor.new + +elements.each do |element| + element.accept(visitor) +end +``` + +### Rust Example + +```rust +trait Visitor { + fn visit_concrete_element_a(&self, element: &ConcreteElementA); + fn visit_concrete_element_b(&self, element: &ConcreteElementB); +} + +struct ConcreteVisitor; + +impl Visitor for ConcreteVisitor { + fn visit_concrete_element_a(&self, _element: &ConcreteElementA) { + println!("Visited ConcreteElementA"); + } + + fn visit_concrete_element_b(&self, _element: &ConcreteElementB) { + println!("Visited ConcreteElementB"); + } +} + +trait Element { + fn accept(&self, visitor: &dyn Visitor); +} + +struct ConcreteElementA; + +impl Element for ConcreteElementA { + fn accept(&self, visitor: &dyn Visitor) { + visitor.visit_concrete_element_a(self); + } +} + +struct ConcreteElementB; + +impl Element for ConcreteElementB { + fn accept(&self, visitor: &dyn Visitor) { + visitor.visit_concrete_element_b(self); + } +} + +fn main() { + let elements: Vec> = vec![Box::new(ConcreteElementA), Box::new(ConcreteElementB)]; + let visitor = ConcreteVisitor; + + for element in elements { + element.accept(&visitor); + } +} +```