**SOLID Principlerinin Temelleri**
Bir geliştirici olarak, yazılım projelerinin kalitesini, esnekliğini ve sürdürülebilirliğini iyileştirmek için Solid Principlerini bilmelisiniz. Bu blog yazımızda, Solid Principlerinin temellerini keşfedeceğiz ve pratik örneklerle her bir principio hakkında daha derine bir şekilde ineceğiz.
**Solid Principlerinin 5 Temeli**
1. **Single Responsibility Principle (SRC)**: Bir sınıfın yalnızca bir, ve yalnızca bir nedenle değişmesini sağlamayı amaçlar. Sınıf tek bir görevi yerine getirmelidir.
Örneğin, bir kullanıcı hesabı oluşturma işlemini tek bir sınıfta yapmak yerine, farklı sınıfların görevlerini ayırmak daha doğru olur.
“`javascript
// Aykırı ejemplo: Tek bir sınıf birden fazla vazifeyi yerine getirir
class UserAccount {
createAccount(user: any) {
// Hesabın doğrulanması
if (!user.email) {
throw new Error(‘”Email is required”‘);
}
// İşlemlerin uygulanması
user.status = “active”;
// Veriler veritabanına kaydedilir
database.save(user);
// E-posta gönderimi
emailService.send(‘”Welcome!”‘);
}
}
// Doğru örnek: Tek bir sınıfın görevlerini ayırmak
class UserValidator {
validate(user: any): void {
// Hesabın doğrulanması
}
}
class UserRepository {
save(user: any): void {
// Veriler veritabanına kaydedilir
}
}
class EmailSender {
send(message: string): void {
// E-posta gönderimi
}
}
“`
2. **Open-Closed Principle (ÖCP)**: Sistemin entegrasyonu açık olmalıdır ve değişken olmalı. Sistemin bir parçalarından yeni özellikler eklemek veya modifikasyon eklemek için yeni bir sınıf oluşturulmalıdır.
Örneğin, bir ödeme işleme sınıfında yeni bir borç türü eklemek için sistemin bir parçası olan sınıf modifiye etmek yerine, yeni bir sınıf oluşturmak daha doğru olur.
“`javascript
// Aykırı örnek: Sistem parçalarından yeni özellikler eklemek
class PaymentProcessor {
process(paymentType: string, amount: number): void {
if (paymentType === “credit”) {
// Kredi kartı işlemi gerçekleştirmek
} else if (paymentType === “paypal”) {
// PayPal işlemi gerçekleştirmek
}
// Yeni bir borç türü eklemek için sistem parçalarından modifiye etmek
}
}
// Doğru örnek: Yeni özellikler eklemek için yeni bir sınıf oluşturmak
interface PaymentMethod {
process(amount: number): void;
}
class CreditCardPayment implements PaymentMethod {
process(amount: number): void {
// Kredi kartı işlemi gerçekleştirmek
}
}
class PayPalPayment implements PaymentMethod {
process(amount: number): void {
// PayPal işlemi gerçekleştirmek
}
}
“`
3. **Liskov Substitution Principle (LSP)**: Alt sınıf bir üst sınıfın yerini alabilir olmalıdır. Alt sınıf tarafından üretilen sonuçlar üst sınıf tarafından üretilen sonuçlarla aynı olmalıdır.
Örneğin, bir kuş sınıfından türetilen pingvin sınıfı, aynı anda uçabildiği gibi, bir kuş sınıfından türetilen kuş sınıfı da aynı anda uçabilir.
“`javascript
// Aykırı örnek: Alt sınıf tarafından üretilen sonuçlar üst sınıf tarafından üretilen sonuçlarla aynı değil
class Bird {
fly(): void {
console.log(“Flying…”);
}
}
class Penguin extends Bird {
fly(): void {
throw new Error(“‘Not implemented: Penguins cannot fly'”);
}
}
// Doğru örnek: Alt sınıf tarafından üretilen sonuçlar üst sınıf tarafından üretilen sonuçlarla aynı
class Bird {
eat(): void {
console.log(“Eating…”);
}
}
class FlyingBird extends Bird {
fly(): void {
console.log(“Flying…”);
}
}
class Penguin extends Bird {
swim(): void {
console.log(“Swimming…”);
}
}
“`
4. **Interface Segregation Principle (ISP)**: Bir sınıfa uygulanan arayüzler fazla ve gereksiz olmalıdır. Arayüzler, kullanıcının gerçekten gerekli olrak uygulayacağı yalnızca özelliklere sahip olmalıdır.
Örneğin, bir makine sınıfının yalnızca baskı yapma özelliği varsa, baskı yapma ve baskı yapma özelliği olmayan bir arayüzün birleştirilmesi gereksizdir.
“`javascript
// Aykırı örnek: Bir sınıfa fazla ve gereksiz olarak uygulanan arayüzler
interface IMachine {
print(): void;
scan(): void;
fax(): void;
}
class SimplePrinter implements IMachine {
print(): void {
console.log(“Printing…”);
}
scan(): void {
throw new Error(“‘Not supported'”);
}
fax(): void {
throw new Error(“‘Not supported'”);
}
}
// Doğru örnek: Bir sınıfa gereksiz olarak uygulanan arayüzlerden ayrılmak
interface IPrinter {
print(): void;
}
interface IScanner {
scan(): void;
}
interface IFax {
fax(): void;
}
class SimplePrinter implements IPrinter {
print(): void {
console.log(“Printing…”);
}
}
class MultiFunctionPrinter implements IPrinter, IScanner, IFax {
print(): void {
console.log(“Printing…”);
}
scan(): void {
console.log(“Scanning…”);
}
fax(): void {
console.log(“Faxing…”);
}
}
“`
5. **Dependency Inversion Principle (DIP)**: Yüksek seviyeli modüller düşük seviyeli detallara bağımlı olmalıdır. Her iki modül de abstraksiyonlara ( arayüzler ) bağımlı olmalıdır.
Örneğin, bir kullanıcı kayıt işlemini gerçekleştiren sınıfa, doğrudan veritabanına bağımlı olması yerine, veritabanıyla olan bağımlılığı arayüzler vasıtasıyla oluşturmak daha doğru olur.
“`javascript
// Aykırı örnek: Yüksek seviyeli modüller düşük seviyeli detallara bağımlı
class MySQLDatabase {
save(data: any): void {
// MySQL’e verilerin kaydedilmesi
}
}
class UserService {
private db = new MySQLDatabase();
createUser(user: any): void {
this.db.save(user);
}
}
// Doğru örnek: Yüksek seviyeli modüller düşük seviyeli detallara bağımlı olmayarak abstraksiyonlara (arrayüzler) bağımlı
interface IDatabase {
save(data: any): void;
}
class MySQLDatabase implements IDatabase {
save(data: any): void {
// MySQL’e verilerin kaydedilmesi
}
}
class MongoDatabase implements IDatabase {
save(data: any): void {
// Mongo’ya verilerin kaydedilmesi
}
}
class UserService {
constructor(private db: IDatabase) {}
createUser(user: any): void {
this.db.save(user);
}
}
“`
SOLID priniciplerinin uygulama alanı çok geniş ve karmaşıktır. Bu blog yazımda, daha fazla derinlemesine bilgi edinmek için yeni konuları keşfetmek ve pratik olarak uygulamak için bir fırsat size sunduk.