1. چیست الگوی نمونه‌ای (Proxy Pattern)

الگوی نمونه‌ای (Proxy Pattern) یک الگوی طراحی ساختاری است که به عنوان یک نماینده (proxy) عمل می‌کند تا دسترسی به یک شیء خاص را کنترل کند. بر اساس شیء هدف (شیءی که توسط proxy نماینده می‌شود)، الگوی نمونه‌ای یک شیء proxy ارائه می‌دهد که کلاینت‌ها می‌توانند از طریق آن به شیء هدف دسترسی پیدا کنند و این امکان را فراهم می‌کند که قابلیت‌های اضافی به شیء هدف اضافه شوند.

1.1 تعریف الگوی نمونه‌ای (Proxy Pattern)

الگوی نمونه‌ای (Proxy Pattern) یک الگوی طراحی است که شامل همکاری دو یا چند شیء است. یکی از این اشیاء شیء هدف واقعی است که فراخوانی می‌شود، در حالی که یک یا چند شیء دیگر به عنوان اشیاء proxy عمل می‌کنند. اشیاء proxy دسترسی به شیء هدف را از میان می‌گیرند و یک راه غیرمستقیم برای دسترسی به شیء هدف فراهم می‌کنند.

1.2 هدف و اهداف الگوی نمونه‌ای (Proxy Pattern)

هدف اصلی الگوی نمونه‌ای (Proxy Pattern) ایجاد یک راه غیرمستقیم برای دسترسی به شیء هدف است، که اجازه می‌دهد قابلیت‌های اضافی به شیء هدف اضافه شود. اشیاء proxy می‌توانند منطق‌های مشترکی را انجام دهند، مانند کنترل دسترسی به شیء هدف، حافظه پنهان (caching) و ثبت رویدادها (logging). الگوی نمونه‌ای (Proxy Pattern) همچنین می‌تواند بارگذاری تنبل (lazy loading) را پیاده‌سازی کند، به‌طوری‌که شیء هدف فقط در صورت نیاز نمونه‌سازی شود.

2. ویژگی‌ها و مزایای الگوی نمونه‌ای (Proxy Pattern)

الگوی نمونه‌ای (Proxy Pattern) دارای ویژگی‌ها و مزایای زیر است:

  • قابلیت گسترش قابلیت‌های شیء هدف بدون تغییر آن.
  • کنترل دسترسی به شیء هدف از طریق شیء proxy.
  • انجام عملیات اضافی قبل یا بعد از دسترسی به شیء هدف.
  • امکان پیاده‌سازی بارگذاری تنبل، فقط موقع نیاز شیء هدف را نمونه‌سازی کند.

3. نمونه‌های کاربردی عملی الگوی نمونه‌ای (Proxy Pattern)

الگوی نمونه‌ای (Proxy Pattern) در بسیاری از سناریوهای کاربردی استفاده می‌شود. در زیر چند نمونه معمول از کاربردهای عملی آورده شده است:

  • Proxy از راه دور: برای دسترسی به اشیاء در شبکه به صورت محلی استفاده می‌شود.
  • Proxy مجازی: برای ایجاد اشیاء گرانقیمت در هنگام نیاز استفاده می‌شود.
  • Proxy امنیتی: برای کنترل دسترسی به اشیاء استفاده می‌شود.
  • ارجاع هوشمند: برای انجام عملیات اضافی هنگام دسترسی به اشیاء مانند شمارش اشیاء استفاده می‌شود.

4.1 نمودار کلاس UML

در زیر نمودار کلاس UML الگوی نمونه‌ای (Proxy Pattern) در Golang آمده است:

Golang Proxy Pattern

4.2 مقدمه مثال

فرض کنید یک رابط Subject داریم که یک متد Request را تعریف می‌کند. کلاس پیاده‌سازی واقعی RealSubject را داریم که رابط Subject را پیاده‌سازی می‌کند. سپس یک کلاس نماینده Proxy ایجاد می‌شود که یک شیء RealSubject را نگهداری می‌کند و همچنین رابط Subject را پیاده‌سازی می‌کند. در متد Request کلاس Proxy، می‌توانیم عملیات اضافی قبل یا بعد از فراخوانی متد Request از RealSubject انجام دهیم.

4.3 گام ۱: تعریف رابط Proxy

در ابتدا، نیاز داریم یک رابط Subject را تعریف کنیم که حاوی یک متد Request باشد:

package main

type Subject interface {
    Request()
}

4.4 گام ۲: پیاده‌سازی شیء هدف

سپس، شیء هدف خاص RealSubject را پیاده‌سازی می‌کنیم که رابط Subject را پیاده‌سازی می‌کند:

package main

import "fmt"

type RealSubject struct {}

func (r *RealSubject) Request() {
    fmt.Println("RealSubject: Handling Request")
}

4.5 گام ۳: پیاده‌سازی شیء نماینده

سپس، یک شیء نماینده Proxy ایجاد می‌کنیم که یک شیء RealSubject را نگهداری می‌کند و رابط Subject را پیاده‌سازی می‌کند. در متد Request کلاس Proxy، می‌توانیم قبل یا بعد از فراخوانی متد Request شیء RealSubject، عملیات اضافی انجام دهیم:

package main

import "fmt"

type Proxy struct {
    realSubject *RealSubject
}

func (p *Proxy) Request() {
    fmt.Println("Proxy: Pre-Request")

    if p.realSubject == nil {
        p.realSubject = &RealSubject{}
    }
    
    p.realSubject.Request()
    
    fmt.Println("Proxy: Post-Request")
}

4.6 گام ۴: فراخوانی شیء نماینده

در نهایت، می‌توانیم از شیء نماینده Proxy استفاده کنیم تا متدهای شیء از RealSubject را فراخوانی کنیم:

package main

func main() {
    proxy := Proxy{}
    proxy.Request()
}

اجرای کد فوق خروجی زیر را تولید می‌کند:

Proxy: Pre-Request
RealSubject: Handling Request
Proxy: Post-Request

5.1 تفاوت و ارتباط بین الگوی پروکسی و الگوی دکوراتور

هر دو الگوی پروکسی و الگوی دکوراتور الگوهای طراحی ساختاری هستند که شامل یک شی هدف و یک شی پروکسی/دکوراتور می‌باشند. با این حال، تفاوت‌هایی بین این دو وجود دارد:

  • الگوی پروکسی به طور کلی شامل کنترل دسترسی به شی هدف است، در حالی که الگوی دکوراتور بیشتر بر توسعه شی هدف تمرکز دارد.
  • الگوی پروکسی به طور معمول عملیات اضافی قبل یا بعد از شی هدف را انجام می‌دهد، در حالی که الگوی دکوراتور به طور پویا قابلیت‌های اضافی را به شی هدف اضافه می‌کند.

5.2 مقایسه بین پروکسی استاتیک و پروکسی پویا

الگوی پروکسی را می‌توان به پروکسی استاتیک و پروکسی پویا تقسیم کرد. پروکسی استاتیک نوع شی پروکسی را در زمان کامپایل تعیین می‌کند و شی پروکسی به صورت دستی توسط برنامه نویس نوشته می‌شود. از سوی دیگر، پروکسی پویا، شی پروکسی را به صورت پویا در زمان اجرا بر اساس رابط شی هدف تولید می‌کند. پروکسی پویا انعطاف‌پذیرتر است اما نسبت به مقابل استاتیکش پیچیده‌تر است.

5.3 کاربرد الگوی پروکسی در معماری میکروسرویس

الگوی پروکسی می‌تواند در یک معماری میکروسرویس به کار رود. به عنوان مثال، می‌توان از یک پروکسی استفاده کرد تا دسترسی به سرویس‌های دیگر میکروسرویس‌ها را بسته‌بندی کرده و مکانیزم‌هایی مانند توازن بار، محدودیت نرخ و شکست مدار را در لایه پروکسی پیاده‌سازی کرد. این کار می‌تواند اعتمادپذیری و عملکرد سیستم را تقویت کند. الگوی پروکسی همچنین برای پیاده‌سازی کشف سرویس و قابلیت هدایت نیز مورد استفاده قرار می‌گیرد.