Skip to content

Commit 431e17b

Browse files
Mayur KadamMayur Kadam
authored andcommitted
Added Proxy Design Pattern
1 parent 6f803c5 commit 431e17b

File tree

5 files changed

+232
-0
lines changed

5 files changed

+232
-0
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
interface Account {
2+
withdraw(accountNumber: string, amount: number): void;
3+
checkBalance(accountNumber: string): number | null;
4+
nonAuthCheckPersonName(accountNumber: string): string;
5+
}
6+
7+
export { Account };
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
import { Account } from "./Account";
2+
3+
class Bank implements Account {
4+
private accounts: { [key: string]: { name: string; balance: number } } = {};
5+
6+
constructor(name: string, accountNumber: string, balance: number) {
7+
this.accounts[accountNumber] = { name, balance };
8+
}
9+
10+
withdraw(accountNumber: string, amount: number): void {
11+
const account = this.accounts[accountNumber];
12+
if (!account) {
13+
console.log("Account not found.");
14+
return;
15+
}
16+
17+
if (amount > account.balance) {
18+
console.log("Insufficient funds.");
19+
return;
20+
}
21+
22+
account.balance -= amount;
23+
console.log(`Withdrawn: $${amount}. Remaining balance: $${account.balance}`);
24+
}
25+
26+
checkBalance(accountNumber: string): number {
27+
return this.accounts[accountNumber].balance;
28+
}
29+
30+
nonAuthCheckPersonName(accountNumber: any): string {
31+
return this.accounts[accountNumber].name;
32+
}
33+
}
34+
35+
export { Bank };
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
import { Account } from "./Account";
2+
import { Bank } from "./Bank";
3+
4+
class ProxyServer implements Account {
5+
6+
bank: Bank;
7+
isAuthenticated: boolean;
8+
9+
constructor(bank: Bank, isAuthenticated: boolean = false) {
10+
this.bank = bank;
11+
this.isAuthenticated = isAuthenticated;
12+
}
13+
14+
withdraw(accountNumber: string, amount: number): void {
15+
if (!this.isAuthenticated) {
16+
console.log("Access Denied: Authentication required.");
17+
return;
18+
}
19+
20+
this.bank.withdraw(accountNumber, amount);
21+
}
22+
checkBalance(accountNumber: string): number | null {
23+
if (!this.isAuthenticated) {
24+
console.log("Access Denied: Authentication required.");
25+
return null;
26+
}
27+
28+
return this.bank.checkBalance(accountNumber);
29+
}
30+
nonAuthCheckPersonName(accountNumber: string): string {
31+
return this.bank.nonAuthCheckPersonName(accountNumber);
32+
}
33+
}
34+
35+
export { ProxyServer };
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
import { Bank } from "./Bank";
2+
import { ProxyServer } from "./ProxyServer";
3+
4+
const accountNumber = "MFHY2125466456645";
5+
const bankAccount = new Bank("Mayur", accountNumber, 35555455300);
6+
7+
8+
// DIRECT OPERATION WITHOUT PROXY
9+
console.log("Before Withdraw : ", bankAccount.checkBalance(accountNumber));
10+
bankAccount.withdraw(accountNumber, 1254668);
11+
console.log("After Withdraw : ", bankAccount.checkBalance(accountNumber));
12+
console.log("After Withdraw : ", bankAccount.nonAuthCheckPersonName(accountNumber));
13+
console.log();
14+
15+
// WITH PROXY with auth user
16+
const proxyServer = new ProxyServer(bankAccount, true);
17+
console.log("Before Withdraw : ", proxyServer.checkBalance(accountNumber));
18+
proxyServer.withdraw(accountNumber, 1254668);
19+
console.log("After Withdraw : ", proxyServer.checkBalance(accountNumber));
20+
console.log("After Withdraw : ", proxyServer.nonAuthCheckPersonName(accountNumber));
21+
console.log();
22+
23+
24+
// WITH PROXY with non auth user
25+
const proxyServer1 = new ProxyServer(bankAccount, false);
26+
console.log("Before Withdraw : ", proxyServer1.checkBalance(accountNumber));
27+
proxyServer1.withdraw(accountNumber, 1254668);
28+
console.log("After Withdraw : ", proxyServer1.checkBalance(accountNumber));
29+
console.log("After Withdraw : ", proxyServer1.nonAuthCheckPersonName(accountNumber));
30+
console.log()
Lines changed: 125 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,125 @@
1+
# Proxy Design Pattern in TypeScript
2+
3+
## πŸ“Œ Overview
4+
The **Proxy Design Pattern** is a **structural pattern** that provides a substitute or placeholder for another object to control access, add security, cache results, or perform lazy initialization.
5+
6+
In this example, we implement a **ProxyServer** that acts as a security layer for a **Bank** object. The proxy ensures that only authenticated users can perform transactions while allowing non-authenticated users to check account holder names.
7+
8+
---
9+
10+
## πŸ”„ **Flow of Execution**
11+
1. **`Bank` Class**: Stores user account details and provides methods for withdrawal, balance checking, and retrieving account holder names.
12+
2. **`ProxyServer` Class**: Acts as a middle layer, enforcing authentication before allowing access to sensitive operations like withdrawals and balance checks.
13+
3. **Client Code**:
14+
- Tries to withdraw money via the proxy.
15+
- If authenticated, the proxy forwards the request to the real `Bank` object.
16+
- If not authenticated, the proxy blocks access and displays an error.
17+
18+
---
19+
20+
## πŸš€ **Code Implementation**
21+
```typescript
22+
// Define a common interface for both Bank and Proxy
23+
interface Account {
24+
withdraw(accountNumber: string, amount: number): void;
25+
checkBalance(accountNumber: string): number;
26+
nonAuthCheckPersonName(accountNumber: string): string;
27+
}
28+
29+
// Real Bank implementation
30+
class Bank implements Account {
31+
private accounts: { [key: string]: { name: string; balance: number } } = {};
32+
33+
constructor(name: string, accountNumber: string, balance: number) {
34+
this.accounts[accountNumber] = { name, balance };
35+
}
36+
37+
withdraw(accountNumber: string, amount: number): void {
38+
const account = this.accounts[accountNumber];
39+
if (!account) {
40+
console.log("Account not found.");
41+
return;
42+
}
43+
44+
if (amount > account.balance) {
45+
console.log("Insufficient funds.");
46+
return;
47+
}
48+
49+
account.balance -= amount;
50+
console.log(`Withdrawn: $${amount}. Remaining balance: $${account.balance}`);
51+
}
52+
53+
checkBalance(accountNumber: string): number {
54+
return this.accounts[accountNumber]?.balance ?? 0;
55+
}
56+
57+
nonAuthCheckPersonName(accountNumber: string): string {
58+
return this.accounts[accountNumber]?.name ?? "Unknown";
59+
}
60+
}
61+
62+
// Proxy class implementing the same interface
63+
class ProxyServer implements BankAccount {
64+
private bank: Bank;
65+
private isAuthenticated: boolean;
66+
67+
constructor(bank: Bank, isAuthenticated: boolean) {
68+
this.bank = bank;
69+
this.isAuthenticated = isAuthenticated;
70+
}
71+
72+
withdraw(accountNumber: string, amount: number): void {
73+
if (!this.isAuthenticated) {
74+
console.log("Access Denied: Authentication required.");
75+
return;
76+
}
77+
this.bank.withdraw(accountNumber, amount);
78+
}
79+
80+
checkBalance(accountNumber: string): number {
81+
if (!this.isAuthenticated) {
82+
console.log("Access Denied: Authentication required.");
83+
return 0;
84+
}
85+
return this.bank.checkBalance(accountNumber);
86+
}
87+
88+
nonAuthCheckPersonName(accountNumber: string): string {
89+
return this.bank.nonAuthCheckPersonName(accountNumber);
90+
}
91+
}
92+
93+
// Usage example
94+
const realBank = new Bank("Alice", "12345", 1000);
95+
const proxy = new ProxyBankAccount(realBank, false);
96+
97+
proxy.withdraw("12345", 200); // Output: Access Denied: Authentication required.
98+
99+
const authProxy = new ProxyBankAccount(realBank, true);
100+
authProxy.withdraw("12345", 200); // Withdraws successfully
101+
```
102+
103+
---
104+
105+
## 🎯 **Benefits of the Proxy Pattern**
106+
βœ… **Access Control** – Restricts unauthorized users from performing sensitive actions.
107+
βœ… **Security Enhancement** – Prevents direct access to important objects.
108+
βœ… **Lazy Initialization** – Loads objects only when needed, optimizing resource usage.
109+
βœ… **Logging & Monitoring** – Allows tracking of actions before execution.
110+
βœ… **Performance Optimization** – Implements caching or request batching.
111+
112+
---
113+
114+
## πŸ“Œ **When to Use the Proxy Pattern?**
115+
πŸ”Ή **Security Proxies** – Control access to sensitive objects based on authentication.
116+
πŸ”Ή **Cache Proxy** – Store previously fetched data to improve performance.
117+
πŸ”Ή **Logging Proxy** – Log requests before executing operations.
118+
πŸ”Ή **Lazy Loading Proxy** – Load expensive objects only when required.
119+
πŸ”Ή **Virtual Proxy** – Represent resource-intensive objects with lightweight stand-ins.
120+
121+
---
122+
123+
## πŸ“š **Conclusion**
124+
The Proxy Design Pattern is an excellent way to enforce **security, access control, and optimization** without modifying the original class. By wrapping the **real object** with a **proxy**, we ensure that all interactions are controlled and managed efficiently. πŸš€
125+

0 commit comments

Comments
Β (0)