Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
## 0.13.0
- Add "Observer" pattern from official book, rewritten from Java example.

## 0.12.19
- Refactoring: reformatting and minor changes

Expand Down
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ It contains **Dart** examples for all classic **GoF** design patterns.
- [ ] [**Iterator**](https://refactoring.guru/design-patterns/iterator)
- [ ] [**Mediator**](https://refactoring.guru/design-patterns/mediator)
- [ ] [**Memento**](https://refactoring.guru/design-patterns/memento)
- [ ] [**Observer**](https://refactoring.guru/design-patterns/observer)
- [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)]
- [ ] [**State**](https://refactoring.guru/design-patterns/state)
- [ ] [**Template Method**](https://refactoring.guru/design-patterns/template-method)
- [ ] [**Visitor**](https://refactoring.guru/design-patterns/visitor)
Expand Down
44 changes: 44 additions & 0 deletions patterns/observer/open_close_editor_events/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
# 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.

## Editor example
In this example, the Observer pattern lets the text editor object notify other service objects about
changes in its state.

More detailed explanation on [RefactoringGuru](https://refactoring.guru/design-patterns/observer?#pseudocode).

### Origin source code:
This example rewrite from [java example](https://github.com/RefactoringGuru/design-patterns-java/tree/master/src/refactoring_guru/observer/example).

### Diagram:
![image](https://user-images.githubusercontent.com/8049534/150955865-7fbb29f3-ed48-4317-a356-cbb9cc79ed11.png)

### Client code:
```dart
void main() {
final editor = Editor();
editor.events
..subscribe(
'open',
LogOpenListener('log.txt'),
)
..subscribe(
'save',
EmailNotificationListener('admin@example.com'),
);

try {
editor.openFile('test.txt');
editor.saveFile();
} catch (e) {
print(e);
}
}
```

**Output:**
```
Save to log "log.txt": Someone has performed "open" operation with the following file: "test.txt"
Email to "admin@example.com": Someone has performed "save" operation with the following file: "test.txt"
```
22 changes: 22 additions & 0 deletions patterns/observer/open_close_editor_events/editor/editor.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
import 'dart:io';

import '../event_manager/event_manager.dart';

class Editor {
final events = EventManager(['open', 'save']);

File? _file;

void openFile(String filePath) {
_file = File(filePath);
events.notify("open", _file!);
}

void saveFile() {
if (_file == null) {
throw Exception('Please open a file first.');
}

events.notify('save', _file!);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
import 'dart:io';

import '../listeners/event_listener.dart';

class EventManager {
final _listeners = <String, List<EventListener>>{};

EventManager(List<String> operations) {
for (final operation in operations) {
_listeners[operation] = [];
}
}

void subscribe(String eventType, EventListener listener) {
_usersBy(eventType).add(listener);
}

void unsubscribe(String eventType, EventListener listener) {
_usersBy(eventType).remove(listener);
}

void notify(String eventType, File file) {
final users = _usersBy(eventType);
for (final listener in users) {
listener.update(eventType, file);
}
}

List<EventListener> _usersBy(String eventType) {
final users = _listeners[eventType];

if (users == null) {
throw UnsupportedError('Event type "$eventType" do not support.');
}

return users;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
import 'dart:io';

import 'event_listener.dart';

class EmailNotificationListener implements EventListener {
String email;

EmailNotificationListener(this.email);

@override
void update(String eventType, File file) {
print('Email to "$email": '
'Someone has performed "$eventType" '
'operation with the following file: "${file.path}"');
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
import 'dart:io';

abstract class EventListener {
void update(String eventType, File file);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
import 'dart:io';

import 'event_listener.dart';

class LogOpenListener implements EventListener {
File logFile;

LogOpenListener(String logFileName) : logFile = File(logFileName);

@override
void update(String eventType, File file) {
print('Save to log "${logFile.path}": '
'Someone has performed "$eventType" '
'operation with the following file: "${file.path}"');
}
}
23 changes: 23 additions & 0 deletions patterns/observer/open_close_editor_events/main.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
import 'editor/editor.dart';
import 'listeners/email_notification_listener.dart';
import 'listeners/log_open_listener.dart';

void main() {
final editor = Editor();
editor.events
..subscribe(
'open',
LogOpenListener('log.txt'),
)
..subscribe(
'save',
EmailNotificationListener('admin@example.com'),
);

try {
editor.openFile('test.txt');
editor.saveFile();
} catch (e) {
print(e);
}
}
2 changes: 1 addition & 1 deletion pubspec.yaml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
name: design_patterns_dart
description: Dart examples for all classic GoF design patterns.
version: 0.12.19
version: 0.13.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
Expand Down