diff --git a/CHANGELOG.md b/CHANGELOG.md index 909b96a..fea0c92 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,6 @@ +## 0.29.0 +- Add conceptual visitor pattern. + ## 0.28.0 - Add conceptual flyweight pattern. diff --git a/README.md b/README.md index 1d1220a..a93a531 100644 --- a/README.md +++ b/README.md @@ -19,7 +19,7 @@ It contains **Dart** examples for all classic **GoF** design patterns. - [x] **Observer** - [[Open-Close Editor Events](https://github.com/RefactoringGuru/design-patterns-dart/tree/main/patterns/observer/open_close_editor_events)] [[AppObserver](https://github.com/RefactoringGuru/design-patterns-dart/tree/main/patterns/observer/app_observer)] [[![16x16](https://user-images.githubusercontent.com/8049534/171852337-57db0faf-1f5e-489a-a79a-22ed4f47b4ed.png) Subscriber Flutter Widget](https://github.com/RefactoringGuru/design-patterns-dart/tree/main/patterns/observer/subscriber_flutter_widget)] - [x] **State** - [[Conceptual](https://github.com/RefactoringGuru/design-patterns-dart/tree/main/patterns/state/three_state)] [[![16x16](https://user-images.githubusercontent.com/8049534/171852337-57db0faf-1f5e-489a-a79a-22ed4f47b4ed.png) State Manipulator](https://github.com/RefactoringGuru/design-patterns-dart/tree/main/patterns/state/manipulator_state)] - [x] **Template Method** - [[Data Miner](https://github.com/RefactoringGuru/design-patterns-dart/tree/main/patterns/template_method/data_miner)] - - [X] **Visitor** [[Shape XML Exporter](https://github.com/RefactoringGuru/design-patterns-dart/tree/main/patterns/visitor/shapes_exporter)] + - [X] **Visitor** - [[Conceptual](https://github.com/RefactoringGuru/design-patterns-dart/tree/main/patterns/visitor/conceptual)] [[Shape XML Exporter](https://github.com/RefactoringGuru/design-patterns-dart/tree/main/patterns/visitor/shapes_exporter)] - [X] **Strategy** [[Reservation Cargo Spaces](https://github.com/RefactoringGuru/design-patterns-dart/tree/main/patterns/strategy/reservation_cargo_spaces)] - [ ] **Structural** - [x] **Adapter** - [[Text Graphics](https://github.com/RefactoringGuru/design-patterns-dart/tree/main/patterns/adapter/text_graphics)] [[Square Round conflict](https://github.com/RefactoringGuru/design-patterns-dart/tree/main/patterns/adapter/square_round_conflict)] [[![16x16](https://user-images.githubusercontent.com/8049534/171852337-57db0faf-1f5e-489a-a79a-22ed4f47b4ed.png) Flutter Adapter](https://github.com/RefactoringGuru/design-patterns-dart/tree/main/patterns/adapter/flutter_adapter)] @@ -27,7 +27,7 @@ It contains **Dart** examples for all classic **GoF** design patterns. - [x] **Composite** - [[Image Editor](https://github.com/RefactoringGuru/design-patterns-dart/tree/main/patterns/composite/image_editor)] [[Products and Boxes](https://github.com/RefactoringGuru/design-patterns-dart/tree/main/patterns/composite/products_and_boxes)] - [x] **Decorator** - [[Data Source Decoder](https://github.com/RefactoringGuru/design-patterns-dart/tree/main/patterns/decorator/data_source_decoder)] - [ ] **Facade** - - [x] **Flyweight** [[Conceptual](https://github.com/RefactoringGuru/design-patterns-dart/tree/main/patterns/flyweight/conceptual)] + - [x] **Flyweight** - [[Conceptual](https://github.com/RefactoringGuru/design-patterns-dart/tree/main/patterns/flyweight/conceptual)] - [ ] **Proxy** ## Requirements diff --git a/patterns/visitor/conceptual/README.md b/patterns/visitor/conceptual/README.md new file mode 100644 index 0000000..fef872e --- /dev/null +++ b/patterns/visitor/conceptual/README.md @@ -0,0 +1,82 @@ +# Visitor pattern +Visitor is a behavioral design pattern that lets you separate algorithms from the objects on which +they operate. + +Tutorial: [here](https://refactoring.guru/design-patterns/visitor). + +### About example. + +## Client code: +### Before: +```dart +void main() { + final list = createElements(); + list.forEach(operation1); +} + +Iterable createElements() { + return [ + One(), + Two(), + Three(), + ]; +} + +void operation1(Object obj) { + if (obj is One) { + print('operation1: one (param1 = ${obj.param1})'); + } else if (obj is Two) { + print('operation1: two (param2 = ${obj.param2})'); + } else if (obj is Three) { + print('operation1: two (param3 = ${obj.param3})'); + } +} +``` + +### After: +```dart +void main() { + final list = createElements(); + + for (final e in elements) { + e.accept(visitor); + } +} + +Iterable createElements() { + return [ + One(), + Two(), + Three(), + ]; +} + +class ConcreteVisitor1 implements Visitor { + @override + void visitOne(One one) { + print('operation1: one (param1 = ${one.param1})'); + } + + @override + void visitTwo(Two two) { + print('operation1: two (param2 = ${two.param2})'); + } + + @override + void visitThree(Three three) { + print('operation1: three (param3 = ${three.param3})'); + } +} +``` +#### Diagram: +![image](https://user-images.githubusercontent.com/8049534/174583542-5f57463c-148b-4113-acd3-2814ec017ecc.png) + +### Output: +``` +operation1: one (param1 = 1) +operation1: two (param2 = 2) +operation1: three (param3 = 3) +operation2: one (param1 = 1) +operation2: two (param2 = 2) +operation2: three (param3 = 3) +``` diff --git a/patterns/visitor/conceptual/after/elements/one.dart b/patterns/visitor/conceptual/after/elements/one.dart new file mode 100644 index 0000000..3d174a6 --- /dev/null +++ b/patterns/visitor/conceptual/after/elements/one.dart @@ -0,0 +1,11 @@ +import '../pattern/element.dart'; +import '../pattern/visitor.dart'; + +class One implements Element { + final String param1 = '1'; + + @override + void accept(Visitor visitor) { + visitor.visitOne(this); + } +} diff --git a/patterns/visitor/conceptual/after/elements/three.dart b/patterns/visitor/conceptual/after/elements/three.dart new file mode 100644 index 0000000..28a8559 --- /dev/null +++ b/patterns/visitor/conceptual/after/elements/three.dart @@ -0,0 +1,11 @@ +import '../pattern/element.dart'; +import '../pattern/visitor.dart'; + +class Three implements Element { + final String param3 = '3'; + + @override + void accept(Visitor visitor) { + visitor.visitThree(this); + } +} diff --git a/patterns/visitor/conceptual/after/elements/two.dart b/patterns/visitor/conceptual/after/elements/two.dart new file mode 100644 index 0000000..9937c09 --- /dev/null +++ b/patterns/visitor/conceptual/after/elements/two.dart @@ -0,0 +1,11 @@ +import '../pattern/element.dart'; +import '../pattern/visitor.dart'; + +class Two implements Element { + final String param2 = '2'; + + @override + void accept(Visitor visitor) { + visitor.visitTwo(this); + } +} diff --git a/patterns/visitor/conceptual/after/main.dart b/patterns/visitor/conceptual/after/main.dart new file mode 100644 index 0000000..3bb0215 --- /dev/null +++ b/patterns/visitor/conceptual/after/main.dart @@ -0,0 +1,27 @@ +import 'elements/one.dart'; +import 'elements/three.dart'; +import 'elements/two.dart'; +import 'operations/concrete_visitor1.dart'; +import 'operations/concrete_visitor2.dart'; +import 'pattern/element.dart'; +import 'pattern/visitor.dart'; + +void main() { + final list = createElements(); + operation(list, ConcreteVisitor1()); + operation(list, ConcreteVisitor2()); +} + +Iterable createElements() { + return [ + One(), + Two(), + Three(), + ]; +} + +void operation(Iterable elements, Visitor visitor) { + for (final e in elements) { + e.accept(visitor); + } +} diff --git a/patterns/visitor/conceptual/after/operations/concrete_visitor1.dart b/patterns/visitor/conceptual/after/operations/concrete_visitor1.dart new file mode 100644 index 0000000..3784140 --- /dev/null +++ b/patterns/visitor/conceptual/after/operations/concrete_visitor1.dart @@ -0,0 +1,21 @@ +import '../elements/one.dart'; +import '../elements/three.dart'; +import '../elements/two.dart'; +import '../pattern/visitor.dart'; + +class ConcreteVisitor1 implements Visitor { + @override + void visitOne(One one) { + print('operation1: one (param1 = ${one.param1})'); + } + + @override + void visitTwo(Two two) { + print('operation1: two (param2 = ${two.param2})'); + } + + @override + void visitThree(Three three) { + print('operation1: three (param3 = ${three.param3})'); + } +} diff --git a/patterns/visitor/conceptual/after/operations/concrete_visitor2.dart b/patterns/visitor/conceptual/after/operations/concrete_visitor2.dart new file mode 100644 index 0000000..0dec8d3 --- /dev/null +++ b/patterns/visitor/conceptual/after/operations/concrete_visitor2.dart @@ -0,0 +1,21 @@ +import '../elements/one.dart'; +import '../elements/three.dart'; +import '../elements/two.dart'; +import '../pattern/visitor.dart'; + +class ConcreteVisitor2 implements Visitor { + @override + void visitOne(One one) { + print('operation2: one (param1 = ${one.param1})'); + } + + @override + void visitTwo(Two two) { + print('operation2: two (param2 = ${two.param2})'); + } + + @override + void visitThree(Three three) { + print('operation2: three (param3 = ${three.param3})'); + } +} diff --git a/patterns/visitor/conceptual/after/pattern/element.dart b/patterns/visitor/conceptual/after/pattern/element.dart new file mode 100644 index 0000000..5a7026d --- /dev/null +++ b/patterns/visitor/conceptual/after/pattern/element.dart @@ -0,0 +1,5 @@ +import 'visitor.dart'; + +abstract class Element { + void accept(Visitor visitor); +} diff --git a/patterns/visitor/conceptual/after/pattern/visitor.dart b/patterns/visitor/conceptual/after/pattern/visitor.dart new file mode 100644 index 0000000..0556fca --- /dev/null +++ b/patterns/visitor/conceptual/after/pattern/visitor.dart @@ -0,0 +1,11 @@ +import '../elements/one.dart'; +import '../elements/three.dart'; +import '../elements/two.dart'; + +abstract class Visitor { + void visitOne(One one); + + void visitTwo(Two two); + + void visitThree(Three three); +} diff --git a/patterns/visitor/conceptual/before/elements/elements.dart b/patterns/visitor/conceptual/before/elements/elements.dart new file mode 100644 index 0000000..5e844c9 --- /dev/null +++ b/patterns/visitor/conceptual/before/elements/elements.dart @@ -0,0 +1,11 @@ +class One { + final String param1 = '1'; +} + +class Two { + final String param2 = '2'; +} + +class Three { + final String param3 = '3'; +} diff --git a/patterns/visitor/conceptual/before/main.dart b/patterns/visitor/conceptual/before/main.dart new file mode 100644 index 0000000..a75fdd6 --- /dev/null +++ b/patterns/visitor/conceptual/before/main.dart @@ -0,0 +1,36 @@ +import 'elements/elements.dart'; + +void main() { + final list = createElements(); + + list.forEach(operation1); + list.forEach(operation2); +} + +Iterable createElements() { + return [ + One(), + Two(), + Three(), + ]; +} + +void operation1(Object obj) { + if (obj is One) { + print('operation1: one (param1 = ${obj.param1})'); + } else if (obj is Two) { + print('operation1: two (param2 = ${obj.param2})'); + } else if (obj is Three) { + print('operation1: two (param3 = ${obj.param3})'); + } +} + +void operation2(Object obj) { + if (obj is One) { + print('operation2: one (param1 = ${obj.param1})'); + } else if (obj is Two) { + print('operation2: two (param2 = ${obj.param2})'); + } else if (obj is Three) { + print('operation2: two (param3 = ${obj.param3})'); + } +} diff --git a/pubspec.yaml b/pubspec.yaml index b3b877c..18c1e3d 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -1,6 +1,6 @@ name: design_patterns_dart description: Dart examples for all classic GoF design patterns. -version: 0.28.0 +version: 0.29.0 homepage: https://refactoring.guru/design-patterns repository: https://github.com/RefactoringGuru/design-patterns-dart issue_tracker: https://github.com/RefactoringGuru/design-patterns-dart/issue