Strategy Design Pattern - Interface'nin Gücü

Strategy Design Pattern – Interface’nin Gücü

Merhabalar,

Bu yazıda uzun zamandır yazmak istediğim Strategy Design Pattern’e yani Strateji Tasarım Desenine değineceğim.

Strategy Design Pattern, nesnenin duruma göre stratejisini değiştirebilmesidir, Behavioural / Davranışsal patternler içerisinde yer alan bu pattern davranışına çalışma anında karar veren bir patterndir / desendir. Bu pattern uygulama içerisinde benzer algoritmaları sınıflandırmamızı ve çalışma anında kullanacağımız algoritmayı seçmemizi sağlar ve kendimizi tekrar etmekten -DRY- kurtarır.

UML Diagramı aşadağı ki gibidir;

Strateji Tasarım Deseni

Strateji Tasarım Deseni

Örnek verecek olursak,

<?php

class RedisStore {
    public function update() {
        // güncelleme için query
        return "RedisStore üzerinde veri güncellendi";
    }
}

class MySQLStore {
    public function update() {
        // güncelleme için query
        return "MySQLStore üzerinde veri güncellendi";
    }
}

$redis = new RedisStore();
$redis->update();

$sql = new MySQLStore();
$sql->update();

Yukarıda ki iki sınıfta update metodu bulunmakta yani ikisi de aynı işi yapmaktadır biri Redis üzerinde diğeri de MySQL üzerinde. Fakat ileri zamanlarda Redis yerine Mongo kullanmak istersek, MongoStore sınıfını oluşturup uygulama içerisinde RedisStore sınıfının kullanıldığı satırları bulup değiştireceğiz. Bu bizim için biraz külfetli olurdu. İşte tam da bu noktada Strategy Design Pattern devreye giriyor.

Yeni bir Interface oluşturalım;

Datastore.php

<?php
interface Datastore {
    public function update();
}

Interfacemizi implement edelim;

<?php

require 'Datastore.php';

class RedisStore implements Datastore {
    public function update() {
        // güncelleme için query
        return "RedisStore üzerinde veri güncellendi";
    }
}

class MySQLStore implements Datastore {
    public function update() {
        // güncelleme için query
        return "MySQLStore üzerinde veri güncellendid";
    }
}

$redis = new RedisStore();
$redis->update();

$sql = new SQLStore();
$sql->update();

Evet kodumuz bu şekilde daha güzel oldu fakat hala sorunlar var, hangi algoritmayı kullanacağına çalışma anında karar veriyor demiştik uygulama içerisinde Store’yi biraz daha soyutlayalım.

DatabaseAdapter.php

<?php
require 'Redis.php';
require 'MySQL.php';

class DatabaseAdapter {

    private $strategy = null;

    public function __construct($strategy) {
        if ($strategy == "redis") {
            $this->strategy = new RedisStore();
        } else if ($strategy == "sql") {
            $this->strategy = new MySQLStore();
        }
    }

    public function updateStore() {
        return $this->strategy->update();
    }
}

Datastore.php

<?php
interface Datastore {
    public function update();
}

Redis.php

<?php
require 'Datastore.php';

class RedisStore implements Datastore {
    public function update() {
        // güncelleme için query
        return "RedisStore üzerinde veri güncellendi";
    }
}

MySQL.php

<?php
require 'Datastore.php';

class MySQLStore implements Datastore {
    public function update() {
        // güncelleme için query
        return "MySQLStore üzerinde veri güncellendi";
    }
}
<?php
require 'DatabaseAdapter.php';

$store = new DatabaseAdapter();
echo $store->updateStore("redis");

Gördüğünüz algoritmalar kendi içinde kapsüllenerek (encapsulate) uygulamanın geri kalanından soyutlandı ve uygulamamızın loose coupled bir yapıda oldu yani nesneler arası bağımlılığı gevşetmiş olduk.

Peki Redis yerine MongoDB’yi kullanmak istersek ne yapacağız ?

MongoDB.php

<?php
require 'Datastore.php';

class MongoDBStore implements Datastore {
    public function update() {
        /// güncelleme için query
        return "MongoDBStore üzerinde veri güncellendi";
    }
}

Daha sonra DatabaseAdapter.php dosyası içerisinde yer alan sınıfımızın constructor’un da bulunan if else bloğuna Mongodb’yi ekleyelim;

DatabaseAdapter.php

<?php

require 'Redis.php';
require 'MySQL.php';

class DatabaseAdapter {

    private $strategy = null;

    public function __construct($strategy) {
        if ($strategy == "redis") {
            $this->strategy = new RedisStore();
        } else if ($strategy == "sql") {
            $this->strategy = new SQLStore();
        } else if ($strategy == "mongodb") {
            $this->strategy = new MongoDBStore();
        }
    }

    public function updateStore() {
        return $this->strategy->update();
    }
}
<?php
require 'DatabaseAdapter.php';

$store = new DatabaseAdapter();
echo $store->updateStore("mongodb");

Gördüğünüz gibi yeni bir Database Adaptoru implemente etmek işte bu kadar basit 🙂

Bir sonra ki makalemizde görüşmek üzere sağlıcakla kalın (:

Kaynak