IhsanErdem

Ihsan Erdem - blogS.O.L.I.D : Nesne Yönelimli Programlamanın 5 Temel İlkesi

Title Image

Single-Responsibility Principle

Single-responsibility ilkesi kısaca aşağıdaki fikri ortaya koyar:

Bir sınıfın(class) değişikliğe uğramak için sadece tek bir sebebi olmalı birden fazla değişime sebep olacak bileşen barındırmamalı , yani bir sınıfın sadece bir görevi olmalı.

"Single Responsibility" kelimelerini Türkçe'ye çevirecek olursak "Tek Sorumluluk" şeklinde çevirebiliriz.

1def calculator(type, a, b)
2  case type
3  when "add"
4    puts "Sum: #{a + b}"
5  when "subtract"
6    puts "Difference: #{a - b}"
7  when "multiply"
8    puts "Product: #{a * b}"
9  when "divide"
10    puts "Quotient: #{a / b}" if b != 0
11  when "area"
12    puts "Area of circle: #{Math::PI * a**2}" 
13  when "circumference"
14    puts "Circumference of circle: #{2 * Math::PI * a}" radius
15  else
16    puts "Unknown calculation type"
17  end
18end
19

Yukarıda gördüğünüz kod bloğu Single Responsibilitiy prensipine uymaz aynı anda birden fazla görev yapmaya çalıştığından.

1
2def multiply(a, b)
3    a * b
4end
5

Yukarıda gördüğünüz kod bloğu sadece tek bir görevi yerine getirmeye çalıştığından Single Responsibility prensipine uyar.

Open-Closed Principle

Open-closed ilkesi nesnelerin genişletilebilir fakat değiştirilemeyecek bir durumda olmaları gerektiğini öne sürer.

1class Payment
2  def process(payment_method)
3    payment_method.process
4  end
5end
6
7class CreditCardPayment
8  def process
9    puts 'Processing credit card payment...'
10  end
11end
12
13class PayPalPayment
14  def process
15    puts 'Processing PayPal payment...'
16  end
17end
18
19payment = Payment.new
20credit_card = CreditCardPayment.new
21paypal = PayPalPayment.new
22
23payment.process(credit_card)  
24payment.process(paypal)       
25

Yukarıda gördüğünüz kod bloğu open-closed ilkesine uyar, her yeni bir ödeme methodu eklemek istediğimizde orjinal sınıfı değiştirmek yerine orjinal sınıfı genişletip yeni bir class(eklemek istediğimiz ödeme methodu) ekliyoruz.

Liskov-Substition Principle

Liskov-Substition ilkesi her alt sınıfın kendi ata-sınıflarının rolünü oynayıp onların yerine geçebilmeleri gerektiğini öne sürer.

1
2
3class Bird
4# General bird behavior
5end
6
7class FlyingBird < Bird
8def fly
9puts 'Flying high!'
10end
11end
12
13class NonFlyingBird < Bird
14# Penguins, ostriches, etc.
15end
16
17class Sparrow < FlyingBird
18# Specific behavior for sparrows
19end
20
21class Penguin < NonFlyingBird
22def swim
23puts 'Penguin swimming!'
24end
25end
26
27def make_bird_fly(bird)
28bird.fly if bird.is_a?(FlyingBird)
29end
30
31sparrow = Sparrow.new
32penguin = Penguin.new
33
34make_bird_fly(sparrow) 
35make_bird_fly(penguin) 


Eğer penguin alt sınıfı FlyingBird ata sınıfına ait bir alt sınıf olsaydı bu ilkemizi ihlal etmiş olurdu çünkü penguenler uçamaz dolayısıyla atasınıfta bulunan method bizim alt sınıfımız için geçerli olmayacağından LSB'yi ihlal etmiş olurdu.

Interface-Segregation Principle

Interface-Segregation ilkesi bir sınıfın(class) kullanmayacağı methodlarla yüklenmemesi gerektiğini belirtir; bu nedenle herşey için tek bir şablon kullanmak yerine çok sayıda küçük şablonlar kullanmamız gerektiğini öne sürer.

1class CanWork
2  def work
3    raise NotImplementedError, 'Subclasses must implement the work method'
4  end
5end
6
7class CanEat
8  def eat
9    raise NotImplementedError, 'Subclasses must implement the eat method'
10  end
11end
12
13class HumanWorker < CanWork
14  include CanEat
15
16  def work
17    puts 'Human is working'
18  end
19
20  def eat
21    puts 'Human is eating'
22  end
23end
24
25class RobotWorker < CanWork
26  def work
27    puts 'Robot is working'
28  end
29end
30

Dependency Inversion Principle

Ata sınıflarımızın alt sınıflarına ihtiyaç duymayacak şekilde tasarlanmaları gerektiğini öne sürer.

1class CanSwitch
2  def turn_on
3    raise NotImplementedError, 'Subclasses must implement turn_on method'
4  end
5end
6
7class LightBulb < CanSwitch
8  def turn_on
9    puts 'Light is on'
10  end
11end
12
13class Fan < CanSwitch
14  def turn_on
15    puts 'Fan is spinning'
16  end
17end
18
19class Switch
20  def initialize(device)
21    @device = device
22  end
23
24  def toggle
25    @device.turn_on
26  end
27end
28
29light = LightBulb.new
30switch = Switch.new(light)
31switch.toggle  
32
33fan = Fan.new
34switch = Switch.new(fan)
35switch.toggle  
36

Yukarıda gördüğümüz örnekte ata sınıfımız olan Switch hiç bir alt sınıfa bağlı olmadan çalışır, dolayısıyla alt sınıflarımızda yapılan değişiklikler bizim atasınıfımızı etkilemez, ata sınıfımız Switch ve alt sınıflarımız arasındaki ilişkilendirme soyutlanmış sınıflar veya arayüzler aracılığı ile yapılır.