Design Patterns PHP — 1. Bu yazımda mühendislikte önemli yeri…
By: Ercan Çavuşoğlu
Tags: Design Patterns

Bu yazımda mühendislikte önemli yeri olan design pattern’leri tek bi çatı altında örneklerle anlamlı hale getirmek istedim. Meslek hayatına yeni başlamış, kendini bu konularda geliştirmek isteyen, kullanmaya kullanmaya unutmuş olan veya kendini yetersiz gören meslektaşlarıma faydası olması dileğiyle paylaşıyorum. Hatalarımı, eksiklerimi yorumlarda paylaşırsanız memnun olurum.

Tarihçesinden biraz bahsetmem gerekirse, Prof. Cristopher Alexander, inşaat profesörü olarak makaleler yayımlayan bir kişi olarak binaların tasarım sorunları, mimari problemlerine dikkat çeken kişi olmuş. 1977 yılında yayımladığı ve baş yazarı olduğu “A Pattern Language” ile design patternlerinde fikir babası olmuştur.

Yazılım dünyasındaki dönemin önemli kişileri de bu patternlerin kendileri içinde ihtiyaç olduğunu fark etmişlerdir. 1990'larda C.Alexander’ın fikirlerini yazılımda kullanmaya başlamışlar. Gang of Four diye bilinen grup üyeleri Erich Gamma, Richard Helm, Ralph Johnson and John Vlissides kafa kafaya vererek 1995 yılında Design Patterns: Elements Of Reusable Object-Oriented Software kitabını yayımlamışlardır.

Peki niçin ortaya çıkmış ?

- Amerikayı yeniden keşfetmemek için

- Yeniden kullanılabilir, değiştirilebilir özellikle nesne yönelimli programlama yapabilmek için

- OOP prensiblerinin daha anlaşılabilir olması için

- Sınıf kalıtımı yerine toplamayı tercih etmek için

- Arayüzlerle programlama yapmak için (uygulamalara değil)

- Değişen kavramı özetlemek, uyum sağlatmak için

- Var olan sistem ve tasarımı daha iyi anlamak için

- Ortak dile sahip olmak için

Bize ne faydası var ?

Resimde göreceğiniz üzere Design Patterns ’ler yazılım dünyasında ileriye gitmek için tam orta noktada bulunmakta. Dolayısıyla ileriye doğru attığınız her adımda size faydası olacaktır.

Sürekli yaşanan sorunların üzerinde uzun uzun düşünüldükten sonra üretilmiş çözümler diye tanımlamasını yapabiliriz. Temiz, anlaşılır ve karmaşıklıklar artıkça kolay yönetilir kodlar yazmak için clean-code, object-oriented, solid, dry gibi yöntemlerin artık yetmediği noktalarda, başlangıçta biraz daha zaman harcayıp ilerleyen süreçlerde rahatlamamız için faydası olan patternlerdir diyebiliriz ayrıca.

Design Patterns’ler genel kullanım şekli olarak 3 başlık altında toparlanmıştır. Burada sayı artabilir. Yeni bir kategori varsa ve göremediysem orada benim eksiğim olabilir. Yorumlarda yazarsanız memnun olurum. Genel kabul görmüş pattern kategorileri bunlardır. Hadi başlayalım.

Creational Design Patterns (Oluşturucu Tasarım Kalıpları)

Bu kategorideki patternler nesnenin nasıl oluşturulacağı hakkındaki problemlere çözüm olması için ortaya çıkarılmıştır. Bazı durumlarda çok fazla nesne üretmek beklenmeyen performans kaybı yaratabilir, yada çok sayıda constructer propertysi tanımlanmış bi nesneye sadece istediklerimizi tanımlatmak isteyebiliriz, veya cloneladığımız nesnenin propertylerinden birini değiştirdiğimizde clonelanan nesnede de aynı şekilde değiştiğini görebiliriz. Bu gibi istenmeyen ve belki ekipçe saatlerimizi harcayıp çözeceğimiz problem/fix olarak çıkabilecek durumları önlemek için oluşturulmuş hazır çözümlerdir diye tanımlayabiliriz bu kısmı.

Singleton Pattern (Object)

Her noktadan erişim noktalarına sahip yalnızca tek bir örneğe sahip bir sınıf diye tanımlayabiliriz. Kelime anlamı olarak tekil demektir. İlgili nesneden bir tane oluşsun istediğimiz zaman kullanabiliriz. Kullanım yerleri olarak connection pool, configuration manager vb. örnek gösterebiliriz.

?php



namespace Creational\Singleton;



class CustomerManager

{

protected static $customerManager;



protected function __construct()

{

}



protected function __clone()

{

}



public static function createAsSingleton(): self

{

if (static::$customerManager === null) {

static::$customerManager = new static();

}



return static::$customerManager;

}



public function save()

{

echo "Save";

}

}



class Program

{

public function run()

{

# Call to private CustomerManager::__construct() from invalid context

# $customerManager = new CustomerManager();



$customerManager = CustomerManager::createAsSingleton();

$customerManager->save();

}

}



$program = new Program();

$program->run();

Builder Pattern (Object)

…

<?php



namespace Creational\Builder;



class ProductViewModel

{

public $id;

public $categoryName;

public $productName;

public $unitPrice;

public $discountedPrice;

public $discountApplied;

}



abstract class ProductBuilder

{

abstract public function getProductData();



abstract public function applyDiscount();



abstract public function getModel();

}



class NewCustomerProductBuilder extends ProductBuilder

{

protected $model;



public function __construct()

{

$this->model = new ProductViewModel();

}



public function getProductData()

{

$this->model->id = 1;

$this->model->categoryName = "Meşrubat";

$this->model->productName = "Şalgam";

$this->model->unitPrice = 12;

}



public function applyDiscount()

{

$this->model->discountedPrice = $this->model->unitPrice * 0.9;

$this->model->discountApplied = true;

}



public function getModel()

{

return $this->model;

}

}



class OldCustomerProductBuilder extends ProductBuilder

{

protected $model;



public function __construct()

{

$this->model = new ProductViewModel();

}



public function getProductData()

{

$this->model->id = 1;

$this->model->categoryName = "Meşrubat";

$this->model->productName = "Şalgam";

$this->model->unitPrice = 12;

}



public function applyDiscount()

{

$this->model->discountedPrice = $this->model->unitPrice;

$this->model->discountApplied = false;

}



public function getModel()

{

return $this->model;

}

}



class ProductDirector

{

public function generateProduct(ProductBuilder $productBuilder)

{

$productBuilder->getProductData();

$productBuilder->applyDiscount();

}

}



class Program

{

public function run()

{

$ProductDirector = new ProductDirector();

$ProductDirector->generateProduct(new NewCustomerProductBuilder());



$ProductDirector2 = new ProductDirector();

$ProductDirector2->generateProduct(new OldCustomerProductBuilder());

}

}



$program = new Program();

$program->run();

Prototype (Object)

…

<?php



namespace Creational\Prototype;



abstract class Person

{

abstract public function clone();



protected $id;

protected $firstname;

protected $lastname;



/**

* @return mixed

*/

public function getId()

{

return $this->id;

}



/**

* @param mixed $id

* @return Person

*/

public function setId($id)

{

$this->id = $id;

return $this;

}



/**

* @return mixed

*/

public function getFirstname()

{

return $this->firstname;

}



/**

* @param mixed $firstname

* @return Person

*/

public function setFirstname($firstname)

{

$this->firstname = $firstname;

return $this;

}



/**

* @return mixed

*/

public function getLastname()

{

return $this->lastname;

}



/**

* @param mixed $lastname

* @return Person

*/

public function setLastname($lastname)

{

$this->lastname = $lastname;

return $this;

}

}



class Customer extends Person

{

protected $city;



/**

* @return mixed

*/

public function getCity()

{

return $this->city;

}



/**

* @param mixed $city

* @return Customer

*/

public function setCity($city)

{

$this->city = $city;



return $this;

}



public function clone()

{

return clone $this;

}

}



class Employee extends Person

{

protected $salary;



/**

* @return mixed

*/

public function getSalary()

{

return $this->salary;

}



/**

* @param mixed $salary

* @return Employee

*/

public function setSalary($salary)

{

$this->salary = $salary;



return $this;

}



public function clone()

{

return clone $this;

}

}



class Program

{

public function run()

{

$customer = new Customer();

$customer

->setId(1)

->setFirstname("Ercan")

->setLastname("Cavusoglu");



$newCustomer = $customer->clone();

$newCustomer->setFirstname("Apple");



echo $customer->getFirstname();

echo $newCustomer->getFirstname();

}

}



$program = new Program();

$program->run();

Factory Method Pattern (Class)

….

<?php



namespace Creational\Factory;



interface LoggerFactoryInterface

{

public function createLogger();

}



interface LoggerInterface

{

public function log();

}



class MonologLoggerFactory implements LoggerFactoryInterface

{

public function createLogger()

{

return new MonologLogger();

}

}



class LoggerFactory implements LoggerFactoryInterface

{

public function createLogger()

{

return new GrayLogger();

}

}



class GrayLogger implements LoggerInterface

{

public function log()

{

echo "Grayloggera logla";

}

}



class MonologLogger implements LoggerInterface

{

public function log()

{

echo "Dosyaya logla";

}

}



class CustomerManager

{

protected $loggerFactory;



public function __construct(LoggerFactoryInterface $loggerFactory)

{

$this->loggerFactory = $loggerFactory;

}



public function save()

{

$this->loggerFactory->createLogger();

echo "geri kalan işler";

}

}



class Program

{

public function run()

{

$manager = new CustomerManager(new LoggerFactory());

$manager->save();



$manager2 = new CustomerManager(new MonologLoggerFactory());

$manager2->save();

}

}



$program = new Program();

$program->run();

Abstract Factory Pattern (Object)

….