-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathProgram.cs
More file actions
521 lines (413 loc) · 14.3 KB
/
Program.cs
File metadata and controls
521 lines (413 loc) · 14.3 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
/*Bank Account System that demonstrates:
Polymorphism (base class + derived classes overriding behavior)
SRP (Single Responsibility Principle) — each class has a clear, single purpose
OCP (Open/Closed Principle) — system is open for extension (e.g. new account types), closed for modification
LSP (Liskov Substitution Principle) — derived account types can be used wherever a base account is expected
Sealed Logger — cannot be inherited
using System;
// SRP: This class represents a generic bank account.
public abstract class BankAccount
{
public string AccountNumber { get; }
public string HolderName { get; }
public decimal Balance { get; protected set; }
protected BankAccount(string accountNumber, string holderName, decimal initialBalance)
{
AccountNumber = accountNumber;
HolderName = holderName;
Balance = initialBalance;
}
public virtual void Deposit(decimal amount)
{
if (amount <= 0)
{
TransactionLogger.Instance.Log("Deposit failed: Invalid amount.");
return;
}
Balance += amount;
TransactionLogger.Instance.Log($"Deposited {amount:C} to {AccountNumber}. New balance: {Balance:C}");
}
public abstract void Withdraw(decimal amount);
public override string ToString() => $"{HolderName} - {AccountNumber} - Balance: {Balance:C}";
}
// OCP + LSP: SavingsAccount extends BankAccount, can replace it anywhere.
public class SavingsAccount : BankAccount
{
private const decimal WithdrawalLimit = 1000m;
public SavingsAccount(string accountNumber, string holderName, decimal initialBalance)
: base(accountNumber, holderName, initialBalance) { }
public override void Withdraw(decimal amount)
{
if (amount <= 0 || amount > Balance)
{
TransactionLogger.Instance.Log("Savings withdrawal failed: Invalid amount.");
return;
}
if (amount > WithdrawalLimit)
{
TransactionLogger.Instance.Log($"Savings withdrawal failed: Amount exceeds limit of {WithdrawalLimit:C}.");
return;
}
Balance -= amount;
TransactionLogger.Instance.Log($"Withdrew {amount:C} from savings account {AccountNumber}. New balance: {Balance:C}");
}
}
// OCP + LSP: CurrentAccount adds overdraft capability.
public class CurrentAccount : BankAccount
{
private const decimal OverdraftLimit = 500m;
public CurrentAccount(string accountNumber, string holderName, decimal initialBalance)
: base(accountNumber, holderName, initialBalance) { }
public override void Withdraw(decimal amount)
{
if (amount <= 0)
{
TransactionLogger.Instance.Log("Current withdrawal failed: Invalid amount.");
return;
}
if (Balance - amount < -OverdraftLimit)
{
TransactionLogger.Instance.Log("Current withdrawal failed: Exceeds overdraft limit.");
return;
}
Balance -= amount;
TransactionLogger.Instance.Log($"Withdrew {amount:C} from current account {AccountNumber}. New balance: {Balance:C}");
}
}
// SRP + sealed (cannot be inherited): handles logging only.
public sealed class TransactionLogger
{
private static readonly TransactionLogger _instance = new TransactionLogger();
private TransactionLogger() { }
public static TransactionLogger Instance => _instance;
public void Log(string message)
{
Console.WriteLine($"[{DateTime.Now:HH:mm:ss}] {message}");
}
}
// Demonstration
public class Program
{
public static void Main()
{
BankAccount savings = new SavingsAccount("SA001", "Alice", 2000m);
BankAccount current = new CurrentAccount("CA001", "Bob", 500m);
savings.Deposit(300);
savings.Withdraw(1200); // exceeds limit
savings.Withdraw(800);
current.Deposit(200);
current.Withdraw(900); // allowed with overdraft
current.Withdraw(900); // exceeds overdraft
Console.WriteLine();
Console.WriteLine(savings);
Console.WriteLine(current);
}
}
/*
| Principle | How It’s Applied |
| ------------------------------- | -------------------------------------------------------------------------------------------------------- |
| **SRP (Single Responsibility)** | Each class has one responsibility — `BankAccount` manages balances, `TransactionLogger` handles logging. |
| **OCP (Open/Closed)** | You can add new account types (e.g. `BusinessAccount`) without modifying existing classes. |
| **LSP (Liskov Substitution)** | `SavingsAccount` and `CurrentAccount` can both be used as `BankAccount` without breaking functionality. |
| **Polymorphism** | The `Withdraw()` method is overridden in derived classes for specific behavior. |
| **Sealed Class** | `TransactionLogger` is sealed to prevent extension and ensure consistent logging behavior. |
/*
E-Commerce Discount Engine, showing abstraction, polymorphism, and OCP (Open/Closed Principle).
*/
/*
using System;
// Base abstract class: defines a common contract for all discounts
public abstract class Discount
{
// Method to calculate final price after applying discount
public abstract decimal ApplyDiscount(decimal originalPrice);
}
// Derived class: percentage-based discount (e.g. 10%)
public class PercentageDiscount : Discount
{
private readonly decimal _percentage;
public PercentageDiscount(decimal percentage)
{
_percentage = percentage;
}
public override decimal ApplyDiscount(decimal originalPrice)
{
if (_percentage < 0 || _percentage > 100)
{
Console.WriteLine("Invalid percentage discount.");
return originalPrice;
}
decimal discountAmount = originalPrice * (_percentage / 100m);
return originalPrice - discountAmount;
}
}
// Derived class: fixed amount discount (e.g. $20 off)
public class FixedDiscount : Discount
{
private readonly decimal _amount;
public FixedDiscount(decimal amount)
{
_amount = amount;
}
public override decimal ApplyDiscount(decimal originalPrice)
{
if (_amount < 0)
{
Console.WriteLine("Invalid fixed discount amount.");
return originalPrice;
}
decimal finalPrice = originalPrice - _amount;
return finalPrice < 0 ? 0 : finalPrice;
}
}
// Sealed class: represents no discount (cannot be inherited)
public sealed class NoDiscount : Discount
{
public override decimal ApplyDiscount(decimal originalPrice)
{
return originalPrice; // no changes
}
}
// Demonstration
public class Program
{
public static void Main()
{
Discount percentage = new PercentageDiscount(10m);
Discount fixedDiscount = new FixedDiscount(25m);
Discount none = new NoDiscount();
decimal price = 200m;
Console.WriteLine($"Original Price: {price:C}");
Console.WriteLine($"After 10% Discount: {percentage.ApplyDiscount(price):C}");
Console.WriteLine($"After $25 Discount: {fixedDiscount.ApplyDiscount(price):C}");
Console.WriteLine($"After No Discount: {none.ApplyDiscount(price):C}");
// OCP: Adding a new discount type without modifying existing code
Discount bogo = new BuyOneGetOneDiscount();
Console.WriteLine($"After BOGO Discount: {bogo.ApplyDiscount(price):C}");
}
}
// Demonstrating Open/Closed Principle
// You can extend behavior by adding new discount types like this:
public class BuyOneGetOneDiscount : Discount
{
public override decimal ApplyDiscount(decimal originalPrice)
{
// For demo: half price when BOGO applies
return originalPrice / 2;
}
}
*/
/*Singleton Logger implemented in clean, production-ready C# following SOLID and thread-safe best practices*/
/*
using System;
public sealed class Logger
{
// Step 1: Create a private static readonly instance (eager initialization)
private static readonly Logger _instance = new Logger();
// Step 2: Private constructor prevents external instantiation
private Logger()
{
Console.WriteLine("Logger initialized.");
}
// Step 3: Public static property to access the single instance
public static Logger Instance
{
get { return _instance; }
}
// Step 4: Add a simple logging method
public void Log(string message)
{
Console.WriteLine($"[{DateTime.Now:HH:mm:ss}] {message}");
}
}
// Demonstration
public class Program
{
public static void Main()
{
Logger logger1 = Logger.Instance;
logger1.Log("Application started.");
Logger logger2 = Logger.Instance;
logger2.Log("Performing a database operation...");
// Both references point to the same instance
Console.WriteLine(Object.ReferenceEquals(logger1, logger2)
? "Same instance confirmed ✅"
: "Different instances ❌");
}
}
/*
/*Polymorphism in Shapes, implemented in clean, SOLID-friendly C# showing abstraction, inheritance, and polymorphism in action.*/
/*
using System;
// Base abstract class: Shape
public abstract class Shape
{
public abstract double Area(); // Abstract method forces subclasses to implement
}
// Derived class: Circle
public class Circle : Shape
{
public double Radius { get; }
public Circle(double radius)
{
Radius = radius;
}
public override double Area()
{
return Math.PI * Radius * Radius;
}
}
// Derived class: Rectangle
public class Rectangle : Shape
{
public double Width { get; }
public double Height { get; }
public Rectangle(double width, double height)
{
Width = width;
Height = height;
}
public override double Area()
{
return Width * Height;
}
}
// Derived class: Triangle
public class Triangle : Shape
{
public double BaseLength { get; }
public double Height { get; }
public Triangle(double baseLength, double height)
{
BaseLength = baseLength;
Height = height;
}
public override double Area()
{
return 0.5 * BaseLength * Height;
}
}
// Static class to demonstrate polymorphism — calls Area() on any shape
public static class ShapePrinter
{
public static void PrintArea(Shape shape)
{
Console.WriteLine($"{shape.GetType().Name} Area: {shape.Area():F2}");
}
}
// Demonstration
public class Program
{
public static void Main()
{
Shape circle = new Circle(5);
Shape rectangle = new Rectangle(4, 6);
Shape triangle = new Triangle(3, 8);
ShapePrinter.PrintArea(circle);
ShapePrinter.PrintArea(rectangle);
ShapePrinter.PrintArea(triangle);
}
}
*/
/* Mini ETL Framework, built to demonstrate abstraction, inheritance, polymorphism, sealed classes, and a static counter tracking how many ETL runs have executed. */
/*
using System;
using System.Collections.Generic;
// Abstract base class — defines the ETL framework
public abstract class ETLProcessor
{
// Static counter to track total runs across all processors
private static int _runCount = 0;
// Template Method — defines the workflow
public void Run()
{
Console.WriteLine($"\n[{GetType().Name}] Starting ETL Process...");
Extract();
Transform();
Load();
_runCount++;
Console.WriteLine($"[{GetType().Name}] ETL Process Completed. Total Runs: {_runCount}\n");
}
// Abstract methods for derived classes to implement
protected abstract void Extract();
protected abstract void Transform();
protected abstract void Load();
}
// CSV Implementation
public class CsvETLProcessor : ETLProcessor
{
private List<string> _data = new List<string>();
protected override void Extract()
{
Console.WriteLine("Extracting data from CSV file...");
_data = new List<string> { "Alice,24", "Bob,30", "Charlie,28" };
}
protected override void Transform()
{
Console.WriteLine("Transforming CSV data (splitting names and ages)...");
_data = _data.ConvertAll(d => d.Replace(",", " - Age: "));
}
protected override void Load()
{
Console.WriteLine("Loading CSV data into database...");
_data.ForEach(Console.WriteLine);
}
}
// JSON Implementation
public class JsonETLProcessor : ETLProcessor
{
private List<Dictionary<string, object>> _data = new List<Dictionary<string, object>>();
protected override void Extract()
{
Console.WriteLine("Extracting data from JSON...");
_data = new List<Dictionary<string, object>> {
new() { {"name", "Diana"}, {"age", 26} },
new() { {"name", "Ethan"}, {"age", 32} }
};
}
protected override void Transform()
{
Console.WriteLine("Transforming JSON data (incrementing age by 1)...");
_data.ForEach(record => record["age"] = (int)record["age"] + 1);
}
protected override void Load()
{
Console.WriteLine("Loading JSON data into data warehouse...");
foreach (var record in _data)
Console.WriteLine($"{record["name"]} - Age: {record["age"]}");
}
}
// Sealed Excel Implementation (cannot be inherited)
public sealed class ExcelETLProcessor : ETLProcessor
{
private List<string> _rows = new List<string>();
protected override void Extract()
{
Console.WriteLine("Extracting data from Excel sheet...");
_rows = new List<string> { "ProductA,100", "ProductB,150" };
}
protected override void Transform()
{
Console.WriteLine("Transforming Excel data (converting to key-value format)...");
_rows = _rows.ConvertAll(r => $"Item: {r.Split(',')[0]}, Quantity: {r.Split(',')[1]}");
}
protected override void Load()
{
Console.WriteLine("Loading Excel data into reporting system...");
_rows.ForEach(Console.WriteLine);
}
}
// Demonstration
public class Program
{
public static void Main()
{
ETLProcessor csvProcessor = new CsvETLProcessor();
ETLProcessor jsonProcessor = new JsonETLProcessor();
ETLProcessor excelProcessor = new ExcelETLProcessor();
csvProcessor.Run();
jsonProcessor.Run();
excelProcessor.Run();
}
}
*/