Bambino
Новичок
Вопрос по теме управление зависимостями
Маленькое введение... Пишу приложение с использованием ООП. Есть желание написать его с использованием правильного ООП, т.е. чтобы не было глобальных переменных/функций (я имею в виду global, define), с наследованием, полиморфизмом и т.п.. Случайно наткнулся в одном из топиков на статью про "управление зависимостями в php". Прочитал, понял, что именно такая статья мне была необходима... и как оказалось, я делаю в принципе примерно так как описано в статье, т.е. каждый класс содержит строго свой функционал, "старается" ничего не знать о других классах. Общий смысл статьи я уловил, но с деталями как-то проблематично.. поэтому возникли вопросы:
1. Есть классы, функционирование которых я бы хотел протоколировать или запускать в отладочном режиме (ну т.е. обычный логгер всего, что делает приложение для быстрой отладки, если что). Режим отладки/протоколирования может отключаться для production-версии. Объект одного (основного) класса может создавать объекты других классов, а те в свою очередь могут создавать третьи объекты. Изначально я создал класс Debugger, содержащий метод writeLog, объект которого передавал корневому объекту и далее по цепочке. Мне это показалось сложным (запутанным), т.е. нужно было для каждого отлаживаемого класса создавать свойство $debugger, которому присваивать ссылку на объект Debugger и работать уже через это свойство ($this->debugger->writeLog()). Поэтому я взял и унаследовал класс Debugger всеми другими классами, которым необходима отладка/протоколирование. В голове еще вертелась идея использовать некий интерфейс Traceable (слышал звон, да не знаю где он...), содержащий метод writeLog(). Так что мой класс Debugger реализует этот интерфейс и, соответственно, содержит этот метод. Вследствие чего у каждого класса (который должен "отчитываться") есть свой метод writeLog, который я вызываю как $this->writeLog. Можно ли считать мой подход правильным или я все же намудрил и есть решение попроще?
2. Есть некий класс Core (core.class.php) - основной диспетчер функционала, подключаемый в самом начале любого php-файла приложения, который в зависимости от параметров/условий вызывает те или иные скрипты, создает те или иные общие (и не только) объекты. Например, объект класса Core создается в скрипте index.php, в котором в зависимости от того, проинсталлировано приложение или нет, либо выполняется основной функционал скрипта, либо вызывается новый скрипт install.php для инсталляции, который в свою очередь опять использует объект класса Core. Так вот в этом классе (Core) создаются какие-то общие (глобальный) объекты, например, объект класса Smarty для работы с HTML-шаблонами (в случае инсталляции отображаются параметры инсталляции, иначе целевое содержимое). Но, если при процедурном программировании я мог создать такой глобальный объект и потом использовать его методы везде, где будет подключен core.class.php, то в случае ООП, естественно, мой объект доступен только в области видимости класса Core. Т.е. для того, чтобы какой-нибудь модуль RenderModule отрисовал мне ХТМЛ код, я должен передать ему ссылку на объект Smarty, а в случае с наследованием этот объект придется опять передавать по цепочке. Дабы избежать этого я воспользовался паттерном Singleton (единственный паттерн, смысл которого я осознал). Теперь в любом методе любого класса я могу вызвать Smarty::getInstance(), возвращающий объект Smarty и рабоать с выводом. Правильно ли это? Все вроде работает, но червь сомнения грызет и кажется, что есть какой-то более красивый способ. Т.е. на данный момент все глобальные объекты я реализую через паттерн Singleton.
3. Опять на тему глобализации. Если мне нужны какие-то общие функции, ну, например, безопасное считывание массивов типа $_GET, создание директорий с некими проверками, форматирование вывода и т.п., то как правильно их оформлять? Через статические методы:
или "классическим" способом:
4. Я правильно понимаю термины?
наследование
композиция
Есть ли какое-то правило, когда стоит применять наследование, а когда композицию?
Как итого, испытываю трудности в реализации "общения" между объектами, такого, чтобы при правке возможных ошибок и наращивания функционала, не усложнять скрипты и не создавать новых ошибок.
Недеюсь, написал понятно. Заранее благодарен за ответы.
-~{}~ 27.03.10 02:43:
Еще вопрос возник, связанный с вопросом 4. Как правильнее?
так:
или так
Маленькое введение... Пишу приложение с использованием ООП. Есть желание написать его с использованием правильного ООП, т.е. чтобы не было глобальных переменных/функций (я имею в виду global, define), с наследованием, полиморфизмом и т.п.. Случайно наткнулся в одном из топиков на статью про "управление зависимостями в php". Прочитал, понял, что именно такая статья мне была необходима... и как оказалось, я делаю в принципе примерно так как описано в статье, т.е. каждый класс содержит строго свой функционал, "старается" ничего не знать о других классах. Общий смысл статьи я уловил, но с деталями как-то проблематично.. поэтому возникли вопросы:
1. Есть классы, функционирование которых я бы хотел протоколировать или запускать в отладочном режиме (ну т.е. обычный логгер всего, что делает приложение для быстрой отладки, если что). Режим отладки/протоколирования может отключаться для production-версии. Объект одного (основного) класса может создавать объекты других классов, а те в свою очередь могут создавать третьи объекты. Изначально я создал класс Debugger, содержащий метод writeLog, объект которого передавал корневому объекту и далее по цепочке. Мне это показалось сложным (запутанным), т.е. нужно было для каждого отлаживаемого класса создавать свойство $debugger, которому присваивать ссылку на объект Debugger и работать уже через это свойство ($this->debugger->writeLog()). Поэтому я взял и унаследовал класс Debugger всеми другими классами, которым необходима отладка/протоколирование. В голове еще вертелась идея использовать некий интерфейс Traceable (слышал звон, да не знаю где он...), содержащий метод writeLog(). Так что мой класс Debugger реализует этот интерфейс и, соответственно, содержит этот метод. Вследствие чего у каждого класса (который должен "отчитываться") есть свой метод writeLog, который я вызываю как $this->writeLog. Можно ли считать мой подход правильным или я все же намудрил и есть решение попроще?
2. Есть некий класс Core (core.class.php) - основной диспетчер функционала, подключаемый в самом начале любого php-файла приложения, который в зависимости от параметров/условий вызывает те или иные скрипты, создает те или иные общие (и не только) объекты. Например, объект класса Core создается в скрипте index.php, в котором в зависимости от того, проинсталлировано приложение или нет, либо выполняется основной функционал скрипта, либо вызывается новый скрипт install.php для инсталляции, который в свою очередь опять использует объект класса Core. Так вот в этом классе (Core) создаются какие-то общие (глобальный) объекты, например, объект класса Smarty для работы с HTML-шаблонами (в случае инсталляции отображаются параметры инсталляции, иначе целевое содержимое). Но, если при процедурном программировании я мог создать такой глобальный объект и потом использовать его методы везде, где будет подключен core.class.php, то в случае ООП, естественно, мой объект доступен только в области видимости класса Core. Т.е. для того, чтобы какой-нибудь модуль RenderModule отрисовал мне ХТМЛ код, я должен передать ему ссылку на объект Smarty, а в случае с наследованием этот объект придется опять передавать по цепочке. Дабы избежать этого я воспользовался паттерном Singleton (единственный паттерн, смысл которого я осознал). Теперь в любом методе любого класса я могу вызвать Smarty::getInstance(), возвращающий объект Smarty и рабоать с выводом. Правильно ли это? Все вроде работает, но червь сомнения грызет и кажется, что есть какой-то более красивый способ. Т.е. на данный момент все глобальные объекты я реализую через паттерн Singleton.
3. Опять на тему глобализации. Если мне нужны какие-то общие функции, ну, например, безопасное считывание массивов типа $_GET, создание директорий с некими проверками, форматирование вывода и т.п., то как правильно их оформлять? Через статические методы:
PHP:
class Common
static function GET ( $var,$default = null ) {
return isset ( $_GET[$var] ) ? $_GET[$var] : $default;
}
}
class Foo {
function __construct () {
$var = Common::GET('var');
}
}
PHP:
class Common
function GET ( $var,$default = null ) {
return isset ( $_GET[$var] ) ? $_GET[$var] : $default;
}
static function getInstance () {
...
}
}
class Foo {
function __construct () {
$GLO = new Common; // создали глобальный объект (в каком-нибудь общем подключаемом файле)
$GLO->GET ( 'var' ); // просто вызываем метод класса
}
}
class Bar {
function __construct () {
$var = Common::getInstance()->GET('var'); // через паттерн Singleton используем в других классах
}
}
наследование
PHP:
class Foo {
}
class Bar extends Foo {
}
PHP:
class Foo {
}
class Bar {
private $Foo = null;
function __construct () {
$Foo = new Foo ();
}
}
Как итого, испытываю трудности в реализации "общения" между объектами, такого, чтобы при правке возможных ошибок и наращивания функционала, не усложнять скрипты и не создавать новых ошибок.
Недеюсь, написал понятно. Заранее благодарен за ответы.
-~{}~ 27.03.10 02:43:
Еще вопрос возник, связанный с вопросом 4. Как правильнее?
PHP:
class DbDriver extends PDO {
function query () {
parent::query ( ... );
...
}
}
class DbConnection {
protected $conn = null;
function __construct () {
$this->conn = new DbDriver ();
}
function getConn () {
return $this->conn;
}
}
PHP:
class DbManager extends DbConnection {
function createTable () {
$this->conn->query ('...');
}
}
PHP:
class DbManager {
private $conn = null;
function __construct () {
$conn = new DbConnection ();
$this->conn = $conn->getConn ();
}
function createTable () {
$this->conn->query ('...');
}
}
