Показаны сообщения с ярлыком патерны. Показать все сообщения
Показаны сообщения с ярлыком патерны. Показать все сообщения

воскресенье, 7 февраля 2021 г.

Мнение о книге "Распределенные системы. Паттерны проектирования"

 

Книга совсем небольшая, порядка 220 страниц. Мне понравилась структура. Есть три части, в каждой дается вводная часть, описывающая группу паттернов, а затем главы посвящены отдельным паттернам. Каждый паттерн рассматривается теоретически, описываются случаи когда он может быть применен и, самое главное, приводится пример как его реализовать (докер, кубер и kubectl).

Выбор паттернов, как по мне, достаточно специфичен. Здесь нет той же Саги, зато есть очень много советов, как сделать контейнеры реально переиспользуемыми. Одноузловые паттерны это вообще тема, очень мало кто знает про них в достаточном объеме. Тот же прицеп еще на слуху, а амбасадор, уже вызовет вопрос, а что это такое :)

Читать ли книгу? Как по мне, так полезность очень высока. Даже если вы все это уже знаете, будет полезно посмотреть с другой точки зрения, да и конкретные приемы развертывания попадаются достаточно интересными. Единственно, я не могу рекомендовать эту книжку совсем уж новичкам. Скорее она ориентированна на уровень, когда человек уже набил некоторое количество шишек, а тут ему подсказка, как их не набивать в следующий раз.

воскресенье, 29 сентября 2013 г.

Показ дочерних View в рамках патерна MVVM

Время от времени, участвую в обсуждениях, как правильно в рамках паттерна MVVM показывать дополнительные (дочерние View) в отдельных окнах. Т.е. когда смотришь на диаграмму иллюстрирующую паттерн, все ясно: View знает про ViewModel только на уровне имен свойств указанных в биндинге, ViewModel вообще ничего не знает про View. Но вот, пользователь нажимает на кнопку и нам надо создать новые View и ViewModel для того, чтобы показать это все в отдельном окне... Что делать? Вот об этом сегодня и пойдет речь.

четверг, 18 апреля 2013 г.

Выделить элемент в дереве или развернуть его из кода

Сегодня статья будет не очень большая, но охватывать будет много всего.
1. Как из кода выбирать элемент в дереве (для тех кто не в курсе, у TreeView свойство SelectedItem доступно только для чтения).
2. Как получить информацию о том, что в некоторой ноде происходит сворачивание и разворачивание.
3. Посмотрим на паттерны "обертка" (декоратор) и на MVVM (что это за паттерн, можно почитать здесь).
4. Применение "ленивой" загрузки.
Интересно? Тогда начинаем.

воскресенье, 3 марта 2013 г.

Упрощения жизни в примере показа всплывающих сообщений


В прошлой статье, был пример разработки метода, позволяющего показать информационное окно с картинкой. На мой взгляд, единственным недостатком приведенного метода, является сложность его вызова. Действительно, чтобы  показать достаточно простое окно, нам пришлось создавать экземпляры класса PopubButton, задавать имена и т.д. давайте сегодня посмотрим пример паттерна Фасад, который позволит упростить жизнь тем, кто решит воспользоваться этим классом.

среда, 9 января 2013 г.

четверг, 25 октября 2012 г.

Обертка для привязки команд к произвольным событиям

При использовании паттерна MVVM часто возникает желание вызвать команду на событие, которое получает параметры необходимые в методе выполняемом командой. И если просто вызов команды сделать достаточно легко, я сегодня бы хотел продемонстрировать пример именно с передаче параметров. Собственно, как достаточно часто в последнее время, на написание этого топика меня подтолкнул вот этот вопрос на форумах MSDN.

среда, 16 мая 2012 г.

Отображение странных иерархий в TreeView

Данный пример написан как ответ на вопрос заданный на формуме MSDN.
Под катом показано, как при помощи паттерна "декоратор" отобразить в виде дерева то, что первоначально назвать деревом можно с очень большой натяжкой.

вторник, 23 июня 2009 г.

Патерн "Фабрика объектов" на примере "Фабрики форм"

При работе над проектом "Электронный университет" давно используем "Фабрику форм", но там задачи спецефические, да и времени небыло, поэтому документация в достаточно разрозненном виде, да и отягчена работой с AzMan-ом, Web-сервисами и прочими вещами. Поэтому в данной статье попробую расказать основные идеи данного патерна. Итак, начнем.
Задача:
Необходимо реализвать приложение загружающее формы в соответствии с правами пользователя. Или, говоря простым языком, каждый пользователь после аутентификации должен получать главное меню ориентированное под его задачи. Ингода формы связанные с пунктами меню должны быть сразу загружены.
Средства достижения:
1. Reflection - используется для динамического создания объектов
2. Интерфейc IFactoryForm - для того чтобы мы спросили у созданной формы, нужен ли ей пункт меню, а также получили возможность передавать форме команды из главного приложения, а также получать команды из формы, для передачи в другие формы (во завернул) .
3. Enum содержащий все команды - для организации взаимодействия форм между собой в процессе работы.
4. Интерфейс IParam для передачи параметров команды. Кстати этот интерфейс ничего не содержит и создан только для того, чтобы при передаче параметорв команды разработчик работающий с фабрикой понимал, что он передает не просто объект, а объект параметр команды.
5. Ну и собственно сама фабрика - часть кода выполняющая работу с загружаемымми формами.

Давайте начнем в таком порядке и обсуждать.
1. Reflection - написано очень много всего хорошего, поэтому здесь я останавливаться не буду. Кто с Reflection не работал может посмотреть в msdn.
2. Как я уже сказал интерфейс используется для взаимодействия фабрики с формой. Для ростоты использования реализовывать лучше в отдельной dll. В самом простом случае должен иметь вид:

Код интерфейса будет иметь вид:
  public interface IFactoryForm
  {
    event CommandHandler NewCommand;

    /// <summary>
    /// Возвращает с каким пунктом меню необходимо связать форму.
    /// </summary>
    /// <returns>
    /// Путь до пункта меню добавляется форма. Путь имеет вид:
    /// Item-&gt;Item-&gt;Item
    /// Если строка пустая, то пункт меню создавать не надо и форма из пункта меню не вызывается
    /// </returns>
    string GetMenuItem();

    /// <summary>
    /// Вызывается при клике пользователя на пункте меню связанном с формой
    /// </summary>
    void Activate(object sender, EventArgs e);

    /// <summary>
    /// Вызывается главной формой приложения для передачи команд в форму
    /// </summary>
    void DoCommand(Commands p_command, IParam p_param);
  }


* This source code was highlighted with Source Code Highlighter.


3. Перечисление Commands (см. предыдущий рисунок) будет содержать команды которыми обмениваются формы в процессе работы приложения, для начала это всего одна команда которая нам нужна для показа тестовой формы в нашем приложении.
4. Опять же, как видно из рисунка IParam ничего не содержит ;)
5. Ну а теперь перейдем к фабрике.
Фабрика будет реализованна в виде пары методов и вспомогательного события.
Итак первый метод отвечает за создание форм. В нашем проекте идентификация пользователей идет при помощи штрих-кодов с бейджиков. Поэтому главная форма приложения после запуска имеет вид:

Для получения списка сборок и форм для загрузки используется типизированный DataSet содержащий табличку вида:

Код метода:
/// <summary>
    /// Список форм созданных при помощи фабрики
    /// </summary>
    List<IFactoryForm> formsFromFactory;

    private void CreateForms()
    {
      // Показываем форму идентификации
      FrmLogin login = new FrmLogin();
      login.StartPosition = FormStartPosition.CenterParent;
      if (login.ShowDialog() == DialogResult.OK)
      {
        // если штрих-корд считан, то получаем перечень форм для загрузки.
        // Реализация метода может быть любая. Мы, например, берем из базы данных
        FactoryFormData.FormsDataTable forms = GetFormsForPerson(new Guid(login.tbPersonId.Text));
        // Строка для сбора сообщений об ошибках работы
        StringBuilder errors = new StringBuilder();
        // Пробегаем по всем формам и загружаем их в приложение
        foreach (FactoryFormData.FormsRow item in forms)
        {
          // Получаем и загружаем сборку
          Assembly dll = null;
          try
          {
            dll = Assembly.LoadFile(Application.StartupPath + '\\' + item.Assembly);
          }
          catch{}
          if (dll != null)
          {
            // Сборка загружена. загружаем форму
            Type currentFormClass = dll.GetType(item.FormFullName);
            if (currentFormClass != null)
            {
              // Создаем объект и приводим его к IFactoryForm
              ConstructorInfo ci = currentFormClass.GetConstructor(new Type[] { });
              IFactoryForm currentForm = ci.Invoke(new object[] { }) as IFactoryForm;
              formsFromFactory.Add(currentForm);
              ((Form)currentForm).MdiParent = this;
              if (currentForm != null)
              {
                // Собственно форма в памяти, осталось только создать меню и привязать форму к нему
                string menuItemText = currentForm.GetMenuItem();
                switch (menuItemText)
                {
                  case "":
                    // Собственно делать ничего не нужно
                    break;
                  case "_show_":
                    // Форме пункт меню не нужен, форма требует немедленного показа
                    ((Form)currentForm).Show();
                    break;
                  default:
                    // Создаем пункт меню
                    ToolStripMenuItem mi = null;
                    string[] path = menuItemText.Split(new string[] { "->" }, StringSplitOptions.RemoveEmptyEntries);
                    foreach (string currentMenuItemText in path)
                    {
                      ToolStripItemCollection itemsForCheck = null;
                      if (mi == null)
                      {
                        // если мы на вершине иерархии, то ищем пункт меню в главном меню
                        itemsForCheck = msMain.Items;
                      }
                      else
                      {
                        // а если нет, то в подпунктах текущего пункта
                        itemsForCheck = mi.DropDownItems;
                      }
                      ToolStripMenuItem childItem = itemsForCheck.Cast<ToolStripMenuItem>().FirstOrDefault(x => x.Text == currentMenuItemText);
                      if (childItem == null)
                      {
                        // элемент с таким имененм не найден, содаем
                        childItem = new ToolStripMenuItem(currentMenuItemText);
                        if (mi == null)
                        {
                          msMain.Items.Insert(1, childItem);
                        }
                        else
                        {
                          mi.DropDownItems.Add(childItem);
                        }
                        mi = childItem;
                      }
                      mi = childItem;
                    }
                    // Итак сейчас в mi должна быть ссылка на пункт меню к которому привязана форма
                    // Подписываем форму на клик по этому пункту меню
                    mi.Click += currentForm.Activate;
                    break;
                }
              }
              else
              {
                errors.Append(string.Format("Ошибка загрузки формы: {0}. Форма не поддерживает IFactoryForm.\n", item.FormFullName));
              }
            }
            else
            {
              errors.Append(string.Format("Ошибка загрузки Формы: {0}. Форма не найдена в сборке.\n", item.FormFullName));
            }
          }
          else
          {
            errors.Append(string.Format("Ошибка загрузки бибилотеки: {0}. Бибилотека не найдена.\n", item.Assembly));
          }
          if (errors.Length != 0)
          {
            MessageBox.Show(errors.ToString());
          }
        }
      }
    }


* This source code was highlighted with Source Code Highlighter.


Реализация интерфейса у тестовой формы (конечно размещеной в другой сборке, иначе фабрика теряет смысл):
  public partial class TestForm : Form, IFactoryForm
  {
    public TestForm()
    {
      InitializeComponent();
    }

    #region Члены IFactoryForm

    public event CommandHandler NewCommand;

    public string GetMenuItem()
    {
      return "Тестовые формы->Первая тестовая";
    }

    public void Activate(object sender, EventArgs e)
    {
      DoCommand(Commands.ShowFirstForm, null);
    }

    public void DoCommand(Commands p_command, IParam p_param)
    {
      switch (p_command)
      {
        case Commands.ShowFirstForm:
          this.Show();
          break;
      }
    }

    #endregion
  }


* This source code was highlighted with Source Code Highlighter.


Вуаля, все заработало!
Теперь задание на дом, придумать как при помощи имеющегося события NewCommand, метода DoCommand и списка List formsFromFactory реализовать взаимодействие порожденных фабрикой форм между собой, если известно что ссылок друг на друга они не имеют.