diff --git a/.gitignore b/.gitignore index d111b3a..c282350 100644 --- a/.gitignore +++ b/.gitignore @@ -1,6 +1,7 @@ .dart_tool/ .idea/ build/ +windows/ .packages pubspec.lock diff --git a/CHANGELOG.md b/CHANGELOG.md index 203262a..52b67b9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,6 @@ +## 0.15.0 +- Add second "Observer" example. This example was created to be used in a more complex example. + ## 0.14.0 - Add "Memento" conceptual pattern diff --git a/README.md b/README.md index 8f0052c..c7cbbda 100644 --- a/README.md +++ b/README.md @@ -15,8 +15,8 @@ It contains **Dart** examples for all classic **GoF** design patterns. - [ ] Interpreter - [ ] [**Iterator**](https://refactoring.guru/design-patterns/iterator) - [ ] [**Mediator**](https://refactoring.guru/design-patterns/mediator) - - [x] [**Memento**](https://refactoring.guru/design-patterns/memento) [[Conceptual](https://github.com/RefactoringGuru/design-patterns-dart/tree/master/patterns/memento/conceptual)] - - [x] [**Observer**](https://refactoring.guru/design-patterns/observer) - [[Open-Close Editor Events](https://github.com/RefactoringGuru/design-patterns-dart/tree/master/patterns/observer/open_close_editor_events)] + - [x] [**Memento**](https://refactoring.guru/design-patterns/memento) - [[Conceptual](https://github.com/RefactoringGuru/design-patterns-dart/tree/master/patterns/memento/conceptual)] + - [x] [**Observer**](https://refactoring.guru/design-patterns/observer) - [[Open-Close Editor Events](https://github.com/RefactoringGuru/design-patterns-dart/tree/master/patterns/observer/open_close_editor_events)] [[AppObserver](https://github.com/RefactoringGuru/design-patterns-dart/tree/master/patterns/observer/app_observer)] - [ ] [**State**](https://refactoring.guru/design-patterns/state) - [ ] [**Template Method**](https://refactoring.guru/design-patterns/template-method) - [ ] [**Visitor**](https://refactoring.guru/design-patterns/visitor) diff --git a/bin/main.dart b/bin/main.dart new file mode 100644 index 0000000..3865bb7 --- /dev/null +++ b/bin/main.dart @@ -0,0 +1,20 @@ +import 'package:flutter/material.dart'; + +void main() { + runApp(const MyApp()); +} + +class MyApp extends StatelessWidget { + const MyApp({Key? key}) : super(key: key); + + @override + Widget build(BuildContext context) { + return MaterialApp( + title: 'Refactoring Guru: Flutter launcher', + theme: ThemeData( + primarySwatch: Colors.pink + ), + home: Container(), + ); + } +} diff --git a/patterns/observer/app_observer/README.md b/patterns/observer/app_observer/README.md new file mode 100644 index 0000000..4e509eb --- /dev/null +++ b/patterns/observer/app_observer/README.md @@ -0,0 +1,56 @@ +# Observer pattern +Observer is a behavioral design pattern that lets you define a subscription mechanism to notify +multiple objects about any events that happen to the object they’re observing. + +Tutorial: [here](https://refactoring.guru/design-patterns/observer). + +## AppObserver example +This example was created to be used in a more complex example. +A complex example will be implemented later. + +### Diagram: +![image](https://user-images.githubusercontent.com/8049534/152049751-b111e02a-1d33-4796-810c-b7ed069cecdc.png) + +### Sequence +![image](https://user-images.githubusercontent.com/8049534/152049996-72131655-402d-4b92-b5d0-10e3f2dd0e79.png) + +### Client code: +```dart +void main() { + final observer = AppObserver(); + + observer.subscribe((e) { + print('First'); + }); + + + observer.subscribe((SecondEvent e) { + print('Second'); + }); + + final saveThirdEvent = observer.subscribe((ThirdEvent e) { + print('Third'); + }); + + observer.notify(FirstEvent()); + observer.notify(SecondEvent()); + observer.notify(ThirdEvent()); + + print('---unsubscribe "ThirdEvent"---'); + observer.unsubscribe(saveThirdEvent); + + observer.notify(FirstEvent()); + observer.notify(SecondEvent()); + observer.notify(ThirdEvent()); +} +``` + +**Output:** +``` +First +Second +Third +---unsubscribe "ThirdEvent"--- +First +Second +``` diff --git a/patterns/observer/app_observer/main.dart b/patterns/observer/app_observer/main.dart new file mode 100644 index 0000000..620fb21 --- /dev/null +++ b/patterns/observer/app_observer/main.dart @@ -0,0 +1,36 @@ +import 'observer/app_observer.dart'; +import 'observer/event.dart'; + +class FirstEvent extends Event {} + +class SecondEvent extends Event {} + +class ThirdEvent extends Event {} + +void main() { + final observer = AppObserver(); + + observer.subscribe((e) { + print('First'); + }); + + + observer.subscribe((SecondEvent e) { + print('Second'); + }); + + final saveThirdEvent = observer.subscribe((ThirdEvent e) { + print('Third'); + }); + + observer.notify(FirstEvent()); + observer.notify(SecondEvent()); + observer.notify(ThirdEvent()); + + print('---unsubscribe "ThirdEvent"---'); + observer.unsubscribe(saveThirdEvent); + + observer.notify(FirstEvent()); + observer.notify(SecondEvent()); + observer.notify(ThirdEvent()); +} diff --git a/patterns/observer/app_observer/observer/app_observer.dart b/patterns/observer/app_observer/observer/app_observer.dart new file mode 100644 index 0000000..a6fa01a --- /dev/null +++ b/patterns/observer/app_observer/observer/app_observer.dart @@ -0,0 +1,46 @@ +import 'event.dart'; + +typedef EventFunction = void Function(T e); + +class AppObserver { + final _subscribers = >{}; + + EventFunction subscribe(EventFunction func) { + assert( + Class() is Class, + '\n\nThe callback argument must implement the "Event" class.\n' + 'Correct use: \n' + '\tobserver.subscribe((MyEvent e) {}); \n' + 'Mistaken usage: \n' + '\tobserver.subscribe((String e) {});\n' + '\tobserver.subscribe((e) {});\n', + ); + + _subscribers.putIfAbsent(T.hashCode, () => []).add(func); + return func; + } + + void unsubscribe(EventFunction func) { + final isDelete = _subscribers[T.hashCode]?.remove(func) ?? false; + + if (isDelete) { + return; + } + + throw Exception('Subscriber not found.'); + } + + void notify(T event) { + final subscribers = _subscribers[T.hashCode]; + + if (subscribers == null) { + return; + } + + for (var sub in subscribers) { + sub.call(event); + } + } +} + +class Class {} diff --git a/patterns/observer/app_observer/observer/event.dart b/patterns/observer/app_observer/observer/event.dart new file mode 100644 index 0000000..dbd3bf8 --- /dev/null +++ b/patterns/observer/app_observer/observer/event.dart @@ -0,0 +1,3 @@ +abstract class Event { + +} diff --git a/pubspec.yaml b/pubspec.yaml index 26fbabd..c516e54 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.14.0 +version: 0.15.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 @@ -10,6 +10,10 @@ environment: dependencies: collection: ^1.15.0 + flutter: + sdk: flutter dev_dependencies: lints: ^1.0.0 + + diff --git a/web/favicon.png b/web/favicon.png new file mode 100644 index 0000000..8aaa46a Binary files /dev/null and b/web/favicon.png differ diff --git a/web/icons/Icon-192.png b/web/icons/Icon-192.png new file mode 100644 index 0000000..b749bfe Binary files /dev/null and b/web/icons/Icon-192.png differ diff --git a/web/icons/Icon-512.png b/web/icons/Icon-512.png new file mode 100644 index 0000000..88cfd48 Binary files /dev/null and b/web/icons/Icon-512.png differ diff --git a/web/icons/Icon-maskable-192.png b/web/icons/Icon-maskable-192.png new file mode 100644 index 0000000..eb9b4d7 Binary files /dev/null and b/web/icons/Icon-maskable-192.png differ diff --git a/web/icons/Icon-maskable-512.png b/web/icons/Icon-maskable-512.png new file mode 100644 index 0000000..d69c566 Binary files /dev/null and b/web/icons/Icon-maskable-512.png differ diff --git a/web/index.html b/web/index.html new file mode 100644 index 0000000..0e76fb2 --- /dev/null +++ b/web/index.html @@ -0,0 +1,104 @@ + + + + + + + + + + + + + + + + + + + + flutter_launcher + + + + + + + diff --git a/web/manifest.json b/web/manifest.json new file mode 100644 index 0000000..7bab0e5 --- /dev/null +++ b/web/manifest.json @@ -0,0 +1,35 @@ +{ + "name": "flutter_launcher", + "short_name": "flutter_launcher", + "start_url": ".", + "display": "standalone", + "background_color": "#0175C2", + "theme_color": "#0175C2", + "description": "A new Flutter project.", + "orientation": "portrait-primary", + "prefer_related_applications": false, + "icons": [ + { + "src": "icons/Icon-192.png", + "sizes": "192x192", + "type": "image/png" + }, + { + "src": "icons/Icon-512.png", + "sizes": "512x512", + "type": "image/png" + }, + { + "src": "icons/Icon-maskable-192.png", + "sizes": "192x192", + "type": "image/png", + "purpose": "maskable" + }, + { + "src": "icons/Icon-maskable-512.png", + "sizes": "512x512", + "type": "image/png", + "purpose": "maskable" + } + ] +}