DESIGN PATTERNS (3/3)

Zeynep Türker
HardwareAndro
Published in
3 min readMay 19, 2023

--

Herkese Merhaba, bu yazımda en çok kullanılan behavioral design patternlardan bahsedeceğim.

Design pattern’ları anlattığım yazı serisinin ikincisine aşağıdaki linkten erişebilirsiniz.

BEHAVIORAL DESIGN PATTERNS

Strategy Design Pattern

Bir nesne veya sınıfın, belirli bir fonksiyonu yerine getirmek için birden fazla farklı stratejik yaklaşım sunabileceği durumlarda kullanılır. Nesneleri birbiri arasında değişebilir hale getirmeyi sağlar.

Mesela alışveriş yaparken ki farklı ödeme seçenekleri bu pattern ile gösterilebilir. Bu seçenekler aynı parent altında olduğunda birbirleri arasında geçiş işlemi yapabilirler.

Başka bir örnek üzerinden bu pattern’e bakalım. Mesela bir oyun karakterimiz olsun ve bu karakter başka bir karaktere saldırı yapabilsin.

Karakterler, saldırı yapmak için saldırı yöntemlerini kullansınlar.
Saldırı yöntemleri ortak methoda sahip oldukları için aynı parent’i implement ederler. Bu alt sınıflar aynı parent a sahip oldukları içinde setAttackStrategy methoduna gelen farklı bir saldırı yönetemi nesnesiyle karakterin saldırı yöntemini değiştirebiliyoruz.

AttackStrategy interface’imizde karakterlerin birbirlerine saldırabileceği method var. Saldırmak istediği karakteri alıyor.

public interface AttackStrategy {
void attack(Character target);
}

Saldırı yöntemleri bu interface’i implement edip kendilerine göre methodu override ediyor.

public class BowAttackStrategy implements AttackStrategy {
@Override
public void attack(Character target) {
System.out.println("Bow attack on " + target.getName());
}
}
public class MagicAttackStrategy implements AttackStrategy {
@Override
public void attack(Character target) {
System.out.println("Magic attack on " + target.getName());
}
}
public class SwordAttackStrategy implements AttackStrategy {
@Override
public void attack(Character target) {
System.out.println("Sword attack on " + target.getName());
}
}

Karakter sınıfı içerisinde karakterin ismi ve saldırı yöntemi field’ları var.
Attack methodu ile saldırı yönteminin attack methodu çağrılır.
Karakterin saldırı yöntemini değiştirmek istediğimizde setAttackStrategy methodumuza yeni saldırı yöntemini yollarız.

public class Character {
private final String name;
private AttackStrategy attackStrategy;

public Character(String name, AttackStrategy attackStrategy) {
this.name = name;
this.attackStrategy = attackStrategy;
}

public String getName() {
return name;
}

public void attack(Character target) {
attackStrategy.attack(target);
}

public void setAttackStrategy(AttackStrategy attackStrategy) {
this.attackStrategy = attackStrategy;
}
}

Client tarafında iki farklı karakter oluşturduk. Bu karakterin attack methodlarını çağırdığımızda saldırı yöntemlerine göre birbirlerine saldırırlar.
Karakterin Kılıç ile olan saldırı yöntemini, Büyü ile değiştirmek istediğimizde setAttackStrategy methodunu kullandık.

public class Demo {
public static void main(String[] args) {
Character character = new Character("Player", new SwordAttackStrategy());
Character enemy = new Character("Enemy", new BowAttackStrategy());

character.attack(enemy);
enemy.attack(character);

character.setAttackStrategy(new MagicAttackStrategy());
character.attack(enemy);
}
}

Bu desing pattern ile birbirleriyle aynı parent’a ve farklı algoritmalara sahip sınıflar arasında geçiş yapabildik.

Observer Design Pattern

Observer tasarım deseni, birden fazla nesneyi, takip ettikleri başka bir nesnede gerçekleşen olaylarla ilgili bilgilendirmeyi sağlayan bir abonelik mekanizması oluşturmayı amaçlar.

Object ve Subject yapıları vardır. Subject, nesnelerin dinlendiği bir sınıf kaynağıdır. Observer da nesneyi dinleyen abonedir.
Aralarında one subject to many observers ilişkisi vardır.
Subject, abone olan Observer listesine sahiptir. Abonelik listesi dinamiktir. Yani observerlar abone olup subject’i dinlemeye başladıkları gibi abonelikten çıkıp dinlemeyi bırakabilirler.

Subject interface’imizde observer’ı ekleyebileceğimiz ve çıkarabileceğimiz methodlar ve de veri değişiminde observerlara haber yollayacak bir methodumuz var.

public interface Subject {
void addObserver(Observer observer);
void removeObserver(Observer observer);
void notifyObservers();
}

Observer interface’imizde veri değişimi olduğunda Observer’ın bu değişimi alacağı update methodu var.

public interface Observer {
void update(int temperature);
}

Ekranda sıcaklık bilgisini gösterecek WeatherScreen isimli sınıfımız olsun. Bu sınıf, sıcaklık verisini dinlemek isteyecek. Bu yüzden bir Observer’dır. WeatherScreen Observer interface’inden gelen update methodunu ekranda değişikliği gösterecek şekilde implement ediyor.

public class WeatherScreen implements Observer {
@Override
public void update(int temperature) {
System.out.println("Weather updated: " + temperature);
}
}

Weather sınıfı, sıcaklık değerini tutar. Bu sınıf bizim Subject’imizdir. Bu yüzden Subject interface’ini implement eder.

Abonelerin tutulduğu nesnelerimiz ve sıcaklık bilgisini tutan temperature field’ları var.
setTemperature methodunda sıcaklık değeri değiştiği için notifyObserver method çağrılır. Bu methodda da abone listesindeki Observerlara sıcaklığın değiştiği bilgisi gönderilir.

import java.util.ArrayList;
import java.util.List;

public class Weather implements Subject {
private final List<Observer> observers = new ArrayList<>();
private int temperature;

public int getTemperature() {
return temperature;
}

public void setTemperature(int temperature) {
this.temperature = temperature;
notifyObservers();
}

@Override
public void addObserver(Observer observer) {
observers.add(observer);
}

@Override
public void removeObserver(Observer observer) {
observers.remove(observer);
}

@Override
public void notifyObservers() {
for (Observer observer : observers) {
observer.update(getTemperature());
}
}
}

Client tarafında Weather ve WeatherScreen nesnelerimizi oluşturduk.
WeatherScreen’i Weather Subject’ine abone ederiz ve sıcaklık verisinin dinleme işlemi başlar.
Sıcaklık değişimi olduğunda ise WeatherScreen’in update methodunda sıcaklık değişimleri print edilir.
Abone işlemi bitirildiğinde artık dinleme işlemi olmaz. Bu yüzden sıcaklık değişiminde ekrana bilgi yazdırma olmaz.

public class Demo {
public static void main(String[] args) {
Weather weather = new Weather();

WeatherScreen screen = new WeatherScreen();

weather.addObserver(screen);

weather.setTemperature(25);
weather.setTemperature(30);

weather.removeObserver(screen);

weather.setTemperature(35);
}
}
Weather updated: 25
Weather updated: 30

Process finished with exit code 0

Eğer projelerimizde doğru design pattern’ı kullanırsak daha kalite kodlar elde ederiz. Ayrıca yaptığımız yazılımın daha doğru bir şekilde tasarlanmasını sağlar. Bu yüzden design pattern’ları kullanmak oldukça önemli.

Umarım faydalı olmuştur.

--

--