*بعد از تلاشهای بسیار و حل چالشهای قبلی، شما به شرکت رایان همافزار پیوستهاید!*
![توضیح تصویر](https://quera.org/qbox/view/0tbk999rWu/D.svg)
از شما خواسته شده است تا سیستم پرداختهای مختلفی را که مشتریان استفاده میکنند، طراحی کنید. این سیستم باید بهطور کامل پرداختهای مختلف از جمله پرداخت با کارت اعتباری، کیف پول دیجیتال و نقدی را مدیریت کند. جزئیات این تسک بهشرح زیر است.
هدف شما این است که سیستم پرداختهای مختلف را در یک محیط شبیهسازی کنید که از حسابهای بانکی مختلف برای انجام تراکنشها استفاده کند. پرداختها باید به حساب مقصد منتقل شوند و موجودی حسابها بهروزرسانی گردد. در صورت بروز هرگونه کمبود موجودی، باید پیغام خطای مناسب نمایش داده شود.
# پروژه اولیه
پروژه شما باید شامل چند کلاس اصلی باشد که سیستم پرداختها را مدیریت کنند. ساختار فایلهای پروژه بهصورت زیر است:
پروژهی اولیهی این سؤال را میتوانید از [این لینک](/problemset/assignments/4367/download_problem_initial_project/268838/) دانلود کنید.
```
init.zip
├── Account.java
├── Payment.java
├── CreditCardPayment.java
├── DigitalWalletPayment.java
├── CashPayment.java
└── Main.java
```
در این ساختار، شما با چندین کلاس مختلف برای مدیریت پرداختها سر و کار دارید. `Account` نمایانگر حسابهای بانکی است که هر حساب میتواند یک موجودی داشته باشد. `Payment` کلاس پایهای است که پرداختها را مدیریت میکند. شما باید از این کلاس برای ساخت انواع مختلف پرداختها استفاده کنید.
# کلاس `Account`
کلاس `Account` نمایانگر یک حساب بانکی است. هر حساب دارای نام و موجودی است. همچنین، میتوان موجودی حساب را بررسی کرده و واریز یا برداشت از آن انجام داد. در این کلاس باید امکان برداشت از حسابها و مدیریت موجودی را داشته باشد. همچنین، در صورت تلاش برای برداشت بیشتر از موجودی، خطای کمبود موجودی به کاربر نمایش داده میشود.
# کلاس `Payment`
کلاس `Payment` یک کلاس انتزاعی است که روشهای پرداخت مختلف از جمله پرداخت با کارت اعتباری، کیف پول دیجیتال و پرداخت نقدی از آن ارث میبرند. این کلاس متدی به نام `processPayment()` دارد که فرایند هر پرداخت را انجام میدهد.
# پرداختها
شما باید سه روش پرداخت مختلف را پیادهسازی کنید:
+ پرداخت با کارت اعتباری (`CreditCardPayment`): این کلاس باید اطلاعات مربوط به کارت اعتباری را نگهداری کرده و عملیات برداشت از حساب و واریز به حساب مقصد را انجام دهد.
+ پرداخت با کیف پول دیجیتال (`DigitalWalletPayment`): این کلاس باید اطلاعات مربوط به کیف پول دیجیتال و ایمیل صاحب کیف پول را نگهداری کرده و مانند پرداخت کارت اعتباری، عملیات مالی را انجام دهد.
+ پرداخت نقدی (`CashPayment`): این کلاس باید میزان مبلغ نقدی را مشخص کرده و مشابه دو نوع دیگر، پرداخت را انجام دهد.
جزئیات پیادهسازی این سه کلاس در ادامه آورده شده است.
<details class="blue">
<summary>
**توضیحات کلاس `CreditCardPayment`**
</summary>
----------
پرداخت با کارت اعتباری باید شامل ویژگیها و متدهای زیر باشد:
+ `sourceAccount`: حساب مبدا که پرداخت از آن انجام میشود.
+ `destinationAccount`: حساب مقصد که پرداخت به آن انجام میشود.
+ `amount`: مبلغ پرداخت.
سازنده این کلاس بهصورت زیر است:
```java
public CreditCardPayment(Account sourceAccount, Account destinationAccount, int amount)
```
این سازنده باید ویژگیهای کلاس را مقداردهی کند.
متد `processPayment()` باید بررسی کند که حساب مبدا موجودی کافی برای پرداخت دارد. اگر موجودی کافی بود، مبلغ مشخصشده را از حساب مبدا کم کند و مبلغ را به حساب مقصد واریز کند.
در صورت موفقیتآمیز بودن پرداخت، پیام
```
Credit card payment processed: {amount}
```
برگردانده شود که در آن `{amount}`، یک عدد است که مقدار تراکنش را نشان میدهد.
همچنین اگر موجودی کافی نبود، پیغام خطای زیر را برگرداند:
```
Insufficient funds in account: {accountName}
```
</details>
<details class="blue">
<summary>
**توضیحات کلاس `DigitalWalletPayment`**
</summary>
----------
پرداخت با کیف پول دیجیتال باید شامل ویژگیها و متدهای زیر باشد:
+ `sourceAccount`: حساب مبدا که پرداخت از آن انجام میشود.
+ `destinationAccount`: حساب مقصد که پرداخت به آن انجام میشود.
+ `walletName`: نام کیف پول دیجیتال.
+ `email`: ایمیل صاحب کیف پول دیجیتال.
+ `amount`: مبلغ پرداخت.
سازنده این کلاس بهصورت زیر است:
```java
public DigitalWalletPayment(Account sourceAccount, Account destinationAccount, String walletName, String email, int amount)
```
این سازنده باید ویژگیهای کلاس را مقداردهی کند.
متد `processPayment()` باید بررسی کند که حساب مبدا موجودی کافی برای پرداخت دارد. اگر موجودی کافی بود مبلغ مشخصشده را از حساب مبدا کم کند و مبلغ را به حساب مقصد واریز کند. سپس یک پیام موفقیت به صورت زیر برگرداند:
```
Payment of {amount} processed via {walletName} for {email}.
```
و اگر موجودی کافی نبود، پیغام خطای زیر را برگرداند:
```
Insufficient funds in account: {accountName}
```
</details>
<details class="blue">
<summary>
**توضیحات کلاس `CashPayment`**
</summary>
----------
پرداخت نقدی باید شامل ویژگیها و متدهای زیر باشد:
+ `sourceAccount`: حساب مبدا که پرداخت از آن انجام میشود.
+ `destinationAccount`: حساب مقصد که پرداخت به آن انجام میشود.
+ `amount`: مبلغ پرداخت.
سازنده این کلاس بهصورت زیر است:
```java
public CashPayment(Account sourceAccount, Account destinationAccount, int amount)
```
این سازنده باید ویژگیهای کلاس را مقداردهی کند.
متد `processPayment()` باید بررسی کند که حساب مبدا موجودی کافی برای پرداخت دارد.
اگر موجودی کافی بود، مبلغ مشخصشده را از حساب مبدا کم کند، مبلغ را به حساب مقصد واریز کند و یک پیام موفقیت به صورت زیر برگرداند:
```
Cash payment of {amount} completed.
```
اگر موجودی کافی نبود، پیغام خطای زیر را برگرداند:
```
Insufficient funds in account: {accountName}
```
پس از پیادهسازی کامل، مطمئن شوید که برنامه شما تست میشود و تمامی سناریوها (مانند موفقیت در پرداخت یا خطای کمبود موجودی) به درستی مدیریت شدهاند.
</details>
# نکات
+ کد شما باید از **اصول شیگرایی و مدیریت خطا** برای پیادهسازی انواع مختلف پرداختها و حسابها استفاده کند.
+ برای هر کلاس متدهای `get` و `set` برای دسترسی به ویژگیهای آنها ایجاد کنید.
+ در صورتی که کاربر سعی کند مبلغی بیشتر از موجودی خود برداشت کند، باید پیغام خطای مناسب چاپ شود.
+ از طراحی کد بهگونهای استفاده کنید که بهراحتی بتوانید انواع جدید پرداختها را به سیستم اضافه کنید.
+ تمام این کلاسهای پرداخت باید از کلاس انتزاعی `Payment` ارثبری کنند و متد `processPayment()` را پیادهسازی نمایند.
+ برای مدیریت حسابها، از متدهای موجود در کلاس `Account` برای برداشت و واریز استفاده کنید.
# نمونه
در زیر نمونهای از نحوه استفاده از کلاسها برای انجام پرداختها آورده شده است:
```java Main.java
package org.example.solution;
public class Main {
public static void main(String[] args) {
Account account1 = new Account("Ali", 1000);
Account account2 = new Account("Sara", 2000);
System.out.println(account1.logBalance());
System.out.println(account2.logBalance());
Payment[] payments = new Payment[]{
new CreditCardPayment(account1, account2, 500),
new DigitalWalletPayment(account2, account1, "wallet1", "email@email.com", 300),
new CashPayment(account1, account2, 900) // این پرداخت باید خطای کمبود موجودی بدهد
};
for (Payment payment : payments) {
System.out.println(payment.processPayment());
}
System.out.println(account1.logBalance());
System.out.println(account2.logBalance());
}
}
```
در این مثال، حسابها مقدار اولیهای دارند و پرداختها بهصورت مختلف پردازش میشوند. خروجی باید بهصورت زیر باشد:
```
Account: Ali, Balance: 1000
Account: Sara, Balance: 2000
Credit card payment processed: 500
Payment of 300 processed via wallet1 for email@email.com.
Insufficient funds in account: Ali
Account: Ali, Balance: 800
Account: Sara, Balance: 2200
```
# آنچه باید ارسال کنید
پس از پیادهسازی سیستم، تنها فایلهای کلاسهای پیادهسازیشده را در قالب یک فایل فشرده ارسال کنید. از درج کردن `package` در فایلها پرهیز کنید. انتظار میرود باقی فایلها را تغییر ندهید و میتوانید فرض کنید که همین فایلها به همین شکل در زمان اجرای پروژه نیز در کنار برنامهی شما موجودند.
```
[your-solution-files-name].zip
├── CreditCardPayment.java
├── DigitalWalletPayment.java
└── CashPayment.java
```
پرداختها و حسابهای بانکی