Логин:   Пароль:






Новости
Рассылки
Форум
Поиск


Java
- Апплеты
- Вопрос-ответ
- Классы
- Примеры
- Руководства
- Статьи
- IDE
- Словарь терминов
- Скачать

Мобильная Java
- Игры
- Примеры
- Статьи
- WAP, WML и пр.

JavaScript
- Вопрос-ответ
- Примеры
- Статьи

Веб-мастеринг
- HTML
- CSS
- SSI

Разминка для ума
Проекты
Книги
Ссылки
Программы
Юмор :)




Rambler's Top100
Rambler's Top100

Java: СтатьиО том, как крутой программер Вася Ковырялкин посредника искал

О том, как крутой программер Вася Ковырялкин посредника искал

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

Вася работал над распределенной системой в солидном банке, и как это часто бывает, система была очень запутанной и непонятной. Как большинство всех систем, создаваемых на территории бывшего СССР, она никогда никем не проектировалась, а возникла стихийно из отдельных программ, связанных друг с другом через заднее место. Отдавая должное, надо сказать, что, не смотря ни на что, система работала исправно. Все бы было хорошо, если бы ее не надо было постоянно модифицировать. Практически никто кроме Васи не был способен разобраться в ней, и Вася очень гордился этим. Между тем, система постоянно менялась, расширялась, модифицировалась, и, наконец, в одну дивную летнюю пятницу перестала работать. Перестала она работать практически безо всякой на то причины. Единственное, что Вася сделал, так это вставил вывод дополнительного текстового сообщения на консоль оператора системы. Увидев, к каким жутким последствиям привела, эта, казалось бы, безобидная операция, Вася тут же убрал вывод сообщения, но система от этого не заработала. Вася не верил в чудеса и знал, что если программа не идет, значит в ней ошибка. Однако, поиски ошибки были тщетны. Вася просидел целую неделю в бесплодных поисках, да так ничего и не нашел. Количество связей в его программе было так велико, что даже разум, натренированный постоянным написанием программ, играми в Героев меча и магии, Warcraft, Starcraft и, конечно, Quake, не был в состоянии справится с поставленной задачей. Как раз во время игры в Quake, когда получивший изрядную порцию заряда монстр корчился в предсмертных судорогах, Васе пришла блестящая идея, нарисовать взаимодействия внутри своей распределенной системы, в виде объектов и сообщений которыми объекты обстреливаются, то есть обмениваются. Собравшись с силами, Вася нарисовал взаимодействие между четырьмя объектами. Получилось у него что-то похожее на такой рисунок, с той разницей, что вместо букв a, b, с, d были указаны реальные объекты васиной системы, а вместо аббревиатур m1, m2, m3 и т.д. - аббревиатура реальных сообщений.

Голова у Васи к этому моменту шла кругом, и чем дальше он продвигался, тем сильнее отчаяние охватывало его. Объектов в его системе было не меряно, и процесс описания взаимодействий между ними становился все запутаннее. Осознав свою беспомощность, Вася отказался от идеи. Однако, он был настоящим программистом, а настоящий программист столкнувшись с не решаемой задачей не может быть в депрессии долго, ибо процесс поиска решения есть неотъемлемая часть его разума.

Оперативной памяти своей собственной головы Васе для анализа собственной системы не хватало. И, к утру, леча головную боль бутылкой пива, Вася пришел к единственно правильному выводу, что ее необходимо переделать (программу конечно, не голову ) так, что бы все связи были сосредоточены в одном месте (в правильном, а не в том о котором вы подумали). Осознав это, Вася в очередной раз скромно поразился глубине своего мышления. Он чувствовал, что близко подошел к чему-то очень важному, но что-то мешало придать идее, пришедшей ему в голову, осязаемую форму. В этот момент, он не то чтобы вспомнил о книге , подаренной ему на день рождения старым собутыльником, любителем Visual Basic, Мулькиным, она как-то сама собой оказалась в его руке. Называлась книга "Паттерны проектирования. Приемы объектно-ориентированного проектирования" и была написана аж четырьмя авторами, да еще с непонятными фамилиями. Подарил ее Мулькин со словами, -" на Ковыряло, учись, как програмить надо." "То же мне, Гуру Вижал Бесиковский," - подумал Вася. Однако, обижать старого товарища не хотел. Книге надо было найти применение. Вот и приспособил он ее вместо коврика для мышки. "Ну как, читаешь книгу-то ",- спросил его как-то Мулькин. "Дык. Это ж теперь моя настольная книга ",- честно ответил Вася. И вот теперь, держа книгу в руках, он невзначай открыл ее с середины и стал читать.

Сначала было не очень понятно. Но вскоре до Васи стало доходить, что таинственное слово паттерн означает некий шаблон, по которому создаются программы. По книге получалось, что без этих самых паттернов никаких хороших программ не фига не напишешь. "Во козлы, "- подумал Вася, -"цену себе набивают. И как это мы жили безо всяких паттернов ". По мере чтения недовольство книгой в Васе росло, и он уже хотел было опять приспособить ее под коврик для мыши, когда на 263 странице книги он задержался на описании паттерна с названием Посредник. Он прочитал описание несколько раз, и с каждым разом сердце его билось все сильней и сильней. Это было решение, которое он искал! Основная идея паттерна была в следующем. Предполагалось создание системы, ключевым элементом которой является объект Посредник, держащий всю информацию о связях между объектами системы в себе и перенаправляющий все запросы на объекты, которым эти сообщения предназначаются. В книге они назывались Коллегами. Коллеги в свою очередь не утруждают себя знаниями того, как идут взаимодействия внутри системы, и полагаются во всем на Посредника. Они общаются только с Посредником, а друг о друге ничего не знают. Да и зачем им знать, если есть тот, кто за это отвечает. "Наука!" - подумал Вася и воодушевленный новой идеей откупорил очередную бутылку пива. Выпив ее, он положил книгу рядом с собой и взялся ваять так называемую абстрактную модель системы в виде диаграммы UML. Вася не был силен в UML, волей случая, кстати, очень поучительного (как-нибудь я расскажу о нем отдельно), он получил общие представления, о том, что это такое. Работать таким образом было для него необычно, но он старался рассуждать оперируя понятиями, используемыми в книге.

- Итак, - думал Вася, - в принципе оба участника паттерна, а именно: Посредник и Коллега - должны выполнять практически одни и те же действия.

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


Как видно из диаграммы, интерфейсы имеют много общих методов:
  • putMessage добавляет сообщение в очередь сообщений,
  • getMessage получает сообщение из очереди сообщений,
  • sendMessage отправляет сообщение, и, наконец,
  • processMessage метод, который производит обработку сообщений.
Кроме этих методов в интерфейс Посредника Вася добавил методы для работы со списком Коллег, подключенных к Посреднику:
  • getColleagueList, позволяющий получить список всех Коллег связанных на текущий момент с Посредником,
  • addColleague, добавляющий нового Коллегу в список и
  • removeColleague удаляющий Коллегу из списка.

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

Не откладывая дело в долгий ящик, он сразу написал код нового класса, реализующего очередь объектов.


	package mediator;
	import java.util.*;
	public class MQueue {
	   private ArrayList list;
	   public MQueue() {
	list=new ArrayList();
	   }
	   public void push(Object o){
	list.add(o);
	   }
	   public Object pop(){
	if ((list!=null)&&(list.size()>0)){
	   Object o = list.get(0);
	   list.remove(0);
	   return o;
	}
	return null;
	   }
	}
Все, что позволяет такая очередь, - это отправить объект в очередь и взять объект из очереди по принципу FIFO. Реализации конкретных классов Вася решил унаследовать от класса java.lang.Thread. Для Посредника у него получилось следующее.

Как видно из диаграммы, здесь добавился еще один метод в дополнение к методам интерфейса, - метод run, пришедший от класса Thread. Он же добавился и в реализации Коллеги.

Другое дополнение - объект notifier.Вася всегда пользуется такого рода объектом для синхронизации потоков. Сам по себе notifier - обычный экземпляр класса Object. Однако, даже обычный экземпляр класса Object имеет методы notify() и wait(), которые позволяют легко организовать согласованную работу объектов. Что бы уведомить объект о том, что передано новое сообщение, которое он должен обработать, вызывается notify()

	synchronized(notifier) {
		// Уведомление о полученном сообщении
		notifier.notify();
	}
При этом, что бы заставить объект ждать сообщения, в тело цикла потока добавляется следующий код.

	synchronized(notifier) {
		notifier.wait();
	}
Коллега привязывается к Посреднику при создании. При вызове конструктора посредника, последний в качестве параметра получает Посредника, к которому он привязывается.

   public Colleague(IMediator mediator)
В качестве сообщений, Вася использовал объекты класса Object. Закончив описание, Василий, как истинный Java программер, налил себе чашечку кофе.В процессе поглощения культового напитка Java программеров, Василий ощущал все больший прилив сил и острое желание быстрее взяться за написание кода. Залпом выпив последний глоток, Вася принялся за дело. Текст кода уже сформировался в его голове, и все, что ему оставалось - набирать его клавиатуре. Конструктор Коллеги получает в качестве параметра объект Посредника, к которому он привязан. Коллега хранит ссылку на своего посредника. Здесь же в конструкторе происходит инициализация очереди сообщений и происходит добавление нового Коллеги в список Коллег, привязанных к посреднику.

   public Colleague(IMediator mediator) {
super();
notifier= new Object();
mQueue=new MQueue();
this.theMediator=mediator;
this.theMediator.addColleague(this);
   }
Методы для получения и отправки сообщений в качестве параметра имеют только само сообщение, поскольку отправитель и получатель заранее известны.

   public synchronized void putMessage(Object m) throws Exception {
mQueue.push(m);
synchronized(notifier) {
   notifier.notify();
}
   }
  public void sendMessage(Object m) throws Exception {
theMediator.putMessage(this,m);
  }
Метод run - бесконечный цикл, в теле которого по получении уведомления о пришедшем сообщении вызывается метод обработки сообщений processMessage.

  public void run() {
     try {
  while(true) {
     Object m;
     while((m=getMessage())!=null){
   processMessage(m);
     }
     synchronized(notifier) {
  notifier.wait();
     }
  }
     }catch(InterruptedException e){
     }catch(Exception e){
  e.printStackTrace();
     }finally{
  this.theMediator.removeColleague(this);
     }
  }
Для Посредника, код отличался несильно, хотя конечно есть некоторые различия, обусловленные разным назначением объектов. Так, например, конструктор Посредник не имеет никаких параметров.

  public Mediator() {
    super();
    notifier=new Object();
    mQueue=new MQueue();
    colleagueList=new ArrayList();
  }
С другой стороны методы отправки и передачи сообщений имеют дополнительный параметр -Коллегу, которому отправляют сообщение.

  public void sendMessage(IColleague col,Object m) throws Exception {
     col.putMessage(m);
  }
  public synchronized void putMessage(IColleague col,Object m) throws Exception {
     Object[] ma = {col,m};
     mQueue.push(ma);
     synchronized(notifier) {
  notifier.notify();
     }
  }
Объект, хранящийся в очереди сообщений Посредника, представляет собой массив, состоящий из двух элементов типа Object: объект отправитель и само сообщение.

  public synchronized Object[] getMessage() throws Exception {
     return (Object[])mQueue.pop();
  }
Метод run Посредника при этом выглядит так.

  public void run() {
     try {
  while(true){
     Object m;
     while((m=getMessage())!=null) {
  Object ma[] = (Object[])m;
  processMessage((IColleague)ma[0],ma[1]);
     }
     synchronized(notifier)
     {  notifier.wait(); }
  }
     }
     catch(InterruptedException e) {
     }
     catch(Exception e) {
  e.printStackTrace();
     }
  }
Как видно, его отличия от аналогичного метода Коллеги обусловлены необходимостью обработки информации об объекте отправителе.

В итоге у Васи остался только один пустой метод processMessage, который должен быть специфичным для каждой реализации. Гордый результатом своей работы, Василий, переписал диаграмму классов с точной сигнатурой методов.

Еще раз любовно взглянув на результаты своего труда, Вася пошел к холодильнику за очередной бутылкой пива. Хотя все было сделано, он еще не был до конца уверен, что механизм заработает. Чтобы убедиться в его работоспособности, он буквально на коленке слепил небольшую системку обмена сообщениями. За основу своего теста он взял схему взаимодействия между четырьмя объектами своей же системы, которую он нарисовал в самом начале. С использованием нового паттерна, схема несколько поменяла свой вид, к ней и добавился новый объект-посредник - e. Но, даже с дополнительным объектом, схема явно упростилась.

Код этого примера Вася любезно отправил мне по e-mail.
example.zip
А Васю ожидало самое трудное. Ему пора было браться за переделку своей банковской программы. В течение недели от него не было никаких известий. Как он рассказывал потом, эти дни прошли в почти механической работе. Вася брал классы объектов своей системы и переписывал, или просто наследуя их от класса Colleague, или, когда это было невозможно, реализуя интерфейс IColleague. Он переносил всю обработку получаемых объектом сообщений в метод processMessage, изменяемого класса и в аналогичный метод класса Посредник, создаваемого им по мере внесения изменений. К концу недели система Васи Ковырялкина начала работать. Причем скорость ее работы стала немного выше, чем была до всех злоключений. По Васиному предположению, произошло это по следующей причине. До смены паттерна, каждый объект, так, или иначе, реализовывал механизм приема сообщений из разных источников. Это требовало дополнительной обработки и анализа. Теперь, за все отвечал один объект, благодаря чему, все остальные объекты системы стали более легкими, и из них была удалена некоторая часть кода, ставшая ненужной.

Все это Вася и поведал мне за бутылкой коньяка. Он даже подарил мне код своего паттерна и сказал, что я могу с ним делать все что хочу. Так что, если вам надо, можете взять его здесь:
mediator.jar

Честно говоря, мне он особо не нужен. В своих программах я для тех же целей использую механизм Listener-ов. Я, кстати, спросил Васю, почему он сам им не воспользовался. Вася улыбнулся и сочувственно посмотрел на меня как на безнадежного больного.
- Друг мой, - сказал он, слегка заплетающимся языком, - ваши листинеры работают с единой очередью сообщений, а у меня у каждого объекта своя очередь и события обрабатываются не последовательно, а палларельно. Последнее слово ему так и не удалось выговорить. Что ж, может он и прав. Я не слишком сведущ в подобных вопросах, поэтому не спорил с ним.

P.S. Чуть не забыл самое главное. С тех самых пор книгу по паттернам Вася из под мышки убрал, отвел ей место на книжной полке и даже обернул. Говорят еще, что он стал ярым поборником использования паттернов проектирования.

Благодарности

Автор благодарит:

  • Василия К. за предоставление материалов для данной статьи
  • коллег по работе за содействие
  • особую благодарность автор выражает Андрею Штельмаху. Без его ценных замечаний ничего бы не получилось.

Ресурсы

  • Книга подаренная Васе. Приемы объектно-ориентированного проектирования. Паттерны проектирования ,Э.Гамма, Р.Хелм, Р.Джонсон, Дж.Влиссидес. (Питер, 2001; ISBN:5272003551)
  • Та же книга в оригинале. Design Patterns: Elements of Reusable Object-Oriented Software, Erich Gamma et al. (Addison-Wesley, 1995; ISBN: 0201633612)

    а также


  • Object Oriented Analysis and Design with Applications, Grady Booch, Rational, California, Addison-Wesley Publishing Company, 1994.
  • Объектно-ориентированный анализ и проектирование с примерами приложений на С++, Гради Буч. Второе изд.,2000, Binom.
  • OMG Unified Modelling Language Specification



Автор: Dmitri Zatselyapin,
Volgograd 2002


Warning: mysql_connect() [function.mysql-connect]: Can't connect to local MySQL server through socket '/tmp/mysql.sock' (2) in /pub/home/javaport/javaportal/books/show2b.php on line 11

Warning: mysql_db_query() [function.mysql-db-query]: Can't connect to local MySQL server through socket '/tmp/mysql.sock' (2) in /pub/home/javaport/javaportal/books/show2b.php on line 19

Warning: mysql_db_query() [function.mysql-db-query]: A link to the server could not be established in /pub/home/javaport/javaportal/books/show2b.php on line 19

Warning: mysql_fetch_array(): supplied argument is not a valid MySQL result resource in /pub/home/javaport/javaportal/books/show2b.php on line 30
Узнай о чем ты на самом деле сейчас думаешь тут.


[an error occurred while processing this directive]



Warning: mysql_connect() [function.mysql-connect]: Can't connect to local MySQL server through socket '/tmp/mysql.sock' (2) in /pub/home/javaport/javaportal/news/worldnews.php on line 91

Warning: mysql_db_query() [function.mysql-db-query]: Can't connect to local MySQL server through socket '/tmp/mysql.sock' (2) in /pub/home/javaport/javaportal/news/worldnews.php on line 93

Warning: mysql_db_query() [function.mysql-db-query]: A link to the server could not be established in /pub/home/javaport/javaportal/news/worldnews.php on line 93

Warning: mysql_fetch_array(): supplied argument is not a valid MySQL result resource in /pub/home/javaport/javaportal/news/worldnews.php on line 95