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
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
## 0.16.0
- Add complex example of an Observer pattern, connected to a Flutter application.
- Add new branch "web-demos" for online examples.

## 0.15.0
- Add second "Observer" example. This example was created to be used in a more complex example.

Expand Down
9 changes: 8 additions & 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)
- [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)]
- [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)] [[Subscriber Flutter Widget](https://github.com/RefactoringGuru/design-patterns-dart/tree/master/patterns/observer/subscriber_flutter_widget)]
- [ ] [**State**](https://refactoring.guru/design-patterns/state)
- [ ] [**Template Method**](https://refactoring.guru/design-patterns/template-method)
- [ ] [**Visitor**](https://refactoring.guru/design-patterns/visitor)
Expand All @@ -33,6 +33,7 @@ It contains **Dart** examples for all classic **GoF** design patterns.
## Requirements

The examples were written in **Dart 2.15**.
Some complex examples require **Flutter 2.15.0**.

## Contributor's Guide

Expand Down Expand Up @@ -65,6 +66,12 @@ Here's a style guide which might help you to keep your changes consistent with o
Don't be scared and ignore the non-English part of such comments. If you want to change something in a comment like this, then do it. Even if you do it wrong, we'll tell you how to fix it during the Pull Request.


### Build Flutter examples
```batch
cd root directory
flutter build web -t bin\main.dart --web-renderer html
```

## License

This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivatives 4.0 International License.
Expand Down
12 changes: 7 additions & 5 deletions bin/main.dart
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
import 'package:flutter/material.dart';
import '../patterns/observer/subscriber_flutter_widget/main.dart';

void main() {
runApp(const MyApp());
runApp(MyApp());
}

class MyApp extends StatelessWidget {
Expand All @@ -11,10 +12,11 @@ class MyApp extends StatelessWidget {
Widget build(BuildContext context) {
return MaterialApp(
title: 'Refactoring Guru: Flutter launcher',
theme: ThemeData(
primarySwatch: Colors.pink
),
home: Container(),
theme: ThemeData(primarySwatch: Colors.pink),
initialRoute: '/observer/subscriber_flutter_widget',
routes: {
'/observer/subscriber_flutter_widget': (_) => SubscriberFlutterApp(),
},
);
}
}
44 changes: 44 additions & 0 deletions patterns/observer/subscriber_flutter_widget/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.

Tutorial: [here](https://refactoring.guru/design-patterns/observer).

## Subscriber Flutter Widget example
This is a complex example of an Observer pattern, connected to a Flutter application. The example includes,
the previously implemented **AppObserver** example pattern, which you can see [here](https://github.com/RefactoringGuru/design-patterns-dart/tree/master/patterns/observer/app_observer).

### Diagram:
![image](https://user-images.githubusercontent.com/8049534/152418114-f040bcb4-3bf5-4581-8b9b-a264e103ff76.png)

### Sequence
![image](https://user-images.githubusercontent.com/8049534/152418299-3f6f3e5d-7132-42bc-9b27-11ed53ca6434.png)

### Client code:
```dart
void main() {
// widget that generates a new event
ElevatedButton(
child: Text('Generate new hash'),
onPressed: () {
final hash = 'some hash';
observer.notify(NewHashEvent(hash));
},
);

// widget event consumer NewHashEvent
SubscriberWidget<NewHashEvent>(
observer: observer,
builder: (context, event) {
return Text(
event?.newHash ?? 'Hash no generated' ,
);
},
);
}
```

### Online demo:
Click on the picture to see a [demo](https://ilopx.github.io/design-patterns-dart/#/observer/subscriber_flutter_widget).

[![image](https://user-images.githubusercontent.com/8049534/152419178-f40a07fd-728d-4f99-befa-0935bbdd7b71.png)](https://ilopx.github.io/design-patterns-dart/#/observer/subscriber_flutter_widget)
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
import '../../app_observer/observer/event.dart';

class NewHashEvent extends Event {
final String newHash;

NewHashEvent(this.newHash);
}
28 changes: 28 additions & 0 deletions patterns/observer/subscriber_flutter_widget/main.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
import 'package:flutter/material.dart';
import '../app_observer/observer/app_observer.dart';
import 'widgets/hash_generator_widget.dart';
import 'widgets/hash_user_widget.dart';

class SubscriberFlutterApp extends StatefulWidget {
@override
State<SubscriberFlutterApp> createState() => _SubscriberFlutterAppState();
}

class _SubscriberFlutterAppState extends State<SubscriberFlutterApp> {
final observer = AppObserver();

@override
Widget build(BuildContext context) {
return Scaffold(
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
HashUserWidget(observer: observer),
HashGeneratorWidget(observer: observer),
],
),
),
);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
import 'package:flutter/widgets.dart';

import '../../app_observer/observer/app_observer.dart';
import '../../app_observer/observer/event.dart';

class SubscriberWidget<T extends Event> extends StatefulWidget {
final AppObserver observer;
final Widget Function(BuildContext buildContext, T? event) builder;

const SubscriberWidget({
Key? key,
required this.builder,
required this.observer,
}) : super(key: key);

@override
State<SubscriberWidget<T>> createState() {
return _SubscriberWidgetState<T>();
}
}

class _SubscriberWidgetState<T extends Event>
extends State<SubscriberWidget<T>> {
T? _event;

@override
void initState() {
widget.observer.subscribe<T>(update);
super.initState();
}

@override
void dispose() {
widget.observer.unsubscribe(update);
super.dispose();
}

void update(T event) {
setState(() => _event = event);
}

@override
Widget build(BuildContext context) {
return widget.builder(context, _event);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
import 'dart:math';

import 'package:flutter/material.dart';

import '../../app_observer/observer/app_observer.dart';
import '../events/new_hash_event.dart';

class HashGeneratorWidget extends StatelessWidget {
final AppObserver observer;

const HashGeneratorWidget({
Key? key,
required this.observer,
}) : super(key: key);

@override
Widget build(BuildContext context) {
return ElevatedButton(
child: Text('Generate new hash'),
onPressed: onHashGenerate,
);
}

void onHashGenerate() {
final hash = Random().nextDouble().hashCode.toString();
observer.notify(NewHashEvent(hash));
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
import 'package:flutter/widgets.dart';

import '../../app_observer/observer/app_observer.dart';
import '../events/new_hash_event.dart';
import '../subscriber/subscriber_widget.dart';

class HashUserWidget extends StatelessWidget {
final AppObserver observer;

const HashUserWidget({Key? key, required this.observer}) : super(key: key);

@override
Widget build(BuildContext context) {
return SubscriberWidget<NewHashEvent>(
observer: observer,
builder: (context, event) {
return Text(
event?.newHash ?? 'Hash no generated',
);
},
);
}
}
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.15.0
version: 0.16.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
Loading