برنامه نویسی

اصل تعویض لیسکوف آسان است: نمونه های عملی

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

اصل تعویض لیسکوف گسترش اصل باز/نزدیک است

با کلمات ساده

  1. اشیاء یک ابر کلاس باید بدون تأثیرگذاری بر برنامه ، با اشیاء یک زیر کلاس جایگزین شوند.
  2. شی زیر کلاس باید بتواند به تمام روش ها و خصوصیات ابرقهرمان دسترسی پیدا کند.

بیایید مثالی برای درک این موضوع بگوییم 🙁 از آنجا

همانطور که اکنون دیدیم که اگر انواع مختلفی از حساب بانکی داشته باشیم ، می توانیم با گسترش کلاس BankAccount یک بانک جدید ایجاد کنیم

اکنون فرض کنید اکنون برای سپرده ثابت نوع جدید BankAccount داریم. از اصل باز/بسته ما به سادگی می توانیم این کار را انجام دهیم

class FixedDepositAccount extends BankAccount{
      withdrawAmount(newAmount: number): void {
          throw new Error("Cannot withdraw from Fixed Deposit when in locing period.");
      }
      depositAmount(newAmount: number): void {
        this.setAmount = this.getAmount + newAmount;
      }

  }

const fixedAccount = new FixedDepositAccount("Manas", "123");
fixedAccount.depositAmount(1234567);
حالت تمام صفحه را وارد کنید

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

از آنجا که ما نمی توانیم از FixifdepositAccount خارج شویم ، خطایی برای آن ایجاد می کنیم

بیایید فرض کنیم ما BankWithdrawlService و ما می خواهیم مبلغ را از حساب های مختلف برداشت کنیم.

class BankWithdrawService {
    private _bankAccount:BankAccount

    constructor(bankAccount:BankAccount){
        this._bankAccount=bankAccount
    }

    withdrawAmount(amount:number){
        this._bankAccount.withdrawAmount(amount)
    }
}

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

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

اکنون اصل لیسکوف می گوید که هر زیر کلاس یک کلاس باید بتواند آن را جایگزین کند. بنابراین اکنون اگر سعی کنیم مبلغ را از کلاس Fixifdeposit (زیر کلاس BankAccount) برداشت کنیم ، خطایی دریافت خواهیم کرد که اصل Liskov را نقض می کند

const bankWithdrawlService = new BankWithdrawService(fixedAccount)
bankWithdrawlService.withdrawAmount(123)

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

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

خطا: در دوره قفل نمی تواند از سپرده ثابت خارج شود.

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

مراحل نزدیک شدن:-

  1. ما یک رابط برای روش سپرده ایجاد می کنیم ، زیرا در حال حاضر تمام حساب های بانکی که در آن سپرده گذاری کرده ایم
  2. سپس ما رابط دیگری برای روش برداشت برای حساب های برداشت ایجاد می کنیم
  3. اکنون ما یک کلاس اصلی BankAccount ایجاد می کنیم که رابط سپرده را پیاده سازی می کند
  4. سپس ما یک کلاس انتزاعی قابل برداشت ایجاد می کنیم که کلاس BankAccount را گسترش می دهد و همچنین رابط قابل برداشت را پیاده سازی می کند
  5. اکنون ما از کلاس انتزاعی قابل استفاده برای پس انداز و حساب جاری استفاده ساده استفاده می کنیم
  6. و کلاس انتزاعی BankAccount برای حساب FixedDeposit
interface IDepositAmount {
  depositAmount(amount: number): void;
}

interface IWithdrawAmount {
  withdrawAmount(amount: number): void;
}
abstract class BankAccount implements IDepositAmount {
  private _customerName: string;
  private _customerId: string;
  private _amount: number = 10000;

  constructor(customerName: string, customerId: string) {
    this._customerName = customerName;
    this._customerId = customerId;
  }
  abstract depositAmount(amount: number): void;

  public get getAmount(): number {
    return this._amount;
  }

  public set setAmount(amount: number) {
    this._amount = amount;
  }
}

abstract class WithdrawableAccount
  extends BankAccount
  implements IWithdrawAmount
{
  constructor(customerName: string, customerId: string) {
    super(customerName, customerId);
  }
  abstract withdrawAmount(amount: number): void;
}

class SavingsAccount extends WithdrawableAccount {
  constructor(customerName: string, customerId: string) {
    super(customerName, customerId);
  }

  withdrawAmount(newAmount: number): void {
    this.setAmount = this.getAmount - this.getAmount * 0.005 - newAmount;
  }

  depositAmount(newAmount: number): void {
    this.setAmount = this.getAmount + this.getAmount * 0.005 + newAmount;
  }
}

class CurrentAccount extends WithdrawableAccount {
  constructor(customerName: string, customerId: string) {
    super(customerName, customerId);
  }

  withdrawAmount(newAmount: number): void {
    this.setAmount = this.getAmount - this.getAmount * 0.005 - newAmount;
  }

  depositAmount(newAmount: number): void {
    this.setAmount = this.getAmount + this.getAmount * 0.005 + newAmount;
  }
}

class FixedDepositAccount extends BankAccount {
  depositAmount(amount: number): void {
    this.setAmount = this.getAmount + amount;
  }
}
const fixedAccount = new FixedDepositAccount("Manas", "123");
fixedAccount.depositAmount(1234567);

class BankWithdrawService {
  private _withdrawableAccount: WithdrawableAccount;

  constructor(withdrawableAccount: WithdrawableAccount) {
    this._withdrawableAccount = withdrawableAccount;
  }

  withdrawAmount(amount: number) {
    this._withdrawableAccount.withdrawAmount(amount);
  }
}

const withdrawableAccount = new SavingsAccount("Manas","123")

const bankWithdrawlService = new BankWithdrawService(withdrawableAccount);
bankWithdrawlService.withdrawAmount(123);

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

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

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

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

  2. کیفیت کد بهبود یافته: با دنبال کردن LSP ، کد قابل درک تر و نگهداری آسان تر می شود.

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

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

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

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