diff --git a/src/es05_bank.rs b/src/es05_bank.rs new file mode 100644 index 0000000..3de3343 --- /dev/null +++ b/src/es05_bank.rs @@ -0,0 +1,144 @@ +#![allow(dead_code)] + +use std::{fmt::Debug, rc::Rc}; + +use self::states::AccountState; + +/** + * Dovete implementare un ContoBancario che ha come informazioni + * - nome del cliente (una stringa) + * - ammontare del saldo + * - limite inferiore + * - limite superiore + * - interesse + * + * Le operazioni che si vogliono fare sono: + * - deposita che aggiunge al saldo la quantità depositata + * - preleva che rimuove dal saldo la quantità prelevata + * - paga gli interessi che aggiunge al saldo il saldo per l'interesse + * + * Queste operazioni hanno comportamenti diversi a seconda dello stato del conto, che può essere + * - Rosso (se il saldo e' minore del limite inferiore) + * - Argento (se il saldo e' minore del limite superiore e maggiore di quello inferiore) + * - Oro (se il saldo e' maggiore del limite superiore) + * + * In particolare: + * - prelevare da un conto Rosso non fa niente e cosi' pure paga interessi + * - paga interessi in un conto Argento non fa niente + * + * + * L'implementazione deve essere fatta usando il Pattern State. + * Dovete implementare un crate lib (quindi senza main) + * Mettere i test nella directory tests + */ +#[derive(Debug)] +pub struct BankAccount { + name: String, + balance: f32, + limit_hi: f32, + limit_lo: f32, + interest: f32, + state: Rc, +} + +impl BankAccount { + pub fn new(name: String, limit_lo: f32, limit_hi: f32, interest: f32) -> Self { + assert!( + limit_hi >= 0.0 || limit_lo >= 0.0, + "The limits must have a positive value!" + ); + assert!( + interest >= 0.0 && interest <= 1.0, + "The interest must have a value between 0 and 1!" + ); + + Self { + name, + balance: 0.0, + limit_hi, + limit_lo, + interest, + state: Rc::new(states::Red), + } + } + + pub fn balance(&self) -> f32 { + self.balance + } + + pub fn state(&self) -> String { + format!("{:?}", self.state.as_ref()) + } + + pub fn deposit(&mut self, amount: f32) { + if amount > 0.0 { + self.balance += amount; + self.set_state(); + } + } + + pub fn withdraw(&mut self, amount: f32) { + if amount > 0.0 { + let state = Rc::clone(&mut self.state); + state.withdraw(self, amount); + self.set_state(); + } + } + + pub fn pay_interest(&mut self) { + let state = Rc::clone(&mut self.state); + state.pay_interest(self); + self.set_state(); + } + + fn set_state(&mut self) { + self.state = if self.balance < self.limit_lo { + Rc::new(states::Red) + } else if self.balance > self.limit_hi { + Rc::new(states::Gold) + } else { + Rc::new(states::Silver) + }; + } +} + +/********************************************* + * Trait for States and implementations of it + */ +pub mod states { + use std::fmt::Debug; + + use super::BankAccount; + + pub trait AccountState: Debug { + fn withdraw(&self, account: &mut BankAccount, amount: f32); + fn pay_interest(&self, account: &mut BankAccount); + } + + #[derive(Debug)] + pub struct Red; + impl AccountState for Red { + fn withdraw(&self, _account: &mut BankAccount, _amount: f32) {} + fn pay_interest(&self, _account: &mut BankAccount) {} + } + + #[derive(Debug)] + pub struct Silver; + impl AccountState for Silver { + fn withdraw(&self, account: &mut BankAccount, amount: f32) { + account.balance -= amount; + } + fn pay_interest(&self, _account: &mut BankAccount) {} + } + + #[derive(Debug)] + pub struct Gold; + impl AccountState for Gold { + fn withdraw(&self, account: &mut BankAccount, amount: f32) { + account.balance -= amount; + } + fn pay_interest(&self, account: &mut BankAccount) { + account.balance -= account.balance * account.interest; + } + } +} diff --git a/src/lib.rs b/src/lib.rs index 0278b59..b33b911 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -2,3 +2,5 @@ pub mod es01_anagram; pub mod es02_rational; pub mod es03_game; pub mod es04_rational_traits; +pub mod es05_bank; + diff --git a/tests/es05_bank.rs b/tests/es05_bank.rs new file mode 100644 index 0000000..cca0c83 --- /dev/null +++ b/tests/es05_bank.rs @@ -0,0 +1,37 @@ +use esercizi::es05_bank::BankAccount; + +#[test] +fn test_bank() { + let name = "Nome".to_string(); + let mut account = BankAccount::new(name.clone(), 1000.0, 10000.0, 0.02); + assert_eq!(account.balance(), 0.0); + assert_eq!(account.state(), "Red"); + + account.deposit(1001.0); + assert_eq!(account.balance(), 1001.0); + assert_eq!(account.state(), "Silver"); + + account.pay_interest(); + assert_eq!(account.balance(), 1001.0); + assert_eq!(account.state(), "Silver"); + + account.withdraw(100.0); + assert_eq!(account.balance(), 901.0); + assert_eq!(account.state(), "Red"); + + account.withdraw(1.0); + assert_eq!(account.balance(), 901.0); + assert_eq!(account.state(), "Red"); + + account.deposit(100000.0); + assert_eq!(account.balance(), 100901.0); + assert_eq!(account.state(), "Gold"); + + account.pay_interest(); + assert_eq!(account.balance(), 98882.98); + assert_eq!(account.state(), "Gold"); + + account.withdraw(90882.98); + assert_eq!(account.balance(), 8000.0); + assert_eq!(account.state(), "Silver"); +}