PHP Design Patterns (Tasarım Kalıpları)

Deneyimli geliştiriciler muhtemelen buna aşinadır, ancak bu makale acemi geliştiricileri için son derece yararlı olacaktır. Peki, nedir – tasarım kalıpları? Tasarım Kalıpları, analiz kalıpları değildir, bağlantılı listeler gibi ortak yapıların tanımları değildir, belirli uygulama veya çerçeve tasarımları değildir. Aslında, tasarım kalıpları “belirli bir bağlamda genel tasarım problemini çözmek için özelleştirilmiş iletişim nesnelerinin ve sınıflarının tanımlarıdır.” Başka bir deyişle, Tasarım kalıpları her gün karşılaştığımız programlama sorunlarına genel bir yeniden kullanılabilir çözüm sağlar. Tasarım kalıpları, sisteminize kolayca uygulanabilen hazır sınıflar veya kütüphaneler değildir, bu kaynak koduna dönüştürülebilen somut bir çözüm değildir, tasarım modelleri bundan çok daha fazladır. Farklı özel durumlarda bir sorunu çözmek için uygulanabilecek kalıplar veya şablonlardır.

Tasarım kalıpları, şablonların ispatlandığı ve geliştiricinin konumundan olduğu gibi gelişmeyi hızlandırmaya yardımcı olur, yalnızca uygulama gerekir. Tasarım örüntüleri, yazılım geliştirmeyi daha hızlı yapmakla kalmaz, aynı zamanda büyük fikirleri daha basit bir şekilde de kapsar. Ayrıca, hoş olmayan durumlardan kaçınmak için bunları yanlış yerlerde kullanmamaya dikkat edin. Teoriye ek olarak, size tasarım kalıplarının en soyut ve basit örneklerini de veriyoruz.

“Her tasarım, tekrar tekrar meydana gelen bir problemi tanımlar… ve sonra bu sorunun çözümünün özünü, bu çözümü iki kez aynı şekilde kullanmadan, milyonlarca kez kullanabilecek şekilde tanımlar.”


Christopher Alexander

Şimdiye kadar 23 farklı bilinen tasarım modeli vardır ve bunlar amaçlarına göre üç kategoriye ayrılabilir:

  • Creational Patterns: Uygulama sistemlerinden ayrıştırılabilmeleri için nesneleri inşa etmekte kullanılırlar.
  • Structural Patterns: Birçok farklı nesne arasında büyük nesne yapıları oluşturmak için kullanılır
  • Behavioral Patterns: Nesneler arasındaki algoritmaları, ilişkileri ve sorumlulukları yönetmek için kullanılır

Aşağıda bulabileceğiniz tasarım desenlerinin tam listesi:

Ve şimdi, listelenen kalıplardan bazılarına genel bakış başlatabiliriz

Singleton

Bu en popüler desenlerden biridir. Web uygulamalarını geliştirirken, genellikle belirli bir sınıfın (çalışma zamanı sırasında) yalnızca bir örneğine erişime izin vermek için kavramsal ve mimari açıdan mantıklıdır. Singleton modeli bunu yapmamızı sağlar. Örnek:

<?php
/**
 * Singleton class
 */
final class Product
{
    /**
     * @var self
     */
    private static $instance;
    /**
     * @var mixed
     */
    public $mix;
    /**
     * Return self instance
     *
     * @return self
     */
    public static function getInstance() {
        if (!(self::$instance instanceof self)) {
            self::$instance = new self();
        }
        return self::$instance;
    }
    private function __construct() {
    }
    private function __clone() {
    }
}
$firstProduct = Product::getInstance();
$secondProduct = Product::getInstance();
$firstProduct->mix = 'test';
$secondProduct->mix = 'example';
print_r($firstProduct->mix);
// example
print_r($secondProduct->mix);
// example

Multiton

Belki birisi projenizde çeşitli singletonları kullanmak isteyecektir:

<?php
abstract class FactoryAbstract {
    protected static $instances = array();
    public static function getInstance() {
        $className = static::getClassName();
        if (!(self::$instances[$className] instanceof $className)) {
            self::$instances[$className] = new $className();
        }
        return self::$instances[$className];
    }
    public static function removeInstance() {
        $className = static::getClassName();
        if (array_key_exists($className, self::$instances)) {
            unset(self::$instances[$className]);
        }
    }
    final protected static function getClassName() {
        return get_called_class();
    }
    protected function __construct() { }
    final protected function __clone() { }
}
abstract class Factory extends FactoryAbstract {
    final public static function getInstance() {
        return parent::getInstance();
    }
    final public static function removeInstance() {
        parent::removeInstance();
    }
}
// using:
class FirstProduct extends Factory {
    public $a = [];
}
class SecondProduct extends FirstProduct {
}
FirstProduct::getInstance()->a[] = 1;
SecondProduct::getInstance()->a[] = 2;
FirstProduct::getInstance()->a[] = 3;
SecondProduct::getInstance()->a[] = 4;
print_r(FirstProduct::getInstance()->a);
// array(1, 3)
print_r(SecondProduct::getInstance()->a);
// array(2, 4)

Strategy

Strateji modeli, algoritmalara dayanmaktadır. Belirli bir algoritmanın gerçek uygulama hakkında bilgi sahibi olmaması için istemci sınıfının sorumlu olmasını sağlayan belirli algoritma ailelerini kapsüllersiniz. Örnek:

<?php
interface OutputInterface {
    public function load();
}
class SerializedArrayOutput implements OutputInterface {
    public function load() {
        return serialize($arrayOfData);
    }
}
class JsonStringOutput implements OutputInterface {
    public function load() {
        return json_encode($arrayOfData);
    }
}
class ArrayOutput implements OutputInterface {
    public function load() {
        return $arrayOfData;
    }
}

Decorator

Bu model, duruma bağlı olarak çalışma zamanı sırasında bir nesneye yeni veya ek davranış eklememize olanak tanır. Örnek:

<?php
class HtmlTemplate {
    // any parent class methods
}
class Template1 extends HtmlTemplate {
    protected $_html;
    public function __construct() {
        $this->_html = "<p>__text__</p>";
    }
    public function set($html) {
        $this->_html = $html;
    }
    public function render() {
        echo $this->_html;
    }
}
class Template2 extends HtmlTemplate {
    protected $_element;
    public function __construct($s) {
        $this->_element = $s;
        $this->set("<h2>" . $this->_html . "</h2>");
    }
    public function __call($name, $args) {
        $this->_element->$name($args[0]);
    }
}
class Template3 extends HtmlTemplate {
    protected $_element;
    public function __construct($s) {
        $this->_element = $s;
        $this->set("<u>" . $this->_html . "</u>");
    }
    public function __call($name, $args) {
        $this->_element->$name($args[0]);
    }
}

Registry

Bu model genel listeden biraz gariptir, çünkü bu bir Yaratılış kalıbı değildir. Eh, kayıt – bu karma, ve statik yöntemlerle veriye erişebilirsiniz:

<?php
/**
* Registry class
*/
class Package {
    protected static $data = array();
    public static function set($key, $value) {
        self::$data[$key] = $value;
    }
    public static function get($key) {
        return isset(self::$data[$key]) ? self::$data[$key] : null;
    }
    final public static function removeObject($key) {
        if (array_key_exists($key, self::$data)) {
            unset(self::$data[$key]);
        }
    }
}
Package::set('name', 'Package name');
print_r(Package::get('name'));
// Package name

Factory

Bu başka bilinen bir model. Tam olarak göründüğü gibi davranır: Bu, nesne örneklerinin gerçek fabrikası olarak yapan sınıftır. Başka bir deyişle, bir tür ürün üreten fabrikaların olduğunu bildiğimizi varsayalım. Bir fabrikanın bu ürünü nasıl ürettiğine aldırmıyoruz, ancak herhangi bir fabrikanın bunu sormak için evrensel bir yolu olduğunu biliyoruz:

<?php
interface Factory {
    public function getProduct();
}
interface Product {
    public function getName();
}
class FirstFactory implements Factory {
    public function getProduct() {
        return new FirstProduct();
    }
}
class SecondFactory implements Factory {
    public function getProduct() {
        return new SecondProduct();
    }
}
class FirstProduct implements Product {
    public function getName() {
        return 'The first product';
    }
}
class SecondProduct implements Product {
    public function getName() {
        return 'Second product';
    }
}
$factory = new FirstFactory();
$firstProduct = $factory->getProduct();
$factory = new SecondFactory();
$secondProduct = $factory->getProduct();
print_r($firstProduct->getName());
// The first product
print_r($secondProduct->getName());
// Second product

Abstract Factory

Aynı türden fabrikalardan bazılarına sahip olduğumuz ve fabrikaların belirli bir göreve seçtikleri seçim mantığını kapsüllemek istediğimiz durumlar vardır. Bu model kurtarmaya geliyor:

<?php
class Config {
    public static $factory = 1;
}
interface Product {
    public function getName();
}
abstract class AbstractFactory {
    public static function getFactory() {
        switch (Config::$factory) {
            case 1:
                return new FirstFactory();
            case 2:
                return new SecondFactory();
        }
        throw new Exception('Bad config');
    }
    abstract public function getProduct();
}
class FirstFactory extends AbstractFactory {
    public function getProduct() {
        return new FirstProduct();
    }
}
class FirstProduct implements Product {
    public function getName() {
        return 'The product from the first factory';
    }
}
class SecondFactory extends AbstractFactory {
    public function getProduct() {
        return new SecondProduct();
    }
}
class SecondProduct implements Product {
    public function getName() {
        return 'The product from second factory';
    }
}
$firstProduct = AbstractFactory::getFactory()->getProduct();
Config::$factory = 2;
$secondProduct = AbstractFactory::getFactory()->getProduct();
print_r($firstProduct->getName());
// The first product from the first factory
print_r($secondProduct->getName());
// Second product from second factory

Observer

Bir nesne, başka bir nesneye, gözlemcinin kayıt yaptırmasına izin veren bir yöntem ekleyerek gözlemlenebilir hale getirilir. Gözlemlenebilir nesne değiştirilirse, gözlemci olarak kaydedilen nesnelere bir mesaj gönderir:

<?php
interface Observer {
  function onChanged($sender, $args);
}
interface Observable {
  function addObserver($observer);
}
class CustomerList implements Observable {
  private $_observers = array();
  public function addCustomer($name) {
    foreach($this->_observers as $obs)
      $obs->onChanged($this, $name);
  }
  public function addObserver($observer) {
    $this->_observers []= $observer;
  }
}
class CustomerListLogger implements Observer {
  public function onChanged($sender, $args) {
    echo( "'$args' Customer has been added to the list \n" );
  }
}
$ul = new UserList();
$ul->addObserver( new CustomerListLogger() );
$ul->addCustomer( "Jack" );

Adapter

Bu model, bir sınıfı farklı bir arabirim ile yeniden tanımlamanıza ve farklı arama yöntemleri kullanan bir sistem tarafından kullanılmasına izin verir:

<?php
class SimpleBook {
    private $author;
    private $title;
    function __construct($author_in, $title_in) {
        $this->author = $author_in;
        $this->title  = $title_in;
    }
    function getAuthor() {
        return $this->author;
    }
    function getTitle() {
        return $this->title;
    }
}
class BookAdapter {
    private $book;
    function __construct(SimpleBook $book_in) {
        $this->book = $book_in;
    }
    function getAuthorAndTitle() {
        return $this->book->getTitle().' by '.$this->book->getAuthor();
    }
}
// Usage
$book = new SimpleBook("Gamma, Helm, Johnson, and Vlissides", "Design Patterns");
$bookAdapter = new BookAdapter($book);
echo 'Author and Title: '.$bookAdapter->getAuthorAndTitle();
function echo $line_in) {
  echo $line_in."<br/>";
}

Lazy Initialization

İşte başka ilginç bir durum. Bir fabrikanız olduğunu hayal edin, ancak ihtiyacınız olan işlevselliğin bir kısmını bilmiyorsunuz ve “ne – hayır”. Bu gibi durumlarda gerekli işlemler sadece ihtiyaç duyulduğunda ve sadece bir kez yapılır:

<?php
interface Product {
    public function getName();
}
class Factory {
    protected $firstProduct;
    protected $secondProduct;
    public function getFirstProduct() {
        if (!$this->firstProduct) {
            $this->firstProduct = new FirstProduct();
        }
        return $this->firstProduct;
    }
    public function getSecondProduct() {
        if (!$this->secondProduct) {
            $this->secondProduct = new SecondProduct();
        }
        return $this->secondProduct;
    }
}
class FirstProduct implements Product {
    public function getName() {
        return 'The first product';
    }
}
class SecondProduct implements Product {
    public function getName() {
        return 'Second product';
    }
}
$factory = new Factory();
print_r($factory->getFirstProduct()->getName());
// The first product
print_r($factory->getSecondProduct()->getName());
// Second product
print_r($factory->getFirstProduct()->getName());
// The first product

Chain of responsibility

Desen ayrıca başka bir isme sahip – Komuta Zinciri. Bir dizi işleyici ile bir komut zinciri izler. İleti (sorgu) bu işleyicilerin bir dizisinden geçer ve her bağlantıda işleyicinin sorguyu işleyip işlemeyeceğini denetler. İşlem, bir işleyicinin isteği ele alabileceği anı durdurur:

<?php
interface Command {
    function onCommand($name, $args);
}
class CommandChain {
    private $_commands = array();
    public function addCommand($cmd) {
        $this->_commands[]= $cmd;
    }
    public function runCommand($name, $args) {
        foreach($this->_commands as $cmd) {
            if ($cmd->onCommand($name, $args))
                return;
        }
    }
}
class CustCommand implements Command {
    public function onCommand($name, $args) {
        if ($name != 'addCustomer')
            return false;
        echo("This is CustomerCommand handling 'addCustomer'\n");
        return true;
    }
}
class MailCommand implements Command {
    public function onCommand($name, $args) {
        if ($name != 'mail')
            return false;
        echo("This is MailCommand handling 'mail'\n");
        return true;
    }
}
$cc = new CommandChain();
$cc->addCommand( new CustCommand());
$cc->addCommand( new MailCommand());
$cc->runCommand('addCustomer', null);
$cc->runCommand('mail', null);

Object pool

Nesne havuzu – bir nesneyi başlatmak ve gerektiğinde bunları çıkarmak için istiflenebilen bir karmadır:

<?php
class Product {
    protected $id;
    public function __construct($id) {
        $this->id = $id;
    }
    public function getId() {
        return $this->id;
    }
}
class Factory {
    protected static $products = array();
    public static function pushProduct(Product $product) {
        self::$products[$product->getId()] = $product;
    }
    public static function getProduct($id) {
        return isset(self::$products[$id]) ? self::$products[$id] : null;
    }
    public static function removeProduct($id) {
        if (array_key_exists($id, self::$products)) {
            unset(self::$products[$id]);
        }
    }
}
Factory::pushProduct(new Product('first'));
Factory::pushProduct(new Product('second'));
print_r(Factory::getProduct('first')->getId());
// first
print_r(Factory::getProduct('second')->getId());
// second

Prototype

Bazen, bazı nesneler birden çok kez başlatılmalıdır. Özellikle başlatma işleminin zaman ve kaynak gerektirmesi durumunda, bunların başlatılmasından tasarruf etmek mantıklıdır. Prototip – önceden başlatılmış ve kaydedilmiş bir nesne. Gerekirse, klonlanabilir:

<?php
interface Product {
}
class Factory {
    private $product;
    public function __construct(Product $product) {
        $this->product = $product;
    }
    public function getProduct() {
        return clone $this->product;
    }
}
class SomeProduct implements Product {
    public $name;
}
$prototypeFactory = new Factory(new SomeProduct());
$firstProduct = $prototypeFactory->getProduct();
$firstProduct->name = 'The first product';
$secondProduct = $prototypeFactory->getProduct();
$secondProduct->name = 'Second product';
print_r($firstProduct->name);
// The first product
print_r($secondProduct->name);
// Second product

Builder

Bu şablon, karmaşık bir nesnenin oluşturulmasını kapsüllemek istediğimizde kullanılır:

<?php
class Product {
    private $name;
    public function setName($name) {
        $this->name = $name;
    }
    public function getName() {
        return $this->name;
    }
}
abstract class Builder {
    protected $product;
    final public function getProduct() {
        return $this->product;
    }
    public function buildProduct() {
        $this->product = new Product();
    }
}
class FirstBuilder extends Builder {
    public function buildProduct() {
        parent::buildProduct();
        $this->product->setName('The product of the first builder');
    }
}
class SecondBuilder extends Builder {
    public function buildProduct() {
        parent::buildProduct();
        $this->product->setName('The product of second builder');
    }
}
class Factory {
    private $builder;
    public function __construct(Builder $builder) {
        $this->builder = $builder;
        $this->builder->buildProduct();
    }
    public function getProduct() {
        return $this->builder->getProduct();
    }
}
$firstDirector = new Factory(new FirstBuilder());
$secondDirector = new Factory(new SecondBuilder());
print_r($firstDirector->getProduct()->getName());
// The product of the first builder
print_r($secondDirector->getProduct()->getName());
// The product of second builder

Bonus

Bir Cevap Yazın