Ihsan Erdem - blogS.O.L.I.D : Nesne Yönelimli Programlamanın 5 Temel İlkesi
İçerik
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.