Singleton
Один шаблон - это часто используемый шаблон во многих приложениях, когда требуется только один экземпляр ресурса. Наиболее очевидным типом ресурса для веб-страниц PHP является соединение с базой данных, хотя могут использоваться и другие типы ресурсов. При получении динамического создания веб-страницы может потребоваться выполнить несколько вызовов базы данных. Если вместо создания нескольких соединений можно использовать один экземпляр ресурса, накладные расходы минимизируются. Единственный экземпляр в этом случае создается шаблоном синглтона.
<?php
class db {
/*** Declare instance ***/
private static $instance = NULL;
/**
* the constructor is set to private so
* so nobody can create a new instance using new
*/
private function __construct() {
/*** maybe set the db name here later ***/
}
/**
* Return DB instance or create intitial connection
* @return object (PDO)
* @access public
*/
public static function getInstance() {
if (!self::$instance) {
self::$instance = new PDO("mysql:host='localhost';dbname='animals'", 'username', 'password');
self::$instance->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
}
return self::$instance;
}
/**
* Like the constructor, we make __clone private
* so nobody can clone the instance
*/
private function __clone() {
}
} /*** end of class ***/
?>
Давайте посмотрим, что произошло в синглтон-классе выше. Имя переменной $instance
создано и сделано private
, это никому не гарантирует и пытается получить к ней доступ напрямую. Точно так же методы конструктора и __clone стали частными, чтобы предотвратить клонирование класса или того, кто пытается создать экземпляр его экземпляра. У класса есть единственный метод для предоставления ресурса, метод getInstance()
.
Метод getInstance()
проверяет, что экземпляр еще не существует. Если экземпляр не существует, создается новый экземпляр класса PDO и назначается переменной $instance
. Если существующий экземпляр доступен, метод getInstance()
возвращает это. В результате возвращаемое значение всегда является одним и тем же экземпляром, и новый ресурс или служебные данные не требуются.
Вот небольшая демонстрация того, как это может быть использовано в приложении.
<?php
try {
/*** query the database ***/
$result = DB::getInstance()->query("SELECT animal_type, animal_name FROM animals");
/*** loop over the results ***/
foreach ($result as $row) {
print $row['animal_type'] .' - '. $row['animal_name'] . '<br />';
}
} catch (PDOException $e) {
echo $e->getMessage();
}
?>
Завод
Фабричный шаблон - это класс, который создает объекты для вас, а не вам нужно использовать новое ключевое слово для его создания. Фабрика, как следует из названия, фабрика для создания объектов. Почему нам это надо? Давайте рассмотрим приложение, которое использует файл ini
для конфигурации. Затем приложение изменяется, чтобы получить параметры конфигурации из базы данных. Остальная часть приложения разваливается, как карточный домик, когда база удаляется.
Эта " жесткая связь " объектов, где каждый объект сильно зависит от другого, создает проблемы в более крупных приложениях. Система необходима, когда объекты могут ссылаться друг на друга, но не являются взаимозависимыми.
В нашем примере файл конфигурации становится базой данных, если другие классы зависели от класса, считывающего из файла ini
, и это неожиданно было поручено возникновению проблем с классом базы данных.
Используя шаблон проектирования фабрики, если вы измените тип объекта из класса считывателя ini
на класс базы данных, вам нужно только изменить фабрику. Любой другой код, который использует фабрику, будет обновлен автоматически.
<?php
/**
* @config interface
*/
interface Config {
function getName();
}
/**
* @config class
*/
class userConfig implements Config {
/*
* @username
*/
public $user_id;
/*** contructor is empty ***/
public function __construct($id) {
$this->user_id = $id;
}
public static function Load($id) {
return new userConfig($id);
}
public function getName() {
try {
/*** query the database ***/
$sql = "SELECT username FROM user_table WHERE user_id=:user_id";
$db = db::getInstance();
$stmt = $db->prepare($sql)
$stmt->bindParam(':user_id', $this->user_id, PDO::PARAM_INT);
return $stmt->fetch(PDO::FETCH_COLUMN);
} catch (PDOException $e) {
/*** handle exception here ***/
return false;
}
}
} /*** end of class ***/
/*** returns instance of config ***/
$conf = userConfig::Load( 1 );
echo $conf->getName();
?>
Это может показаться немного чрезмерным кодом для простого получения имени пользователя. Но в крупномасштабном приложении, где выполняется переход от файла к поиску базы данных, результаты могут быть катастрофическими. Здесь просто вопрос изменения метода getName()
, который возвращает имя, и возвращаемый объект такой же, что позволяет другим частям приложения, которым требуется имя пользователя, например, логин для корзины, продолжать работу, пока они делал ранее.