Skip to content

Commit 4b73171

Browse files
committed
done 3rd party youtube example
1 parent c0b2ace commit 4b73171

File tree

4 files changed

+398
-0
lines changed

4 files changed

+398
-0
lines changed
Loading
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,226 @@
1+
# 3rd party youtube example
2+
3+
4+
## source:
5+
> https://refactoring.guru/design-patterns/proxy/java/example
6+
7+
8+
## What is Proxy?
9+
> - Proxy is a structural design pattern
10+
> - that provides an object
11+
> - that acts as a substitute for a real service object used by a client.
12+
> - A proxy receives client requests,
13+
> - does some work (access control, caching, etc.)
14+
> - and then passes the request to a service object.
15+
16+
## The proxy object
17+
- has (the same interface as a service),
18+
- which makes it interchangeable with a real object when passed to a client.
19+
20+
## Usage examples:
21+
- It’s irreplaceable
22+
- when you want to add some `additional behaviors` to an object of some existing class
23+
- without changing the client code.
24+
25+
## Identification:
26+
- Proxies delegate all of the real work to some other object.
27+
- Each proxy method should, in the end, refer to a service object
28+
- unless the proxy is a subclass of a service.
29+
30+
## Caching proxy
31+
In this example,
32+
1. the Proxy pattern helps to implement the lazy initialization
33+
2. and caching to an inefficient 3rd-party YouTube integration library.
34+
35+
## Proxy is invaluable
36+
> when you have to add some additional behaviors to a class which code you can’t change.
37+
38+
## UML
39+
<p align="center">
40+
<img style="background-color:#5547" src = "./3rd_party_youtube_example.png" >
41+
</p>
42+
43+
## Code
44+
45+
### Service Interface || Subject
46+
```dart
47+
int lineNum = 0;
48+
49+
abstract class ThirdPartyYouTubeLib {
50+
Map<String, Video> popularVideos();
51+
Video getVideo(String videoId);
52+
}
53+
```
54+
55+
### RealSubject == Service == ThirdPartyYouTubeClass
56+
57+
```dart
58+
59+
class ThirdPartyYouTubeClass implements ThirdPartyYouTubeLib {
60+
@override
61+
Map<String, Video> popularVideos() {
62+
_connectToServer("http://www.youtube.com");
63+
return _getPopularVideos();
64+
}
65+
66+
@override
67+
Video getVideo(String videoId) {
68+
_connectToServer("http://www.youtube.com/$videoId");
69+
return _getSomeVideo(videoId);
70+
}
71+
72+
// --------------------------------------
73+
// Fake methods to simulate network activity.
74+
// They as slow as a real life.
75+
76+
void _experienceNetworkLatency() {
77+
// int randomLatency = 5 + (Random().nextInt(10) * 6);
78+
int randomLatency = 10;
79+
for (int i = 0; i < randomLatency; i++) {
80+
try {
81+
Future.delayed(Duration(milliseconds: 100));
82+
} catch (ex) {
83+
print(ex);
84+
}
85+
}
86+
}
87+
88+
void _connectToServer(String server) {
89+
print("${++lineNum}: Connecting to $server ... ");
90+
_experienceNetworkLatency();
91+
print("${++lineNum}: Connected! ");
92+
}
93+
94+
Map<String, Video> _getPopularVideos() {
95+
print("${++lineNum}: Downloading popular Videos... ");
96+
_experienceNetworkLatency();
97+
_experienceNetworkLatency();
98+
Map<String, Video> map = Map<String, Video>();
99+
map["catzzzzzzzzz"] = Video(id: "sadgahasgdas", title: "Catzzzz.avi");
100+
map["dancesvideoo"] = Video(id: "asdfas3ffasd", title: "Dancing video.mpq");
101+
print("${++lineNum}: Done!");
102+
return map;
103+
}
104+
105+
Video _getSomeVideo(String videoId) {
106+
print("${++lineNum}: Downloading video... ");
107+
108+
_experienceNetworkLatency();
109+
Video video = Video(id: videoId, title: "Some video title");
110+
111+
print("${++lineNum}: Done!");
112+
return video;
113+
}
114+
}
115+
116+
class Video {
117+
String id;
118+
String title;
119+
String data;
120+
121+
Video({required this.id, required this.title, this.data = "Random video."});
122+
}
123+
```
124+
### Proxy Class
125+
126+
```dart
127+
class YouTubeCacheProxy implements ThirdPartyYouTubeLib {
128+
ThirdPartyYouTubeLib _youtubeService;
129+
Map<String, Video> _cachePopular = Map<String, Video>();
130+
Map<String, Video> _cacheAll = Map<String, Video>();
131+
132+
YouTubeCacheProxy() : _youtubeService = ThirdPartyYouTubeClass();
133+
134+
@override
135+
Map<String, Video> popularVideos() {
136+
if (_cachePopular.isEmpty) {
137+
_cachePopular = _youtubeService.popularVideos();
138+
} else {
139+
print("${++lineNum}: Retrieved list from cache.");
140+
}
141+
return _cachePopular;
142+
}
143+
144+
@override
145+
Video getVideo(String videoId) {
146+
Video? video = _cacheAll[videoId];
147+
if (video == null) {
148+
video = _youtubeService.getVideo(videoId);
149+
_cacheAll[videoId] = video;
150+
} else {
151+
print("${++lineNum}: Retrieved video ' $videoId ' from cache.");
152+
}
153+
return video;
154+
}
155+
156+
void reset() {
157+
_cachePopular.clear();
158+
_cacheAll.clear();
159+
}
160+
}
161+
162+
class YouTubeDownloader {
163+
ThirdPartyYouTubeLib _api;
164+
165+
YouTubeDownloader(ThirdPartyYouTubeLib api) : _api = api;
166+
167+
void renderVideoPage(String videoId) {
168+
Video video = _api.getVideo(videoId);
169+
print("${++lineNum}: -------------------------------");
170+
print("${++lineNum}: Video page (imagine fancy HTML)");
171+
print(
172+
"${++lineNum}: ID: ${video.id} && Title: ${video.title} && Video: ${video.data}");
173+
print("${++lineNum}: -------------------------------");
174+
}
175+
176+
void renderPopularVideos() {
177+
Map<String, Video> map = _api.popularVideos();
178+
print("${++lineNum}: -------------------------------");
179+
print("${++lineNum}: Most popular videos on YouTube (imagine fancy HTML)");
180+
181+
for (Video video in map.values) {
182+
print("${++lineNum}: ID: ${video.id} / Title: ${video.title}");
183+
}
184+
print("${++lineNum}: -------------------------------");
185+
}
186+
}
187+
188+
189+
```
190+
### Testing proxy main()
191+
```dart
192+
193+
void main() {
194+
// without proxy
195+
YouTubeDownloader naiveDownloader =
196+
YouTubeDownloader(ThirdPartyYouTubeClass());
197+
// with proxy
198+
YouTubeDownloader smartDownloader = YouTubeDownloader(YouTubeCacheProxy());
199+
200+
int naive = test(naiveDownloader);
201+
print(
202+
"${++lineNum}: -------------------------Proxy Added-------------------------");
203+
int smart = test(smartDownloader);
204+
print("${++lineNum}: Time elapsed without proxy = naive: $naive ms");
205+
print("${++lineNum}: Time elapsed with proxy = smart: $smart ms");
206+
print(
207+
"${++lineNum}: Time saved by caching proxy: ($naive - $smart= ${naive - smart}) ms");
208+
}
209+
210+
int test(YouTubeDownloader downloader) {
211+
int startTime = DateTime.now().millisecond;
212+
213+
// User behavior in our app:
214+
downloader.renderPopularVideos();
215+
downloader.renderVideoPage("catzzzzzzzzz");
216+
downloader.renderPopularVideos();
217+
downloader.renderVideoPage("dancesvideoo");
218+
// Users might visit the same page quite often.
219+
downloader.renderVideoPage("catzzzzzzzzz");
220+
downloader.renderVideoPage("someothervid");
221+
222+
int estimatedTime = DateTime.now().millisecond - startTime;
223+
return estimatedTime;
224+
}
225+
226+
```
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,161 @@
1+
import 'dart:math';
2+
3+
import 'video_model.dart';
4+
5+
int lineNum = 0;
6+
7+
abstract class ThirdPartyYouTubeLib {
8+
Map<String, Video> popularVideos();
9+
Video getVideo(String videoId);
10+
}
11+
12+
class ThirdPartyYouTubeClass implements ThirdPartyYouTubeLib {
13+
@override
14+
Map<String, Video> popularVideos() {
15+
_connectToServer("http://www.youtube.com");
16+
return _getPopularVideos();
17+
}
18+
19+
@override
20+
Video getVideo(String videoId) {
21+
_connectToServer("http://www.youtube.com/$videoId");
22+
return _getSomeVideo(videoId);
23+
}
24+
25+
// -----------------------------------------------------------------------
26+
// Fake methods to simulate network activity.
27+
// They as slow as a real life.
28+
29+
void _experienceNetworkLatency() {
30+
// int randomLatency = 5 + (Random().nextInt(10) * 6);
31+
int randomLatency = 10;
32+
for (int i = 0; i < randomLatency; i++) {
33+
try {
34+
Future.delayed(Duration(milliseconds: 100));
35+
} catch (ex) {
36+
print(ex);
37+
}
38+
}
39+
}
40+
41+
void _connectToServer(String server) {
42+
print("${++lineNum}: Connecting to $server ... ");
43+
_experienceNetworkLatency();
44+
print("${++lineNum}: Connected! ");
45+
}
46+
47+
Map<String, Video> _getPopularVideos() {
48+
print("${++lineNum}: Downloading popular Videos... ");
49+
_experienceNetworkLatency();
50+
_experienceNetworkLatency();
51+
Map<String, Video> map = Map<String, Video>();
52+
map["catzzzzzzzzz"] = Video(id: "sadgahasgdas", title: "Catzzzz.avi");
53+
map["dancesvideoo"] = Video(id: "asdfas3ffasd", title: "Dancing video.mpq");
54+
print("${++lineNum}: Done!");
55+
return map;
56+
}
57+
58+
Video _getSomeVideo(String videoId) {
59+
print("${++lineNum}: Downloading video... ");
60+
61+
_experienceNetworkLatency();
62+
Video video = Video(id: videoId, title: "Some video title");
63+
64+
print("${++lineNum}: Done!");
65+
return video;
66+
}
67+
}
68+
69+
class YouTubeCacheProxy implements ThirdPartyYouTubeLib {
70+
ThirdPartyYouTubeLib _youtubeService = ThirdPartyYouTubeClass();
71+
Map<String, Video> _cachePopular = Map<String, Video>();
72+
Map<String, Video> _cacheAll = Map<String, Video>();
73+
74+
YouTubeCacheProxy();
75+
76+
@override
77+
Map<String, Video> popularVideos() {
78+
if (_cachePopular.isEmpty) {
79+
_cachePopular = _youtubeService.popularVideos();
80+
} else {
81+
print("${++lineNum}: Retrieved list from cache.");
82+
}
83+
return _cachePopular;
84+
}
85+
86+
@override
87+
Video getVideo(String videoId) {
88+
Video? video = _cacheAll[videoId];
89+
if (video == null) {
90+
video = _youtubeService.getVideo(videoId);
91+
_cacheAll[videoId] = video;
92+
} else {
93+
print("${++lineNum}: Retrieved video ' $videoId ' from cache.");
94+
}
95+
return video;
96+
}
97+
98+
void reset() {
99+
_cachePopular.clear();
100+
_cacheAll.clear();
101+
}
102+
}
103+
104+
class YouTubeDownloader {
105+
ThirdPartyYouTubeLib _api;
106+
107+
YouTubeDownloader(ThirdPartyYouTubeLib api) : _api = api;
108+
109+
void renderVideoPage(String videoId) {
110+
Video video = _api.getVideo(videoId);
111+
print("${++lineNum}: -------------------------------");
112+
print("${++lineNum}: Video page (imagine fancy HTML)");
113+
print(
114+
"${++lineNum}: ID: ${video.id} && Title: ${video.title} && Video: ${video.data}");
115+
print("${++lineNum}: -------------------------------");
116+
}
117+
118+
void renderPopularVideos() {
119+
Map<String, Video> map = _api.popularVideos();
120+
print("${++lineNum}: -------------------------------");
121+
print("${++lineNum}: Most popular videos on YouTube (imagine fancy HTML)");
122+
123+
for (Video video in map.values) {
124+
print("${++lineNum}: ID: ${video.id} / Title: ${video.title}");
125+
}
126+
print("${++lineNum}: -------------------------------");
127+
}
128+
}
129+
130+
void main() {
131+
// without proxy
132+
YouTubeDownloader naiveDownloader =
133+
YouTubeDownloader(ThirdPartyYouTubeClass());
134+
// with proxy
135+
YouTubeDownloader smartDownloader = YouTubeDownloader(YouTubeCacheProxy());
136+
137+
int naive = test(naiveDownloader);
138+
print(
139+
"${++lineNum}: -------------------------Proxy Added-------------------------");
140+
int smart = test(smartDownloader);
141+
print("${++lineNum}: Time elapsed without proxy = naive: $naive ms");
142+
print("${++lineNum}: Time elapsed with proxy = smart: $smart ms");
143+
print(
144+
"${++lineNum}: Time saved by caching proxy: ($naive - $smart= ${naive - smart}) ms");
145+
}
146+
147+
int test(YouTubeDownloader downloader) {
148+
int startTime = DateTime.now().millisecond;
149+
150+
// User behavior in our app:
151+
downloader.renderPopularVideos();
152+
downloader.renderVideoPage("catzzzzzzzzz");
153+
downloader.renderPopularVideos();
154+
downloader.renderVideoPage("dancesvideoo");
155+
// Users might visit the same page quite often.
156+
downloader.renderVideoPage("catzzzzzzzzz");
157+
downloader.renderVideoPage("someothervid");
158+
159+
int estimatedTime = DateTime.now().millisecond - startTime;
160+
return estimatedTime;
161+
}

0 commit comments

Comments
 (0)