Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате
Форум программистов > PHP: Общие вопросы > Паттерн Внедрение Зависимости


Автор: solenko 16.7.2009, 17:39
Не так давно появился сайт http://components.symfony-project.org, на который авторы фреймверка symfony выкладывают библиотеки, которые написаны в процессе разработки фреймверка, но могут быть использованы отдельно.

Один из таких компонентов -- Symfony Service Container.
Это компонент, который реализует паттерн Контейнер Внедрения Зависимостей.
Также была написана небольшая http://components.symfony-project.org/dependency-injection/trunk/book/, которая описывает принципы работы компонента.

Книгу стоит почитать даже если вы не собираетесь использовать компонент -- первые главы описывают сам паттерн, а не конкретный компонент.

Мой вариант превода книги: http://madbee.ukr.su/solenko/dependency-injection/

ksnk и Sanchezzz - очень рекомендую для прочтения (после тем о загрузке классов).

Буду благодарен за критику перевода -- как-никак первый опыт.

Автор: ksnk 16.7.2009, 18:02
solenko, Там есть орфографических ошибок. Можно внедрить систему http://orphus.ru/ и корректировать прямо по прочтении...

А вообще - спасибо! Не  дочитал, но пока - интересно smile

Автор: ksnk 16.7.2009, 18:30
Паттерн, вообще говоря, требует перепроектирование уже спроектированной системы :-( 

К примеру, разнообразные плагины CMS'ки в редкие моменты своего функционирования желают воспользоватся функцией mail. Мы, как умные ООП программисты обернули mail в показавшуюся нам удобной в тот момент обертку.
Строки, работающие с классом выглядят как 
Код

$mail = new mail();
... // send mail 


В дальнейшей жизни нам показалось недостаточной реализация mail и родилась обертка mail2.
Рассматриваются варианты внедрения новой обертки в уже существующие тексты плагинов с минимальной правкой исходного кода...

Рассматриваемый паттерн предлагает нам подставлять уже проинициализированный элемент класса mail2 в объект, не взирая на то, что этот класс реально может и не понадобится? Это ли тру ООП?

Автор: ksnk 16.7.2009, 19:15
в статье Контейнеры Внедрения Зависимостей автор путает паттерн фабрика с паттерном "Внедрения зависимостей" smile 

Вообще, это паттерн-ориентированное программирование - тупик. Нужно сначала писать код, а потом уже угадывать в его контурах тот или иной паттерн  smile 

Автор: solenko 16.7.2009, 19:59
Цитата(ksnk @  16.7.2009,  17:30 Найти цитируемый пост)
Рассматриваемый паттерн предлагает нам подставлять уже проинициализированный элемент класса mail2 в объект, не взирая на то, что этот класс реально может и не понадобится? Это ли тру ООП?


Заивисимость != может использовать. Т.е. если ваш класс не может работать без какого-либо другого, то имеет смысл использовать внедрение зависимости. В вашем же случае -- нет.


Цитата(ksnk @  16.7.2009,  18:15 Найти цитируемый пост)
в статье Контейнеры Внедрения Зависимостей автор путает паттерн фабрика с паттерном "Внедрения зависимостей" 

Похоже вы путаете то, что автор называет Dependency Injection и Dependency Injection Container. Непосредственно внедрению зависимостей посвящена только первая глава.

Паттерн фабрика предназначен не для разрешения проблеммы зависимостей. Фабрика просто создает какой-либо из подтипов (наследников) более общего типа. При этом ничего не зная о том как его инициализировать и о его зависимостях.

Автор: ksnk 16.7.2009, 20:06
Цитата(solenko @  16.7.2009,  19:59 Найти цитируемый пост)
Dependency Injection Container

в статье - это чистой воды фабрика. объект пользователь спрашивает у объекта фабрики - "Дай мне экземпляр объекта mail"... То что этот вопрос формулируется в виде вызова функции контейнера никак не влияет на фабричность... smile Описывемый в первой главе паттерн - это да, это Dependency Injection. А остальное к нему имеет не очень большое отношение. 
Польза Dependency Injection в том, что есть единственное место (сонфигурационный файл), в котором в экземпляр - контейнер  вставляют необходимые ему для работы уже проинициированные компоненты. 
А естл эти компоненты сокрыты в непонятно где лежащем отдельном объекте контейнер, "инициализация" которого делается типично фабричным методом, то и называть такой контейнер стоит фабрикой...

Автор: solenko 16.7.2009, 20:14
Цитата(ksnk @  16.7.2009,  19:06 Найти цитируемый пост)
в статье - это чистой воды фабрика. объект пользователь спрашивает у объекта фабрики - "Дай мне экземпляр объекта mail"... То что этот вопрос формулируется в виде вызова функции контейнера никак не влияет на фабричность...

Вот только не просто создается объект mail (фабрика), а еще и выполняется его конфигурирование -- создается объект mail_transport (контейнер).

Основная разница как раз в том, что фабрика подразумевает самоконфигурирование объектов, а контейнер -- конфигурирует их.

Добавлено через 2 минуты и 28 секунд
Кроме того, фабрика порождает объекты какого-либо одного класса (т.е. возвращает экземпляры подклассов одного класса), а контейнер работает с произвольными классами. Хотя ключевая разница -- конфигурирование.

Добавлено через 5 минут и 1 секунду
Кстати, перефодом я занялся после прочтения http://habrahabr.ru/blogs/php/64061/
Там рассматривается разница фабрики и контейнера.

Автор: youri 16.7.2009, 21:45
Цитата(ksnk @  16.7.2009,  19:15 Найти цитируемый пост)
Вообще, это паттерн-ориентированное программирование - тупик. Нужно сначала писать код, а потом уже угадывать в его контурах тот или иной паттерн   

и какой смысл "потом" в паттернах? Это какое-то антипаттерн-ориентированное программирование ;)

Автор: ksnk 16.7.2009, 22:47
youri, Ну дык откуда взялись-то паттерны? Просто их "отцы-создатели" анализировали большое количество кода и обнаружили, что приемы программирования, вообще говоря можно классифицировать. Примерно та-же фигня, как и в биологии. Типо - хордовые, покрытосемменные, парнокопытные... Сильно обрадовались биологи и начали все обзывать по новой классификации, ан не тут-то было. природа она завсегда всякой классификации найдет свое исключение... smile 

Цитата(youri @  16.7.2009,  21:45 Найти цитируемый пост)
Это какое-то антипаттерн-ориентированное программирование ;) 

"Здравый смысл"-ориентированное программирование!  

Цитата(solenko @  16.7.2009,  20:14 Найти цитируемый пост)
 а еще и выполняется его конфигурирование -- создается объект mail_transport 

Да ну? Вот квинтэссенция статьи "Контейнеры Внедрения Зависимостей". Тру-ООП код, размещенный предпоследним (последний пример - несущественная для ООП мутация в сторону синглтона)
Код

class Container
{
  // ...
 
  public function getMailer()

  {
    $class = $this->parameters['mailer.class'];
 
    $mailer = new $class();
    $mailer->setDefaultTransport($this->getMailTransport());

 
    return $mailer;
  }
}
 
$container = new Container(array(

  'mailer.username' => 'foo',
  'mailer.password' => 'bar',
  'mailer.class'    => 'Zend_Mail',

));
$mailer = $container->getMailer();

Чем, скажите мне, этот код не фабрика? "Фабричный класс" имеет четко определенный (пустой) конструктор. Сам конструктор обязан инициализироваться, выковыривая из некоей "регистри" собственные параметры. Чужой дядя, обращается к контейнеру со словами "getMailer" - дай мне почтальона... Причем тут еще какой-то Dependency Injection? Тем что этот код мутациями и издевательствами из него трансформировали?

Добавлено через 12 минут и 23 секунды
А в статейке-затравке мне понравился вот такой код-конфигурация:
Код

$injector = new Phemto(); 
$injector->whenCreating('Page')->forVariable('session')->willUse(new Reused('Session')); 
$injector->whenCreating('Page')->forVariable('continuation')->willUse('Continuation'); 
$injector->whenCreating('Page')->forVariable('alerts')->willUse('Alert'); 
$injector->whenCreating('Page')->forVariable('accounts')->willUse('Accounts'); 
$injector->whenCreating('Page')->forVariable('mailer')->willUse('Mailer'); 
$injector->whenCreating('Page')->forVariable('clock')->willUse('Clock'); 
$injector->whenCreating('Page')->forVariable('request')->willUse('Request'); 
return $injector;

 Есть в этом некая благородная креза! Хотя обильное повторение некоторых слов портит все впечатление... А вот если переписать этого монстра с помощью ассоциированного массива, может получится радующая мой глаз конструкция
Код

$injector = new Phemto(array(
  'Page'=>array(
       'session'=>new Reused('Session'), 
       'continuation'=>'Continuation', 
       'alerts'=>'Alert',
... 
)));
return $injector;


Автор: Sanchezzz 17.7.2009, 08:16
Цитата

$injector = new Phemto(array(
  'Page'=>array(
       'session'=>new Reused('Session'), 
       'continuation'=>'Continuation', 
       'alerts'=>'Alert',
... 
)));
return $injector;

По мне фабрика лучше выглядит, когда ты только передаешь названия нужных тебе для подключения классов и через другую функцию получаешь нужный тебе экземпляр или на прямую через массив классов.
Меньше леса получается да и читается код с легкостью


Автор: Sanchezzz 17.7.2009, 08:42
прочитав до конца статью, я кое что вывел полезное для себя, пока это объяснить не могу а покажу  кодом , сча попробую накатать велосипед (очередной).

Автор: youri 17.7.2009, 09:11
Цитата(ksnk @  16.7.2009,  22:47 Найти цитируемый пост)
Сильно обрадовались биологи и начали все обзывать по новой классификации, ан не тут-то было. природа она завсегда всякой классификации найдет свое исключение...  

а кто-то говорит, что нужно насоздавать паттернов на все случаи жизни? Кроме того, мне кажется, что паттерны скорее относятся к проектированию, чем к написанию кода. Вот у тебя в разработке есть такой этап как проектирование?

Цитата(ksnk @  16.7.2009,  19:15 Найти цитируемый пост)
Нужно сначала писать код, а потом уже угадывать в его контурах тот или иной паттерн   

я просто не понимаю, зачем после написания кода угадывать в нем какие-то паттерны. И для чего тогда паттерны вообще?

Автор: ksnk 17.7.2009, 10:57
Цитата(youri @  17.7.2009,  09:11 Найти цитируемый пост)
Вот у тебя в разработке есть такой этап как проектирование?

Вот у меня в разработке есть такой этап как перепроектирование на ходу ;-) если проект живет достаточно долго, для него, imho, в обязательном порядке наступит такой этап. Продуманная изначально архитектура позволит пережить этот этап с допустимыми потерями.

А вообще, раз и навсегда спроектированные приложения, это такая-же абстракция как и чистые, незамутненные паттерны и сферические кони. Они никому не нужны, так как не существуют в природе.

А паттерны нужны для анализа получившегося кода на этапе "доводка напильником после проектирования". Паттерны - достаточно удачные решения в каких-то ситуациях. Их нужно знать Можно "поугадывать контуры" в реальных монстрах и, если это принесет пользу, "откорректировать мутацию"...

Автор: youri 17.7.2009, 11:29
Цитата(ksnk @  17.7.2009,  10:57 Найти цитируемый пост)
А вообще, раз и навсегда спроектированные приложения, это такая-же абстракция как и чистые, незамутненные паттерны и сферические кони. Они никому не нужны, так как не существуют в природе.

а где я говорил, про навсегда спроектированные приложения? Ведь придумали же такую штуку как проектирование... навреное не просто так... или ты думаешь, что думать перед тем как что-то делать - абсолютно бессмысленное занятие?

Автор: icewind 17.7.2009, 12:27
solenko, спасибо. Пока что бегло просмотрел. Чуть позже прочту полностью.

Автор: ksnk 17.7.2009, 13:02
youri, Вопрос "проектируете ли вы свое приложение?" напоминает мне "как часто вы бьете свою жену?". Какой ответ предполагается услышать?  smile 

Автор: Sanchezzz 17.7.2009, 13:10
 smile ksnk  smile .
youri,да тут дураку понятно что "без проектирования и мысленного представления как это будет работать далеко не удишь."

Автор: fesor 17.7.2009, 13:26
Штука интересная но неимет смысла ее использовать.

Автор: youri 17.7.2009, 13:30
Цитата(ksnk @  17.7.2009,  13:02 Найти цитируемый пост)
youri, Вопрос "проектируете ли вы свое приложение?" напоминает мне "как часто вы бьете свою жену?". Какой ответ предполагается услышать?   

вроде ж ты ответил уже
просто я тебя понял так, что проектирование - ненужная вещь

Автор: solenko 17.7.2009, 13:30
fesor, а обосновать?

Автор: fesor 17.7.2009, 14:29
Ну например тм рассматривается пример:
В класс системы пользователей передают 2 класа: для работы с БД и управление сессиями. Там же используется такой код: $this->db->execute  к примеру. Это уже задает ограничение на интерфейс класса (ну тобиш названия методов меняться не будут уже. Можно только добавить новых а иначе снова искать и убирать лишнее). Почему бы тогда не воспользоваться чем-то вроде system:: db()->execute() (кстати это довольно похоже на класс-контейнер) или db::execute() вообще...

Ну со своим высказыванием я погорячился, этот паттер много где встречается и в моих проектах, просто я незнал что это типа "фишка" (я конкретно про контейнеры). А так это надо знать чтобы потом повыпендриваться. Всеравно насколько я знаю мало кто придерживается каки-хто святых стандартов и паттернов когда у вас дедлайн через 3 часа)

Автор: ksnk 17.7.2009, 14:51
Цитата(youri @  17.7.2009,  13:30 Найти цитируемый пост)
просто я тебя понял так, что проектирование - ненужная вещь 

Ненужная вешь - проектировать "под паттерны". Нужно расписывать задачи, которые предстоит решать и представить себе пути их решения. Потом решение можно откорректиовать, имея ввиду уже наработанный багаж решений, которые зазываются "паттернами".
Впрочем это уже философия и метафизика... Оно все само как-то поолучается  smile 

Автор: solenko 17.7.2009, 15:27
Цитата(fesor @  17.7.2009,  13:29 Найти цитируемый пост)
Там же используется такой код: $this->db->execute  к примеру. Это уже задает ограничение на интерфейс класса (ну тобиш названия методов меняться не будут уже. Можно только добавить новых а иначе снова искать и убирать лишнее).

Оограничения по интерфейсу есть всегда, даже в разговорной речи. Главное чтобы при смене реализации этот интерфейс не менялся.
 
Цитата(fesor @  17.7.2009,  13:29 Найти цитируемый пост)
Почему бы тогда не воспользоваться чем-то вроде system:: db()->execute() (кстати это довольно похоже на класс-контейнер) или db::execute() вообще...

system:: db()->execute() -- вводятся новые зависимости. Теперь ваш класс зависит от некоего system, от db и от того проинициализирован ли класс db в system.
db::execute()  -- кто занимается инициализацией класса db? Каким образом работать с несколькими базами данных?

Добавлено через 6 минут и 35 секунд
Цитата(ksnk @  16.7.2009,  21:47 Найти цитируемый пост)
Чем, скажите мне, этот код не фабрика? "Фабричный класс" имеет четко определенный (пустой) конструктор. Сам конструктор обязан инициализироваться, выковыривая из некоей "регистри" собственные параметры. Чужой дядя, обращается к контейнеру со словами "getMailer" - дай мне почтальона... Причем тут еще какой-то Dependency Injection? Тем что этот код мутациями и издевательствами из него трансформировали?


Dependency Injection в данном случае -- установка класса транспорта.

Не все то, что пораждает объекты, зовется фабрикой. Суть фабрики в том, чтобы прозрачно для клиента решить какой из подттипов объета вернуть. Фабрика не работает с любыми типами объектов. То что вы приводили в темах о подключении модулей к фабрике имеет слабое отношение.

Суть контейнера в том, чтобы:
1. Создать все объекты-зависимости
2. Создать сам запрашиваемый объект
3. Выполнить инициализацию объекта, передав все зависимости и начальные настройки.

Фабрика из всего этого выполняет лишь второй пунт.

Автор: youri 17.7.2009, 17:00
Цитата(ksnk @  17.7.2009,  14:51 Найти цитируемый пост)
Ненужная вешь - проектировать "под паттерны"

Цитата(ksnk @  16.7.2009,  19:15 Найти цитируемый пост)
Нужно сначала писать код, а потом уже угадывать в его контурах тот или иной паттерн

т.е., обдумывая пути решения задачи, мы должны отбросить пути решения с помощью паттернов (даже если знаем, что их надо будет потом использовать). Это меня, собственно, и смущает. Это твоя позиция?

Автор: ksnk 17.7.2009, 17:14
Цитата(solenko @  17.7.2009,  15:27 Найти цитируемый пост)
1. Создать все объекты-зависимости

Тутошний контейнер не создает, а знает как создавать. Разница, в некоторых случаях значительная...
Цитата(solenko @  17.7.2009,  15:27 Найти цитируемый пост)
3. Выполнить инициализацию объекта, передав все зависимости и начальные настройки.

В каком месте в отквоченном мной коде производится инициализация объекта? инииализацией объекта занят сам объект... 

Ну вот, нужно начинать с определений smile Что есть фабрика, что есть регистри, а что есть Dependency Injection и его контейнер? Желательно просто и понятно, как Аристотелево определение человека...

Следует иметь ввиду, что "паттерны программирования", а не "паттерны ООП программирования". То есть в определении слово "класс" и "объект" должно иметь значение "черный ящик", с определенным списком свойств.

К примеру:
Регистри - ящик, имеющий 2 функции. 
-- по имени (возможно строковому, но не обязательно) и значению сохраняет где-то в себе эту пару,  
-- по имени может выдать сохраненное значение.
Примерная дисциплина использования - любой объект может чего-то сохранить, любой объект может чего-то запросить...

Фабрика - это регистри, отягченная ограничениями.
-- не все имеют право (кроме специально обученных объектов-конфигурации) изменять соответствие имя-значение.

Фабрика объектов - выдаваемое фабрикой значение - объекты с унифицированным ( с одинаковым смыслом и порядком параметров) конструктором.

Автор: solenko 17.7.2009, 17:20
Цитата(ksnk @  17.7.2009,  16:14 Найти цитируемый пост)
В каком месте в отквоченном мной коде производится инициализация объекта? инииализацией объекта занят сам объект... 

вот в этой:
Цитата(ksnk @  16.7.2009,  21:47 Найти цитируемый пост)

Код

$mailer->setDefaultTransport($this->getMailTransport());


Сам объект не запрашивает какой ему пранспорт использовать.

Автор: ksnk 17.7.2009, 18:13
Цитата(solenko @  17.7.2009,  17:20 Найти цитируемый пост)
вот в этой:

Это я упустил ;-(

Однако так получается, что у нас знания о классе - мейлере размазаны по большому количеству кода. если вообразить, что нам понадобился класс, реализованный вообще без параметров (на встроенном mail'е) нам придется править конфиг $container = new Container ... (ну это уж необходимо)
и придется править метод getMailTransport в описателе некоего контейнера неизвестно где описанного... 

Это я про то, что если проявить должную дисциплину при создании обертки, получившийся фабричный элемент был бы более Тру-ООпным. Править пришлось бы только в одном месте, в конфигурации...

Автор: solenko 17.7.2009, 19:03
Цитата(ksnk @  17.7.2009,  17:13 Найти цитируемый пост)
Однако так получается, что у нас знания о классе - мейлере размазаны по большому количеству кода.

Знания о нем сосредоточены в одном месте -- контейнере. А в идеале -- файле-конфигурации контейнера. Собственно, в этом и смысл контейнера.

Цитата(ksnk @  17.7.2009,  17:13 Найти цитируемый пост)
сли вообразить, что нам понадобился класс, реализованный вообще без параметров (на встроенном mail'е) нам придется править конфиг $container = new Container ... (ну это уж необходимо)и придется править метод getMailTransport в описателе некоего контейнера неизвестно где описанного... 


Вообще-то достаточно удалить вызов $mailer->setDefaultTransport(). При использовании Symfony Service Container -- удалить одну строку его конфига.

Автор: fesor 18.7.2009, 00:11
Цитата

system:: db()->execute() -- вводятся новые зависимости. 

Ну допустим класс system является главным в системе и в него все загружается (как в контейнер). Допустим где-то понадобилось вызвать базу данных. Сделав доступ к функции db() класса system мы смотрим, загружен ли класс для работы с БД и если нет - загружаем. Ну и отдаем его. Мне такая реализации кажется достаточно простой и не напряжной в плане расширения.

Автор: solenko 18.7.2009, 04:33
Цитата(fesor @  17.7.2009,  23:11 Найти цитируемый пост)
Ну допустим класс system является главным в системе

В какой системе? В той, которую вы пишите именно сейчас? А как испоьзовать ваши классы, расчитанные на system Sanchezzz-у, который любит называть свой мегакласс, содержащий все, 
Core? Прелесть внедрения зависимостей как раз в том, что класс не знает с каким именно классом он работает -- важен интерфейс. И прелесть контейнера в том, что класс не знает о его существовании -- нет зависимости от контейнера.

Автор: fesor 18.7.2009, 08:49
Ну ладно... тогда стоит рассмотреть этот вариант.

Автор: Sanchezzz 20.7.2009, 08:04
solenko мои классы и работаю и отдельно вне зависимости от моего мега-класса которого я люблю называть "core", бери и подключай.

Мой "core" не случайно называется так, при разработки велосипеда мои задачи были такие:
Нужно было сделать класс который будет подрубать классы и раздавать что первое и получилось.
Затем нужно было создать в ядре функцию которая будет отвечать за подключение зависимых классов, такие классы служат в роли компонентов которые отвечают за контент: новости, блоги, форумы итд.
Также эти компоненты получают доступ к функциям ядра и способность использовать подрубленные классы или подключать их.
Минус в них то они имеют обязательных 2 функции одна из ник подключение шаблона логики для вывода информации и функция вызова, которая  готовит данные для шаблона логики. 

Так выглядит у меня зависимый класс
Код

class news {
 function includeTemplate($name){
  // ... include
 }

 function create($parms = array()){
   /* способ 1*/
   $this->core->initModel('block'); // возращяет также класс      
   $block = new $this->core->class['block']; //Копия блоков это контейнеры информации
   $block->db = this->core->db; // обоьект БД

   /* способ 2*/
   $block  = $this->core->initModel('block');
   $block->db = this->core->db; // обоьект БД

   $arrData = $block->getElementByBlockID($parms['ID']);
   /* подключение вывода */
   $this->includeTemplate($parms['tmp1']);

 }
}


Сча я стараюсь доделать это дело до совершенства сделать как можно меньше зависимости.


Автор: fesor 20.7.2009, 09:06
код очень похож на мой первый фреймворк)

Автор: Sanchezzz 20.7.2009, 09:18
ну это не фреймворк это кусок компонента. (зависимый класс от ядра ((( так для наглядности )
Цитата

код очень похож на мой первый фреймворк)

и что стало с твоим первым фреймворком полетел в топку? или дышит до сих пор?

Автор: fesor 20.7.2009, 09:23
Ну я понял.

Мой фреймворк? Ну я сделал на нем пару проектов и еще надо наверное будет сделать штуки 3... но наверное я его буду переписывать с нуля и попробую написать с его помощью небольшую CMS (мол Joomla c ТРУ MVC+ActiveRecord, блэкджеком и... девушками...)

для нее например контроллер будет выглядеть примерно так:
Код

class PostController extends Controller
{
    public function actionShow()
    {
         $criterias = array(
              array('post_id', $GET['id']),
              array('published', true),
         );
         $post = Post::model()->with('comments', 'profiles')->find($criterias);
         view::render('fullview', $post);
    }
}


Но я еще неуверен что это самый красивый вариант, а ничего красивее не придумалось(

Автор: solenko 20.7.2009, 09:59
Цитата(Sanchezzz @  20.7.2009,  07:04 Найти цитируемый пост)
solenko мои классы и работаю и отдельно вне зависимости от моего мега-класса которого я люблю называть "core", бери и подключай.

Да, передавая ссылку на Core во все классы, вы используете паттерн внедрения зависимости и не зависите от имени класса )
Вот только вы вводите зависимость от core + всех классов, от которых данный компонент действительно зависит. И просто "бери и подключай" не получится, т.к. класс c интерфейсом Core таки необходим.

Автор: Sanchezzz 20.7.2009, 10:19
прочитай внимательнее я написал что у меня 2 типа классов которые не зависят от ядра и есть зависимые которые ваше подключаются через другую функцию и зачем мне подрубать компоненты независимо от ядра если они под мою систему заточены? на то они и кмпоненты.
Цитата

И просто "бери и подключай" не получится, т.к. класс c интерфейсом Core таки необходим.
.
со вторым типом классов да не получится и мне это не так сильно важно.
а с первым все работает на ура.

Автор: IZ@TOP 14.8.2009, 19:56
Мега тема! Особенно про "мега класс, который Сначез любит называть Core" - валялся) И про девушек с блэкджеком - супер)
А вообще, автору респект. Интересные моменты уловил, для себя заметки сделал.

P.S. А вы знаете чем больше всего полезны паттерны? Мы их все знаем и при необходимости изучения/дополнения чужого гоvнокода своим, вполне сможем его понять и с ним работать  smile  smile 

Powered by Invision Power Board (http://www.invisionboard.com)
© Invision Power Services (http://www.invisionpower.com)