برنامه نویسی

چگونه می توان از پلی مورفیسم برای طراحی نرم افزار انعطاف پذیر و قابل نگهداری که به اصول SOLID پایبند است استفاده کرد

Summarize this content to 400 words in Persian Lang
من یک آموزش جامع در مورد استفاده از چند شکلی برای طراحی نرم افزار انعطاف پذیر و قابل نگهداری که به اصول SOLID پایبند است، با استفاده از C# برای مثال ارائه خواهم کرد.

آموزش: استفاده از چند شکلی برای طراحی نرم افزار انعطاف پذیر و قابل نگهداری

مقدمه ای بر پلی مورفیسم

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

دو نوع اصلی پلی مورفیسم وجود دارد:

چند شکلی زمان کامپایل (بارگذاری بیش از حد روش)
چند شکلی زمان اجرا (روش نادیده گرفته شده)

ما بر روی چندشکلی زمان اجرا تمرکز خواهیم کرد زیرا بیشتر با طراحی سیستم های انعطاف پذیر مرتبط است.

بررسی اجمالی اصول جامد

قبل از اینکه به پیاده سازی بپردازیم، اجازه دهید به طور خلاصه اصول SOLID را مرور کنیم:

اصل مسئولیت واحد (SRP)
اصل باز/بسته (OCP)
اصل جایگزینی لیسکوف (LSP)
اصل جداسازی رابط (ISP)
اصل وارونگی وابستگی (DIP)

خواهیم دید که چگونه چندشکلی به ما کمک می کند تا به این اصول پایبند باشیم.

مثال عملی: سیستم اطلاع رسانی

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

مرحله 1: تعریف رابط

ابتدا یک رابط برای سیستم اطلاع رسانی خود تعریف می کنیم:

public interface INotificationService
{
void SendNotification(string recipient, string message);
}

وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

این با متمرکز و ساده نگه داشتن رابط، به اصل جداسازی رابط پایبند است.

مرحله 2: اجرای کلاس های بتن

اکنون، بیایید کلاس های مشخصی را برای هر روش اطلاع رسانی پیاده سازی کنیم:

public class EmailNotificationService : INotificationService
{
public void SendNotification(string recipient, string message)
{
// Email-specific logic here
Console.WriteLine($”Sending email to {recipient}: {message}”);
}
}

public class SmsNotificationService : INotificationService
{
public void SendNotification(string recipient, string message)
{
// SMS-specific logic here
Console.WriteLine($”Sending SMS to {recipient}: {message}”);
}
}

public class PushNotificationService : INotificationService
{
public void SendNotification(string recipient, string message)
{
// Push notification-specific logic here
Console.WriteLine($”Sending push notification to {recipient}: {message}”);
}
}

وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

هر کلاس یک مسئولیت دارد که به اصل مسئولیت واحد پایبند است.

مرحله 3: یک مدیر اعلان را پیاده سازی کنید

اکنون، بیایید یک کلاس NotificationManager ایجاد کنیم که از این خدمات استفاده می کند:

public class NotificationManager
{
private readonly INotificationService _notificationService;

public NotificationManager(INotificationService notificationService)
{
_notificationService = notificationService;
}

public void Notify(string recipient, string message)
{
_notificationService.SendNotification(recipient, message);
}
}

وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

این کلاس با توجه به انتزاع (INotificationService) به جای پیاده سازی مشخص، به اصل وارونگی وابستگی پایبند است.

مرحله 4: استفاده از سیستم اطلاع رسانی

در اینجا نحوه استفاده از سیستم اطلاع رسانی خود آمده است:

class Program
{
static void Main(string[] args)
{
// Using email notification
var emailManager = new NotificationManager(new EmailNotificationService());
emailManager.Notify(“user@example.com”, “Your order has been shipped!”);

// Using SMS notification
var smsManager = new NotificationManager(new SmsNotificationService());
smsManager.Notify(“+1234567890”, “Your order has been shipped!”);

// Using push notification
var pushManager = new NotificationManager(new PushNotificationService());
pushManager.Notify(“user123”, “Your order has been shipped!”);
}
}

وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

مزایا و اصول جامد در عمل

اصل باز/بسته: سیستم ما برای گسترش باز است (می‌توانیم سرویس‌های اعلان جدید اضافه کنیم) اما برای اصلاح بسته است (برای افزودن سرویس‌های جدید نیازی به تغییر کد موجود نداریم).
اصل جایگزینی Liskov: هر INotificationService را می توان به جای یکدیگر در NotificationManager استفاده کرد.
وارونگی وابستگی: NotificationManager به انتزاع INotificationService بستگی دارد نه به پیاده سازی های مشخص.

افزودن یک روش اعلان جدید

برای نشان دادن انعطاف‌پذیری این طراحی، بیایید یک روش اعلان جدید اضافه کنیم – اعلان‌های Slack:

public class SlackNotificationService : INotificationService
{
public void SendNotification(string recipient, string message)
{
// Slack-specific logic here
Console.WriteLine($”Sending Slack message to {recipient}: {message}”);
}
}

// Usage
var slackManager = new NotificationManager(new SlackNotificationService());
slackManager.Notify(“#general”, “New product announcement!”);

وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

ما یک روش اعلان جدید بدون تغییر کد موجود اضافه کرده‌ایم که قدرت چندشکلی و پایبندی به اصول SOLID را نشان می‌دهد.

پیشرفت های بیشتر

برای انعطاف پذیری بیشتر سیستم، پیشرفت های زیر را در نظر بگیرید:

Factory Pattern: یک کارخانه برای ایجاد INotificationService مناسب بر اساس تنظیمات یا پارامترهای زمان اجرا پیاده سازی کنید.
الگوی ترکیبی: یک CompositeNotificationService ایجاد کنید که می تواند اعلان ها را از طریق چندین کانال به طور همزمان ارسال کند.
الگوی دکوراتور: نگرانی های متقاطع مانند ورود به سیستم یا امتحان مجدد منطق را بدون تغییر سرویس های موجود اضافه کنید.

نتیجه گیری:

با استفاده از چند شکلی و رعایت اصول SOLID، یک سیستم اعلان ایجاد کرده ایم که به شرح زیر است:

انعطاف پذیر: به راحتی می توان روش های اعلان جدید را اضافه کرد
قابل نگهداری: هر کلاس یک مسئولیت دارد
توسعه پذیر: قابلیت های جدید را می توان بدون تغییر کد موجود اضافه کرد
قابل آزمایش: وابستگی ها برای آزمایش واحد به راحتی قابل تمسخر هستند

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

این هم یک مثال دیگر:

طراحی شی گرا برای پارکینگ

بر اساس الزامات ارائه شده، می توانیم مفاهیم اصلی زیر را شناسایی کنیم:

پارکینگ: نمایانگر کل پارکینگ با چندین طبقه است.

طبقه: نمایانگر یک طبقه در داخل پارکینگ است.

پارکینگ اسپات: نمایانگر یک پارکینگ واحد است.

وسیله نقلیه: نشان دهنده وسیله نقلیه ای است که می تواند پارک کند.

بلیط: نشان دهنده یک بلیط پارکینگ صادر شده برای مشتری است.

پرداخت: یک تراکنش پرداخت را نشان می دهد.

کاربر: نماینده یک مشتری یا مدیر است.

کلاس های اصلی و روابط

پارکینگ

ویژگی ها: طبقه، ورودی، نقطه خروج، صفحه نمایش
روش‌ها: addFloor، removeFloor، getAvailableSpots، displayParkingStatus

طبقه

ویژگی ها: شماره کف، نقاط پارکینگ، تابلوی نمایش
روش ها: getAvailableSpotsByVehicleType

پارکینگ اسپات

ویژگی ها: spotNumber، spotType، isOccupied، وسیله نقلیه (در صورت اشغال)
روش ها: در دسترس است، اشغال، خالی کردن

وسیله نقلیه

ویژگی ها: نوع خودرو، پلاک مجوز
روش ها: پارک کردن، پارک کردن

بلیط

ویژگی ها: شماره بلیط، زمان صدور، وسیله نقلیه، مقدار کل
روش ها: محاسبه مقدار

پرداخت

ویژگی ها: روش پرداخت، مبلغ، بلیط
روش ها: فرآیند پرداخت

کاربر

ویژگی ها: userType (مشتری، مدیر، پارکینگAttendant)
روش ها: تولید بلیط، بلیط پرداخت، وضعیت پارکینگ مشاهده کنید

چند شکلی و اصول جامد

وسیله نقلیه: می توانیم یک چکیده معرفی کنیم Vehicle کلاس با ویژگی هایی مانند vehicleType و روش هایی مانند park و unpark. این به ما اجازه می دهد تا با به ارث بردن از خودرو، انواع مختلف وسیله نقلیه (ماشین، کامیون، موتور سیکلت و غیره) ایجاد کنیم Vehicle کلاس این پایبند است اصل باز-بسته همانطور که می توانیم انواع خودروهای جدید را بدون تغییر کد موجود اضافه کنیم.

پارکینگ اسپات: ما می توانیم انتزاعی ایجاد کنیم ParkingSpot کلاس با ویژگی هایی مانند spotNumber، isOccupiedو روش هایی مانند isAvailable، occupy، و vacate. انواع مختلف پارکینگ (کامپکت، بزرگ، معلولان، برقی) می توانند از این کلاس پایه به ارث برده و پیاده سازی های خاصی را برای ویژگی های منحصر به فرد خود ارائه دهند. این پایبند است اصل جایگزینی لیسکوف مانند هر ParkingSpot را می توان به عنوان یک ژنریک در نظر گرفت ParkingSpot.

پرداخت: ما می توانیم یک رابط معرفی کنیم IPaymentProcessor با یک processPayment روش روش‌های پرداخت مختلف (پول نقد، کارت اعتباری) می‌توانند این رابط را پیاده‌سازی کنند و گزینه‌های پرداخت انعطاف‌پذیر را فراهم کنند. این پایبند است اصل جداسازی رابط زیرا مشتریان فقط باید در مورد آن بدانند IPaymentProcessor رابط کاربری

ملاحظات اضافی

نرخ پارکینگ: یک کلاس جداگانه برای مدیریت نرخ پارکینگ بر اساس زمان و نوع وسیله نقلیه.

صفحه نمایش: یک کلاس یا رابط انتزاعی برای انواع مختلف صفحه نمایش (LED، LCD).

Ticket Generator: کلاسی که مسئول تولید شماره بلیط منحصر به فرد است.

درگاه پرداخت: کلاسی برای ادغام با ارائه دهندگان پرداخت مختلف.

الگوهای طراحی

الگوی کارخانه: برای ایجاد انواع مختلف وسایل نقلیه و مکان های پارک.

الگوی استراتژی: برای اجرای استراتژی های مختلف پرداخت.

الگوی مشاهده گر: برای اطلاع به اشخاص علاقه مند (مثلاً تابلوهای نمایش) هنگام تغییر وضعیت پارکینگ.

پیاده سازی پلی مورفیسم و ​​جامد در سیستم پارکینگ

چند شکلی در کلاس خودرو

public abstract class Vehicle
{
public string LicensePlate { get; set; }
public VehicleType Type { get; set; }

public abstract int CalculateParkingFee(int hoursParked);
public abstract bool FitsInSpot(ParkingSpot spot);
}

public class Car : Vehicle
{
public override int CalculateParkingFee(int hoursParked)
{
// Calculate fee based on car parking rates
return …;
}

public override bool FitsInSpot(ParkingSpot spot)
{
return spot.SpotType == SpotType.Compact || spot.SpotType == SpotType.Large;
}
}

public class Truck : Vehicle
{
public override int CalculateParkingFee(int hoursParked)
{
// Calculate fee based on truck parking rates
return …;
}

public override bool FitsInSpot(ParkingSpot spot)
{
return spot.SpotType == SpotType.Large;
}
}

وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

چند شکلی: را Vehicle کلاس یک کلاس پایه انتزاعی با CalculateParkingFee و FitsInSpot روش هایی که به صورت انتزاعی تعریف می شوند. کلاس های مشتق شده مانند Car و Truck پیاده سازی مشخصی برای این روش ها ارائه می دهد.

جامد: پایبند است اصل باز-بسته به عنوان انواع خودروهای جدید را می توان بدون تغییر کد موجود اضافه کرد.

چند شکلی در کلاس پارکینگ اسپات

public abstract class ParkingSpot
{
public int SpotNumber { get; set; }
public bool IsOccupied { get; set; }
public SpotType SpotType { get; set; }

public abstract bool CanPark(Vehicle vehicle);
}

public class CompactSpot : ParkingSpot
{
public override bool CanPark(Vehicle vehicle)
{
return vehicle.Type == VehicleType.Car || vehicle.Type == VehicleType.Motorcycle;
}
}

public class LargeSpot : ParkingSpot
{
public override bool CanPark(Vehicle vehicle)
{
return true; // Can accommodate any vehicle
}
}

وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

چند شکلی: را ParkingSpot کلاس یک کلاس پایه انتزاعی با CanPark روش کلاس های مشتق شده مانند CompactSpot و LargeSpot پیاده سازی های خاصی را بر اساس نوع خودرو ارائه می دهد.

جامد: پایبند است اصل جایگزینی لیسکوف مانند هر ParkingSpot می تواند به عنوان یک پایه در نظر گرفته شود ParkingSpot.

رابط پردازشگر پرداخت

public interface IPaymentProcessor
{
void ProcessPayment(decimal amount, Ticket ticket);
}

وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

جامد: پایبند است اصل جداسازی رابط با تعریف یک رابط خاص برای پردازش پرداخت.

پیاده سازی پردازشگر پرداخت

public class CreditCardPaymentProcessor : IPaymentProcessor
{
public void ProcessPayment(decimal amount, Ticket ticket)
{
// Process payment using credit card details
}
}

public class CashPaymentProcessor : IPaymentProcessor
{
public void ProcessPayment(decimal amount, Ticket ticket)
{
// Process cash payment
}
}

وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

چند شکلی: پردازشگرهای پرداخت مختلف این را اجرا می کنند IPaymentProcessor رابط کاربری

جامد: پایبند است اصل باز-بسته به عنوان روش های پرداخت جدید را می توان بدون تغییر کد موجود اضافه کرد.

ملاحظات اضافی

تزریق وابستگی: از تزریق وابستگی برای تزریق پردازشگرهای پرداخت به سیستم پارکینگ استفاده کنید و اتصال شل را تقویت کنید.

الگوی کارخانه: ایجاد یک ParkingSpotFactory برای ایجاد انواع مختلف نقاط پارک بر اساس پیکربندی.

الگوی استراتژی: از الگوی استراتژی برای استراتژی های مختلف محاسبه هزینه پارکینگ استفاده کنید.

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

پیاده سازی الگوی کارخانه در سیستم پارکینگ

درک نیاز به یک کارخانه

در سیستم پارکینگ ما انواع مختلفی از نقاط پارک (کوچک، بزرگ، معلولان و غیره) و وسایل نقلیه (خودرو، کامیون، موتور سیکلت و غیره) داریم. برای جدا کردن ایجاد این اشیاء از کد کلاینت و انعطاف‌پذیری بیشتر سیستم، می‌توانیم یک الگوی Factory معرفی کنیم.

ایجاد کارخانه

public interface ISpotFactory
{
ParkingSpot CreateParkingSpot(SpotType spotType);
}

public class ParkingSpotFactory : ISpotFactory
{
public ParkingSpot CreateParkingSpot(SpotType spotType)
{
switch (spotType)
{
case SpotType.Compact:
return new CompactSpot();
case SpotType.Large:
return new LargeSpot();
// … other spot types
default:
throw new ArgumentException(“Invalid spot type”);
}
}
}

وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

با استفاده از کارخانه

// In ParkingLot class
private readonly ISpotFactory _spotFactory;

public ParkingLot(ISpotFactory spotFactory)
{
_spotFactory = spotFactory;
}

public void AddParkingSpot(SpotType spotType)
{
var parkingSpot = _spotFactory.CreateParkingSpot(spotType);
// … add parking spot to the floor
}

وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

مزایای استفاده از الگوی کارخانه

جداسازی: کد مشتری (ParkingLot) از اجرای بتنی نقاط پارکینگ جدا شده است.

انعطاف پذیری: انواع جدید نقطه ای را می توان بدون تغییر کلاس ParkingLot اضافه کرد.

توسعه پذیری: کارخانه را می توان سفارشی کرد یا با پیاده سازی های مختلف جایگزین کرد.

ملاحظات اضافی

تزریق وابستگی: از تزریق وابستگی برای تزریق استفاده کنید ISpotFactory به ParkingLot کلاس، ترویج جفت شل.

الگوی روش کارخانه: اگر به انعطاف‌پذیری بیشتری نیاز دارید، از الگوی Factory Method استفاده کنید که در آن منطق ایجاد به زیر کلاس‌های یک کارخانه منتقل می‌شود.

الگوی کارخانه چکیده: برای ایجاد خانواده‌های اشیاء مرتبط، مانند انواع مختلف وسایل نقلیه و مکان‌های پارک با هم، الگوی Abstract Factory ممکن است مناسب باشد.

با اعمال الگوی Factory، انعطاف پذیری و قابلیت نگهداری سیستم پارکینگ خود را بهبود بخشیده ایم. اکنون معرفی انواع جدیدی از مکان‌های پارک بدون تأثیرگذاری بر کد موجود آسان‌تر است.

من یک آموزش جامع در مورد استفاده از چند شکلی برای طراحی نرم افزار انعطاف پذیر و قابل نگهداری که به اصول SOLID پایبند است، با استفاده از C# برای مثال ارائه خواهم کرد.

آموزش: استفاده از چند شکلی برای طراحی نرم افزار انعطاف پذیر و قابل نگهداری

  1. مقدمه ای بر پلی مورفیسم

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

دو نوع اصلی پلی مورفیسم وجود دارد:

  • چند شکلی زمان کامپایل (بارگذاری بیش از حد روش)
  • چند شکلی زمان اجرا (روش نادیده گرفته شده)

ما بر روی چندشکلی زمان اجرا تمرکز خواهیم کرد زیرا بیشتر با طراحی سیستم های انعطاف پذیر مرتبط است.

  1. بررسی اجمالی اصول جامد

قبل از اینکه به پیاده سازی بپردازیم، اجازه دهید به طور خلاصه اصول SOLID را مرور کنیم:

  • اصل مسئولیت واحد (SRP)
  • اصل باز/بسته (OCP)
  • اصل جایگزینی لیسکوف (LSP)
  • اصل جداسازی رابط (ISP)
  • اصل وارونگی وابستگی (DIP)

خواهیم دید که چگونه چندشکلی به ما کمک می کند تا به این اصول پایبند باشیم.

  1. مثال عملی: سیستم اطلاع رسانی

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

مرحله 1: تعریف رابط

ابتدا یک رابط برای سیستم اطلاع رسانی خود تعریف می کنیم:

public interface INotificationService
{
    void SendNotification(string recipient, string message);
}
وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

این با متمرکز و ساده نگه داشتن رابط، به اصل جداسازی رابط پایبند است.

مرحله 2: اجرای کلاس های بتن

اکنون، بیایید کلاس های مشخصی را برای هر روش اطلاع رسانی پیاده سازی کنیم:

public class EmailNotificationService : INotificationService
{
    public void SendNotification(string recipient, string message)
    {
        // Email-specific logic here
        Console.WriteLine($"Sending email to {recipient}: {message}");
    }
}

public class SmsNotificationService : INotificationService
{
    public void SendNotification(string recipient, string message)
    {
        // SMS-specific logic here
        Console.WriteLine($"Sending SMS to {recipient}: {message}");
    }
}

public class PushNotificationService : INotificationService
{
    public void SendNotification(string recipient, string message)
    {
        // Push notification-specific logic here
        Console.WriteLine($"Sending push notification to {recipient}: {message}");
    }
}
وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

هر کلاس یک مسئولیت دارد که به اصل مسئولیت واحد پایبند است.

مرحله 3: یک مدیر اعلان را پیاده سازی کنید

اکنون، بیایید یک کلاس NotificationManager ایجاد کنیم که از این خدمات استفاده می کند:

public class NotificationManager
{
    private readonly INotificationService _notificationService;

    public NotificationManager(INotificationService notificationService)
    {
        _notificationService = notificationService;
    }

    public void Notify(string recipient, string message)
    {
        _notificationService.SendNotification(recipient, message);
    }
}
وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

این کلاس با توجه به انتزاع (INotificationService) به جای پیاده سازی مشخص، به اصل وارونگی وابستگی پایبند است.

مرحله 4: استفاده از سیستم اطلاع رسانی

در اینجا نحوه استفاده از سیستم اطلاع رسانی خود آمده است:

class Program
{
    static void Main(string[] args)
    {
        // Using email notification
        var emailManager = new NotificationManager(new EmailNotificationService());
        emailManager.Notify("user@example.com", "Your order has been shipped!");

        // Using SMS notification
        var smsManager = new NotificationManager(new SmsNotificationService());
        smsManager.Notify("+1234567890", "Your order has been shipped!");

        // Using push notification
        var pushManager = new NotificationManager(new PushNotificationService());
        pushManager.Notify("user123", "Your order has been shipped!");
    }
}
وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

  1. مزایا و اصول جامد در عمل
  • اصل باز/بسته: سیستم ما برای گسترش باز است (می‌توانیم سرویس‌های اعلان جدید اضافه کنیم) اما برای اصلاح بسته است (برای افزودن سرویس‌های جدید نیازی به تغییر کد موجود نداریم).

  • اصل جایگزینی Liskov: هر INotificationService را می توان به جای یکدیگر در NotificationManager استفاده کرد.

  • وارونگی وابستگی: NotificationManager به انتزاع INotificationService بستگی دارد نه به پیاده سازی های مشخص.

  1. افزودن یک روش اعلان جدید

برای نشان دادن انعطاف‌پذیری این طراحی، بیایید یک روش اعلان جدید اضافه کنیم – اعلان‌های Slack:

public class SlackNotificationService : INotificationService
{
    public void SendNotification(string recipient, string message)
    {
        // Slack-specific logic here
        Console.WriteLine($"Sending Slack message to {recipient}: {message}");
    }
}

// Usage
var slackManager = new NotificationManager(new SlackNotificationService());
slackManager.Notify("#general", "New product announcement!");
وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

ما یک روش اعلان جدید بدون تغییر کد موجود اضافه کرده‌ایم که قدرت چندشکلی و پایبندی به اصول SOLID را نشان می‌دهد.

  1. پیشرفت های بیشتر

برای انعطاف پذیری بیشتر سیستم، پیشرفت های زیر را در نظر بگیرید:

  • Factory Pattern: یک کارخانه برای ایجاد INotificationService مناسب بر اساس تنظیمات یا پارامترهای زمان اجرا پیاده سازی کنید.
  • الگوی ترکیبی: یک CompositeNotificationService ایجاد کنید که می تواند اعلان ها را از طریق چندین کانال به طور همزمان ارسال کند.
  • الگوی دکوراتور: نگرانی های متقاطع مانند ورود به سیستم یا امتحان مجدد منطق را بدون تغییر سرویس های موجود اضافه کنید.

نتیجه گیری:

با استفاده از چند شکلی و رعایت اصول SOLID، یک سیستم اعلان ایجاد کرده ایم که به شرح زیر است:

  • انعطاف پذیر: به راحتی می توان روش های اعلان جدید را اضافه کرد
  • قابل نگهداری: هر کلاس یک مسئولیت دارد
  • توسعه پذیر: قابلیت های جدید را می توان بدون تغییر کد موجود اضافه کرد
  • قابل آزمایش: وابستگی ها برای آزمایش واحد به راحتی قابل تمسخر هستند

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

این هم یک مثال دیگر:

طراحی شی گرا برای پارکینگ

بر اساس الزامات ارائه شده، می توانیم مفاهیم اصلی زیر را شناسایی کنیم:

  • پارکینگ: نمایانگر کل پارکینگ با چندین طبقه است.
  • طبقه: نمایانگر یک طبقه در داخل پارکینگ است.
  • پارکینگ اسپات: نمایانگر یک پارکینگ واحد است.
  • وسیله نقلیه: نشان دهنده وسیله نقلیه ای است که می تواند پارک کند.
  • بلیط: نشان دهنده یک بلیط پارکینگ صادر شده برای مشتری است.
  • پرداخت: یک تراکنش پرداخت را نشان می دهد.
  • کاربر: نماینده یک مشتری یا مدیر است.

کلاس های اصلی و روابط

پارکینگ

  • ویژگی ها: طبقه، ورودی، نقطه خروج، صفحه نمایش
  • روش‌ها: addFloor، removeFloor، getAvailableSpots، displayParkingStatus

طبقه

  • ویژگی ها: شماره کف، نقاط پارکینگ، تابلوی نمایش
  • روش ها: getAvailableSpotsByVehicleType

پارکینگ اسپات

  • ویژگی ها: spotNumber، spotType، isOccupied، وسیله نقلیه (در صورت اشغال)
  • روش ها: در دسترس است، اشغال، خالی کردن

وسیله نقلیه

  • ویژگی ها: نوع خودرو، پلاک مجوز
  • روش ها: پارک کردن، پارک کردن

بلیط

  • ویژگی ها: شماره بلیط، زمان صدور، وسیله نقلیه، مقدار کل
  • روش ها: محاسبه مقدار

پرداخت

  • ویژگی ها: روش پرداخت، مبلغ، بلیط
  • روش ها: فرآیند پرداخت

کاربر

  • ویژگی ها: userType (مشتری، مدیر، پارکینگAttendant)
  • روش ها: تولید بلیط، بلیط پرداخت، وضعیت پارکینگ مشاهده کنید

چند شکلی و اصول جامد

  • وسیله نقلیه: می توانیم یک چکیده معرفی کنیم Vehicle کلاس با ویژگی هایی مانند vehicleType و روش هایی مانند park و unpark. این به ما اجازه می دهد تا با به ارث بردن از خودرو، انواع مختلف وسیله نقلیه (ماشین، کامیون، موتور سیکلت و غیره) ایجاد کنیم Vehicle کلاس این پایبند است اصل باز-بسته همانطور که می توانیم انواع خودروهای جدید را بدون تغییر کد موجود اضافه کنیم.
  • پارکینگ اسپات: ما می توانیم انتزاعی ایجاد کنیم ParkingSpot کلاس با ویژگی هایی مانند spotNumber، isOccupiedو روش هایی مانند isAvailable، occupy، و vacate. انواع مختلف پارکینگ (کامپکت، بزرگ، معلولان، برقی) می توانند از این کلاس پایه به ارث برده و پیاده سازی های خاصی را برای ویژگی های منحصر به فرد خود ارائه دهند. این پایبند است اصل جایگزینی لیسکوف مانند هر ParkingSpot را می توان به عنوان یک ژنریک در نظر گرفت ParkingSpot.
  • پرداخت: ما می توانیم یک رابط معرفی کنیم IPaymentProcessor با یک processPayment روش روش‌های پرداخت مختلف (پول نقد، کارت اعتباری) می‌توانند این رابط را پیاده‌سازی کنند و گزینه‌های پرداخت انعطاف‌پذیر را فراهم کنند. این پایبند است اصل جداسازی رابط زیرا مشتریان فقط باید در مورد آن بدانند IPaymentProcessor رابط کاربری

ملاحظات اضافی

  • نرخ پارکینگ: یک کلاس جداگانه برای مدیریت نرخ پارکینگ بر اساس زمان و نوع وسیله نقلیه.
  • صفحه نمایش: یک کلاس یا رابط انتزاعی برای انواع مختلف صفحه نمایش (LED، LCD).
  • Ticket Generator: کلاسی که مسئول تولید شماره بلیط منحصر به فرد است.
  • درگاه پرداخت: کلاسی برای ادغام با ارائه دهندگان پرداخت مختلف.

الگوهای طراحی

  • الگوی کارخانه: برای ایجاد انواع مختلف وسایل نقلیه و مکان های پارک.
  • الگوی استراتژی: برای اجرای استراتژی های مختلف پرداخت.
  • الگوی مشاهده گر: برای اطلاع به اشخاص علاقه مند (مثلاً تابلوهای نمایش) هنگام تغییر وضعیت پارکینگ.

پیاده سازی پلی مورفیسم و ​​جامد در سیستم پارکینگ

چند شکلی در کلاس خودرو

public abstract class Vehicle
{
    public string LicensePlate { get; set; }
    public VehicleType Type { get; set; }

    public abstract int CalculateParkingFee(int hoursParked);
    public abstract bool FitsInSpot(ParkingSpot spot);
}

public class Car : Vehicle
{
    public override int CalculateParkingFee(int hoursParked)
    {
        // Calculate fee based on car parking rates
        return ...;
    }

    public override bool FitsInSpot(ParkingSpot spot)
    {
        return spot.SpotType == SpotType.Compact || spot.SpotType == SpotType.Large;
    }
}

public class Truck : Vehicle
{
    public override int CalculateParkingFee(int hoursParked)
    {
        // Calculate fee based on truck parking rates
        return ...;
    }

    public override bool FitsInSpot(ParkingSpot spot)
    {
        return spot.SpotType == SpotType.Large;
    }
}
وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

  • چند شکلی: را Vehicle کلاس یک کلاس پایه انتزاعی با CalculateParkingFee و FitsInSpot روش هایی که به صورت انتزاعی تعریف می شوند. کلاس های مشتق شده مانند Car و Truck پیاده سازی مشخصی برای این روش ها ارائه می دهد.
  • جامد: پایبند است اصل باز-بسته به عنوان انواع خودروهای جدید را می توان بدون تغییر کد موجود اضافه کرد.

چند شکلی در کلاس پارکینگ اسپات

public abstract class ParkingSpot
{
    public int SpotNumber { get; set; }
    public bool IsOccupied { get; set; }
    public SpotType SpotType { get; set; }

    public abstract bool CanPark(Vehicle vehicle);
}

public class CompactSpot : ParkingSpot
{
    public override bool CanPark(Vehicle vehicle)
    {
        return vehicle.Type == VehicleType.Car || vehicle.Type == VehicleType.Motorcycle;
    }
}

public class LargeSpot : ParkingSpot
{
    public override bool CanPark(Vehicle vehicle)
    {
        return true; // Can accommodate any vehicle
    }
}
وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

  • چند شکلی: را ParkingSpot کلاس یک کلاس پایه انتزاعی با CanPark روش کلاس های مشتق شده مانند CompactSpot و LargeSpot پیاده سازی های خاصی را بر اساس نوع خودرو ارائه می دهد.
  • جامد: پایبند است اصل جایگزینی لیسکوف مانند هر ParkingSpot می تواند به عنوان یک پایه در نظر گرفته شود ParkingSpot.

رابط پردازشگر پرداخت

public interface IPaymentProcessor
{
    void ProcessPayment(decimal amount, Ticket ticket);
}
وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

  • جامد: پایبند است اصل جداسازی رابط با تعریف یک رابط خاص برای پردازش پرداخت.

پیاده سازی پردازشگر پرداخت

public class CreditCardPaymentProcessor : IPaymentProcessor
{
    public void ProcessPayment(decimal amount, Ticket ticket)
    {
        // Process payment using credit card details
    }
}

public class CashPaymentProcessor : IPaymentProcessor
{
    public void ProcessPayment(decimal amount, Ticket ticket)
    {
        // Process cash payment
    }
}
وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

  • چند شکلی: پردازشگرهای پرداخت مختلف این را اجرا می کنند IPaymentProcessor رابط کاربری
  • جامد: پایبند است اصل باز-بسته به عنوان روش های پرداخت جدید را می توان بدون تغییر کد موجود اضافه کرد.

ملاحظات اضافی

  • تزریق وابستگی: از تزریق وابستگی برای تزریق پردازشگرهای پرداخت به سیستم پارکینگ استفاده کنید و اتصال شل را تقویت کنید.
  • الگوی کارخانه: ایجاد یک ParkingSpotFactory برای ایجاد انواع مختلف نقاط پارک بر اساس پیکربندی.
  • الگوی استراتژی: از الگوی استراتژی برای استراتژی های مختلف محاسبه هزینه پارکینگ استفاده کنید.

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

پیاده سازی الگوی کارخانه در سیستم پارکینگ

درک نیاز به یک کارخانه

در سیستم پارکینگ ما انواع مختلفی از نقاط پارک (کوچک، بزرگ، معلولان و غیره) و وسایل نقلیه (خودرو، کامیون، موتور سیکلت و غیره) داریم. برای جدا کردن ایجاد این اشیاء از کد کلاینت و انعطاف‌پذیری بیشتر سیستم، می‌توانیم یک الگوی Factory معرفی کنیم.

ایجاد کارخانه

public interface ISpotFactory
{
    ParkingSpot CreateParkingSpot(SpotType spotType);
}

public class ParkingSpotFactory : ISpotFactory
{
    public ParkingSpot CreateParkingSpot(SpotType spotType)
    {
        switch (spotType)
        {
            case SpotType.Compact:
                return new CompactSpot();
            case SpotType.Large:
                return new LargeSpot();
            // ... other spot types
            default:
                throw new ArgumentException("Invalid spot type");
        }
    }
}
وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

با استفاده از کارخانه

// In ParkingLot class
private readonly ISpotFactory _spotFactory;

public ParkingLot(ISpotFactory spotFactory)
{
    _spotFactory = spotFactory;
}

public void AddParkingSpot(SpotType spotType)
{
    var parkingSpot = _spotFactory.CreateParkingSpot(spotType);
    // ... add parking spot to the floor
}
وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

مزایای استفاده از الگوی کارخانه

  • جداسازی: کد مشتری (ParkingLot) از اجرای بتنی نقاط پارکینگ جدا شده است.
  • انعطاف پذیری: انواع جدید نقطه ای را می توان بدون تغییر کلاس ParkingLot اضافه کرد.
  • توسعه پذیری: کارخانه را می توان سفارشی کرد یا با پیاده سازی های مختلف جایگزین کرد.

ملاحظات اضافی

  • تزریق وابستگی: از تزریق وابستگی برای تزریق استفاده کنید ISpotFactory به ParkingLot کلاس، ترویج جفت شل.
  • الگوی روش کارخانه: اگر به انعطاف‌پذیری بیشتری نیاز دارید، از الگوی Factory Method استفاده کنید که در آن منطق ایجاد به زیر کلاس‌های یک کارخانه منتقل می‌شود.
  • الگوی کارخانه چکیده: برای ایجاد خانواده‌های اشیاء مرتبط، مانند انواع مختلف وسایل نقلیه و مکان‌های پارک با هم، الگوی Abstract Factory ممکن است مناسب باشد.

با اعمال الگوی Factory، انعطاف پذیری و قابلیت نگهداری سیستم پارکینگ خود را بهبود بخشیده ایم. اکنون معرفی انواع جدیدی از مکان‌های پارک بدون تأثیرگذاری بر کد موجود آسان‌تر است.

نوشته های مشابه

دیدگاهتان را بنویسید

نشانی ایمیل شما منتشر نخواهد شد. بخش‌های موردنیاز علامت‌گذاری شده‌اند *

دکمه بازگشت به بالا