2.8. Proxy¶
2.8.1. تعریف¶
دیزاین پترن Proxy یک الگوی طراحی ساختاری محسوب میشه که به شما اجازه میده یک جانشین برای آبجکت مورد نظرتون ایجاد کنید.
در واقع میشه گفت پراکسی، با قرار گرفتن بین آبجکت اصلی و Client، نحوه دسترسی به آبجکت اصلی رو کنترل می کنه و اجازه میده اتفاقاتی قبل و بعد از دسترسی به آبجکت مورد نظر رخ بده.
2.8.2. چه زمانی استفاده میشه؟¶
این الگو میتونه در موارد مختلفی استفاده بشه.
به عنوان مثال میتونه برای Lazy initialization یا Virtual Proxy استفاده بشه.
در واقع زمانی که یک سرویس سنگین داریم که منابع زیادی در سیستم مصرف می کنه اما نیاز نیست همیشه در دسترس باشه میتونیم با استفاده از این الگو، initialize کردن آبجکت رو تا زمانی که واقعا بهش نیاز هست به تاخیر بندازیم.
یا میتونه به عنوان پراکسی حفاظتی یا Protection استفاده بشه و اجازه دسترسی کاربر رو قبل از دسترسی به آبجکت مورد نظر چک کنه.
همچنین در کاربرد های متنوع دیگه ای مثل log کردن درخواست قبل از اجرا، کش کردن اطلاعات و استفاده از کش به جای نمایش داده اصلی و… استفاده میشه.
کلا خیلی الگوی پرکاربردی محسوب میشه!
2.8.3. اجزاء¶
یک دیزاین پترن Proxy از چند بخشی اصلی تشکیل میشه.
قبل از هر چیز یک کلاس اصلی داریم که قرار هست پراکسی باهاش در ارتباط باشه که RealSubject نام داره.
بعد از اون Subject رو داریم که در واقع interface مشترک بین RealSubject و Proxy هست و عملکرد اصلی برنامه رو مشخص می کنه.
مشخصا Proxy رو داریم که قرار هست به عنوان جایگزینی برای کلاس اصلی یا همون RealSubject توسط Client مورد استفاده قرار بگیره.
پراکسی در این بین ممکنه عملیات مختلفی رو قبل از دسترسی به کلاس اصلی انجام بده، مواردی مثل بهینه سازی، کش کردن، بررسی بحث های سطوح دسترسی و…
و در نهایت هم که مثل همیشه Client رو داریم.
Traced by User:Stannered, created by en:User:TravisHein, CC BY-SA 3.0, via Wikimedia Commons
Caution
✅ مزایای استفاده
امکان اعمال کنترل روی سرویس مورد نظر بدون اینکه client از نحوه ی اعمال آن با خبر باشد
پراکسی میتونه بدون در دسترس بودن سرویس اصلی به کار خودش ادامه بده!
اصل Open/Closed به علت امکان تعریف پراکسی های جدید بدون تغییر سرویس رعایت میشه
Warning
❌ معایب استفاده
ممکنه سرعت دسترسی به سرویس کمی کاهش پیدا کنه
به علت احتمال تعریف تعداد زیادی کلاس جدید، کد پیچیده تر خواهد شد
2.8.4. کاربرد عملی¶
خب این الگوی طراحی کاربردهای متنوعی داره که بالاتر هم بهشون اشاره شد.
ما یکی از کاربردهای اون که کش کردن هست رو سعی می کنیم پیاده سازی کنیم.
فرض کنید یک سیستم داریم که در بخشی از اون اطلاعات آب و هوا باید از یک API دریافت بشه.
برای اینکه مجبور نباشیم هر بار این API رو فراخوانی کنیم سعی می کنیم از یک کلاس پراکسی در این میان استفاده کنیم.
2.8.5. پیاده سازی¶
قبل از هر چیز Subject رو مشخص می کنیم:
1<?php
2
3interface Subject
4{
5 public function request(): void;
6}
و حالا سرویس اصلی ما که به این صورت تعریف شده:
1<?php
2
3class WeatherService implements Subject
4{
5 private string $apiKey;
6 private string $baseUrl;
7
8 public function __construct(string $apiKey, string $baseUrl)
9 {
10 $this->apiKey = $apiKey;
11 $this->baseUrl = $baseUrl;
12 }
13
14 public function request(): void
15 {
16 // Make an HTTP request to the remote API to retrieve weather information
17 // using the API key and base URL provided.
18 // ...
19 echo "WeatherService: Retrieving weather information from remote API.\n";
20 }
21}
حالا پراکسی رو تعریف می کنیم که کارش اینه که قبل از ارسال درخواست بررسی می کنه آیا نتیجه در کش موجود هست یا نه:
1<?php
2
3class WeatherServiceProxy implements Subject
4{
5 private WeatherService $weatherService;
6 private array $cache;
7
8 public function __construct(string $apiKey, string $baseUrl)
9 {
10 $this->weatherService = new WeatherService($apiKey, $baseUrl);
11 $this->cache = [];
12 }
13
14 public function request(): void
15 {
16 // Check if the weather information is already in the cache.
17 $cacheKey = $this->generateCacheKey();
18 if (isset($this->cache[$cacheKey])) {
19 echo "WeatherServiceProxy: Retrieving weather information from cache.\n";
20 return;
21 }
22
23 // Otherwise, retrieve the weather information from the remote API.
24 $this->weatherService->request();
25
26 // Cache the retrieved weather information for future requests.
27 $this->cache[$cacheKey] = true;
28 }
29
30 private function generateCacheKey(): string
31 {
32 // Generate a cache key based on the current date and time.
33 return date('Y-m-d H:i');
34 }
35}
2.8.6. نحوه فراخوانی¶
1<?php
2
3echo "Client: Executing the client code with a real weather service:\n";
4$weatherService = new WeatherService('your_api_key', 'https://api.weather.com');
5clientCode($weatherService);
6
7echo "\n";
8
9echo "Client: Executing the same client code with a weather service proxy:\n";
10$weatherServiceProxy = new WeatherServiceProxy('your_api_key', 'https://api.weather.com');
11clientCode($weatherServiceProxy);
فکر کنم نیاز به توضیح نداره و همه چیز کاملا مشخص و واضحه!