Θεωρητική Θεμελίωση
1. Γιατί υπάρχουν τα Design Patterns;
Τα Design Patterns δεν είναι "μαγικές συνταγές".
Είναι τυποποιημένες λύσεις σε επαναλαμβανόμενα προβλήματα σχεδίασης.
Αριστοτελικά θα λέγαμε:
- Υλική αιτία: Ο κώδικας και οι κλάσεις.
- Μορφική αιτία: Η αρχιτεκτονική δομή (pattern).
- Ποιητική αιτία: Ο προγραμματιστής.
- Τελική αιτία: Η διατηρησιμότητα, επεκτασιμότητα, καθαρότητα.
- Τα patterns υπηρετούν την τελική αιτία: την ποιότητα του λογισμικού.
Strategy Pattern
Τι είναι το Strategy Pattern;
Το Strategy είναι ένα behavioral pattern που:
Ορίζει μια οικογένεια αλγορίθμων, τους ενθυλακώνει, και τους καθιστά εναλλάξιμους κατά τον χρόνο εκτέλεσης.
Με απλά λόγια:
Αν έχεις πολλούς τρόπους να κάνεις κάτι, αντί για if/switch, βάζεις διαφορετικές στρατηγικές.
Πότε το χρησιμοποιώ;
Χρησιμοποιείται όταν:
- Έχεις πολλαπλούς αλγορίθμους για το ίδιο πρόβλημα
- Θες runtime επιλογή συμπεριφοράς
- Θες να αποφύγεις μεγάλα if/switch
- Θες να τηρείς το Open/Closed Principle
SOLID Θεμελίωση
Το Strategy στηρίζεται κυρίως:
SRP Single Responsibility
Κάθε στρατηγική έχει μία ευθύνη.
OCP Open/Closed
Προσθέτεις νέα στρατηγική χωρίς να τροποποιείς υπάρχουσα κλάση.
DIP Dependency Inversion
Το context εξαρτάται από abstraction (interface), όχι από concrete class.
Παράδειγμα Strategy Pattern (C#)
Σενάριο: Υπολογισμός Έκπτωσης
Θέλουμε διαφορετικούς τρόπους υπολογισμού έκπτωσης:
- Κανονικός πελάτης
- Premium πελάτης
- Black Friday
Ορισμός Strategy Interface
public interface IDiscountStrategy
{
decimal CalculateDiscount(decimal amount);
}
Concrete Strategies
public class RegularDiscountStrategy : IDiscountStrategy
{
public decimal CalculateDiscount(decimal amount)
{
return amount * 0.05m;
}
}
public class PremiumDiscountStrategy : IDiscountStrategy
{
public decimal CalculateDiscount(decimal amount)
{
return amount * 0.15m;
}
}
public class BlackFridayDiscountStrategy : IDiscountStrategy
{
public decimal CalculateDiscount(decimal amount)
{
return amount * 0.30m;
}
}
Context Class
public class Order
{
private readonly IDiscountStrategy _discountStrategy;
public Order(IDiscountStrategy discountStrategy)
{
_discountStrategy = discountStrategy;
}
public decimal CalculateFinalPrice(decimal amount)
{
var discount = _discountStrategy.CalculateDiscount(amount);
return amount - discount;
}
}
Χρήση
var strategy = new PremiumDiscountStrategy();
var order = new Order(strategy);
var finalPrice = order.CalculateFinalPrice(1000);
Console.WriteLine(finalPrice);
Ορθολογική Ανάλυση
Χωρίς Strategy:
if(customerType == "Premium")
...
else if(...)
Αυτό παραβιάζει:
- OCP
- SRP
- οδηγεί σε conditional complexity
Με Strategy:
- Συμπεριφορά αποσυνδέεται
- Ο κώδικας γίνεται επεκτάσιμος
- Μπορεί να ενσωματωθεί σε DI container
Factory Pattern
Τι είναι το Factory Pattern;
Factory είναι creational pattern.
Αντί να δημιουργείς αντικείμενα με new,
μεταφέρεις τη δημιουργία σε ειδική κλάση.
Αποσυνδέει τον client από τη διαδικασία κατασκευής.
Πότε το χρησιμοποιώ;
- Όταν η δημιουργία αντικειμένων είναι σύνθετη
- Όταν θέλω να αποκρύψω implementation details
- Όταν η επιλογή concrete class γίνεται runtime
- Όταν τηρώ το DIP
SOLID Θεμελίωση
SRP
Η Factory έχει μία ευθύνη: δημιουργία αντικειμένων.
OCP
Νέα προϊόντα → νέα implementations, όχι αλλαγή client.
DIP
Ο client εξαρτάται από abstraction.
Παράδειγμα Factory Pattern
Σενάριο: Δημιουργία Payment Processor
Abstraction
public interface IPaymentProcessor
{
void ProcessPayment(decimal amount);
}
Concrete Implementations
public class CreditCardPayment : IPaymentProcessor
{
public void ProcessPayment(decimal amount)
{
Console.WriteLine($"Processing credit card payment: {amount}");
}
}
public class PayPalPayment : IPaymentProcessor
{
public void ProcessPayment(decimal amount)
{
Console.WriteLine($"Processing PayPal payment: {amount}");
}
}
Factory
public class PaymentProcessorFactory
{
public static IPaymentProcessor Create(string paymentType)
{
return paymentType switch
{
"CreditCard" => new CreditCardPayment(),
"PayPal" => new PayPalPayment(),
_ => throw new ArgumentException("Invalid payment type")
};
}
}
Χρήση
var processor = PaymentProcessorFactory.Create("CreditCard");
processor.ProcessPayment(500);
Αριστοτελική Ανάλυση
Το Strategy απαντά στο ερώτημα:
Ποια πράξη θα εκτελέσω;
Το Factory απαντά στο ερώτημα:
Ποιο ον θα δημιουργήσω;
Το πρώτο αφορά ενέργεια (πρᾶξις)
Το δεύτερο αφορά γένεσιν (δημιουργία)
Strategy vs Factory Συγκριτικός Πίνακας
| Strategy | Factory |
| ------------------- | --------------------- |
| Behavioral | Creational |
| Αλλάζει συμπεριφορά | Αλλάζει δημιουργία |
| Runtime εναλλαγή | Runtime επιλογή τύπου |
| Αντικαθιστά if | Αντικαθιστά new |
Συνδυασμός Strategy + Factory (Advanced)
Συχνά:
- Factory δημιουργεί Strategy
- Strategy εκτελεί συμπεριφορά
public class DiscountStrategyFactory
{
public static IDiscountStrategy Create(string type)
{
return type switch
{
"Regular" => new RegularDiscountStrategy(),
"Premium" => new PremiumDiscountStrategy(),
"BlackFriday" => new BlackFridayDiscountStrategy(),
_ => throw new ArgumentException()
};
}
}
Πότε ΔΕΝ πρέπει να τα χρησιμοποιώ;
- Όταν έχω μόνο μία υλοποίηση
- Όταν η πολυπλοκότητα υπερβαίνει το όφελος
- Όταν οδηγούμαι σε over-engineering
Η αρετή βρίσκεται στο μέσον (Αριστοτέλης).
Επίλογος
Τα patterns δεν είναι αυτοσκοπός.
Είναι εργαλεία λογικής καθαρότητας.
Ο καλός σχεδιασμός:
- Ελαχιστοποιεί σύζευξη
- Μεγιστοποιεί συνοχή
- Επιτρέπει επέκταση χωρίς τροποποίηση
Strategy → ελευθερία συμπεριφοράς
Factory → ελευθερία δημιουργίας
Αν θέλετε, μπορούμε να προχωρήσουμε σε:
- Abstract Factory
- Factory Method
- Real-world Clean Architecture παράδειγμα
- Ενσωμάτωση με DI / ASP.NET Core
- Ακαδημαϊκή μορφοποίηση έτοιμη για δημοσίευση

Top comments (0)