Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:

Diploma_All

.pdf
Скачиваний:
20
Добавлен:
05.06.2015
Размер:
1.37 Mб
Скачать

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

Объект «элемент SPICE»

Классом, отражающим свойства SPICE-элемента, является класс SpiceElement. Свойство Name хранит информацию о полном имени SPICE-эле- мента, свойство ModelName отвечает за имя модели элемента, а в массивах строк Pins и Parameters хранятся имена контактов элемента (nodes) и параметры соответственно.

Объект «узел»

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

сок сыновей ChildNodes и полезную информацию об этом узле: значение узла

— ссылку на объект типа SpiceElement, имя узла Name, уровень узла Level,

полный путь этого узла FullPath. Также объект содержит все необходимые методы (функции) для работы со списком сыновей — добавления, удаления, поиску по имени. Также класс Node определяет константу, устанавливающую сим-

вол-разделитель для полного пути к листу иерархии. По умолчанию, это «\». Этот символ используется в случаях разбиения полного пути на составные части а также объектом WinForms TreeView для конструирования своего полного пути к узлам дерева (на самом деле полный путь в исходной иерархии и иерархии, построенной в TreeView будут идентичными, что позволит производить поиск как в первом дереве, так и во втором).

Объект «дерево»

Как было отмечено в 2.2.3, дерево в случае представления списочными структурами представляется указателем на корень. В нашем случае — это ссылка на корень (самый старший узел) дерева.

Класс Tree наследуется из класса Node, поскольку корень — это тот же узел дерева, но без входящих в него дуг. Поэтому в этом классе переопределено свой-

21

ство Parent, которое теперь возвращает нулевую ссылку (null). За счет этого рекурсивное свойство Level будет возвращать 0, что будет являться условием выход из рекурсии:

public int Level

{

get

{

if (_parent == null)

{

return 0;

}

return (_parent.Level + 1);

}

}

Также объект Tree определяет свойство Nodes, которое является хэш-табли- цей, содержащей список пар «ключ — значение», где ключом является строка полного пути к узлу дерева, а значением — ссылка на этот узел. Хэш-таблица (или словарь, как она называется в библиотеке .NET 2.0) со списком узлов была введена для быстрого поиска узлов по их полному пути. Использование хэш-та- блиц эффективно с точки зрения скорости поиска так и с точки зрения использования: для обращения к узлу с известным полным путем до него достаточно написать Nodes[fullPath]. Узлы в эту справочную таблицу добавляются автома-

тически при добавлении нового сына к узлу.

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

22

Алгоритм построения иерархии

Начало

Массив SPICEэлементов

Текущее дерево = NULL

Имя элемента

Разбить имя

Имена блоков

Алг. 2

Создать первую ветвь (новый ствол)

Создание ветвей для всех элементов массива, начиная с 1

Имя элемента

Разбить имя

Имена блоков

Найти имя первого блока в корнях

Алг. 2

 

Корень

 

Нет

 

Создать

 

 

найден?

 

 

 

 

 

новый ствол

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

Да

 

 

Алг. 3

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

Создать ветвь

 

 

 

 

 

 

 

 

из имен блоков

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

Создание ветвей

Конец

Рисунок 2.4. Алгоритм построения иерархии

23

Алгоритм построения «ствола» дерева

Начало

Имена узлов

Текущий узел = корень

Инициализация корня

Добавить корень в словарь узлов

Добавление сыновей для всех имен узлов, начиная с 1

Последнее

Нет

Создать узел

 

 

 

имя блока?

 

 

 

с пустым значением

 

 

 

 

 

Да

Создать узел со значением = SpiceElement

Узел

Добавить узел как сын к текущему узлу

Добавить узел в словарь узлов

Текущий узел = сын

Добавление сыновей

Конец

Рисунок 2.5. Алгоритм 2: построение «ствола» дерева

24

Алгоритм создания ветви из имен блоков

Начало

Имена узлов

Добавление узлов для всех имен узлов, начиная с 1

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

Искать узел по имени в

 

 

 

 

 

 

сыновьях текущего узла

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

Да

 

 

 

 

 

 

 

 

 

Узел найден?

 

Текущий узел = узел

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

Нет

 

 

 

Нет

 

 

 

 

 

 

 

 

 

 

 

Последнее

Создать узел

 

 

 

 

имя блока?

 

 

 

 

с пустым значением

 

 

 

 

 

 

 

 

 

 

Да

Создать узел со значением = SpiceElement

Узел

Добавить узел как сын к текущему узлу текущего дерева

Добавить узел в словарь узлов текущего дерева

Текущий узел = сын

Оставшиеся имена узлов

 

 

 

 

 

 

 

 

 

 

 

 

У каждого узла один

 

Достроить ветвь

 

 

 

 

 

сын (кроме листа)

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

Текущий узел = текущее дерево

Добавление узлов

Конец

Рисунок 2.6. Алгоритм 3: создание ветви из имен блоков

25

2.3.3 Представление иерархии в графическом виде

Паттерн «Model — View — Controller» (MVC)

В современном объектно-ориентированном программировании при проектировании систем с графическим интерфейсом пользователя (GUI — Graphics User Interface) архитектурой де-факто является архитектура, построенная по шаблону (паттерну) MVC (Модель — Представление — Контроллер).

Шаблон проектирования MVC предполагает разделение данных приложения, пользовательского интерфейса и управляющей логики на три отдельных компонента: модель, представление и контроллер. Модель — это объект приложения, а вид — экранное представление. Контроллер описывает, как интерфейс реагирует на управляющие воздействия пользователя. До появления схемы MVC эти объекты в пользовательских интерфейсах смешивались. MVC отделяет их друг от друга, за счет чего повышается гибкость и улучшаются возможности повторного использования.

MVC отделяет вид от модели, устанавливая между ними протокол взаимодействия «подписка/оповещение». Вид должен гарантировать, что внешнее представление отражает состояние модели. При каждом изменении внутренних данных модель оповещает все зависящие от нее виды, в результате чего вид обновляет себя. Такой подход позволяет присоединить к одной модели несколько видов, обеспечив тем самым различные представления. Можно создать новый вид, не переписывая модель.

MVC позволяет также изменять реакцию вида на действия пользователя. При этом визуальное представление остается прежним. Например, можно изменить реакцию на нажатие клавиши или использовать всплывающее меню вместо командных клавиш. MVC инкапсулирует механизм определения реакции в объекте Controller. Существует иерархия классов контроллеров, и это позволяет без труда создавать новый контроллер как вариант уже существующего.

Компонентный уровень MVC в языках программирования имеет ряд отступлений от оригинального MVC. Во-первых, отсутствует четкое разделение между представлением и контроллером. Во-вторых, в отличие от платформы Java, остальные реализации MVC не требуют выделения бизнес-логики приложения в отдельный компонент – модель.

26

Что касается использованной в разработке библиотеки .NET, то в классах Windows Forms (WinForms) задается только представление и контроллер. Класс, наследуемый от классов Form или Control, является представлением. Представление и контроллер компилируются в один класс. Контроллером являются выполняемые на уровне операционной системы генерация и транспорт событий, а также прием и перенаправление событий классами Form и Control в соответствующие обработчики, определенные разработчиком.

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

Реализация принципа MVC в программе построения иерархии

Вкачестве модели выступает объект «дерево», содержащий всю информацию об иерархии. Он абсолютно абстрагирован от представления.

Вкачестве представлений (view) выступают объект WinForms TreeView,

отражающий иерархию в древовидной форме, разработанный объект-менеджер Renderer, призванный отображать структуру блоков в виде вложенных геомет-

рических элементов, например, прямоугольников, и текстовое поле с описанием имеющихся элементов на языке SPICE.

Как уже было сказано выше, в классах WinForms представлениями являются классы, унаследованные от класса Control. Таковым является класс TreeView, объект типа Panel, на который осуществляется вывод иерархии блоков в геометрическом виде и текстовое поле типа TextBox. Класс Renderer является своего рода посредником между моделью и представлениями WinForms.

Функции контроллера полностью возложены на встроенную событийную модель WinForms — никаких собственных событий при работе программы не генерируется. Логика диспетчеризации действий, инициируемых пользователем, полностью сконцентрирована в обработчиках стандартных событий WinForms. Поскольку вся бизнес-логика выполняется в отведенных для этого классах — TreeBuilder, NetListAnalyzer и других, а обработчики событий лишь вызывают

27

необходимые методы из этих классов и содержат минимальное количество выполняемых действий, то выделение этих действий в отдельный класс нецелесообразно. Например, обработчик события «Paint» (возникает при команде элементу управления перерисовать свое содержимое) панели, на которую производится вывод иерархии блоков в геометрическом виде, содержит всего лишь одну инструкцию — команду менеджеру отображения «перерисовать все текущие элементы»:

private void pnlDraw_Paint(object sender, PaintEventArgs e)

{

Renderer.Instance.Render(e.Graphics);

}

В общем виде пользовательский интерфейс разработанной программы выглядит так, как показано на рисунке 2.7.

Рисунок 2.7. Пользовательский интерфейс программы

Геометрическое отображение иерархии блоков. Класс Renderer.

За геометрическое представление иерархии блоков SPICE-элементов отвечает класс Renderer, реализующий механизмы создания рисуемых объектов (так называемых глифов), отображения этих объектов, их подсветки и масштабирования. Также класс определяет методы для заполнения объекта класса TreeView готовыми деревьями, взятыми из модели.

28

Заполнение объекта TreeView узлами из модели не представило никакой сложности, потому что он предназначен для отображения ориентированных деревьев:

public void FillTreeView(TreeView treeView, Tree[] trees)

{

treeView.Nodes.Clear();

foreach (Tree tree in trees)

{

treeView.Nodes.Add(CreateTreeNode(tree));

}

for (int i = 0; i < trees.Length; i++)

{

AddChildren(trees[i], treeView.Nodes[i]);

}

}

Метод AddChildren(Node parentNode, TreeNode parentTreeNode)

реализован с помощью рекурсии. Условием выхода из рекурсии является отсутствие у листа сыновей:

private void AddChildren(Node parentNode, TreeNode parentTreeNode)

{

if (parentNode.HasChildren)

{

for (int i = 0; i < parentNode.ChildNodes.Count; i++)

{

parentTreeNode.Nodes.Add(CreateTreeNode(parentNode.

ChildNodes[i]));

AddChildren(parentNode.ChildNodes[i],

parentTreeNode.Nodes[i]);

}

}

}

29

На снимке экрана, представленном на рисунке 2.8, показано, как выглядит ориентированное дерево в представлении объекта TreeView:

Рисунок 2.8. Представление ордерева объектом

TreeView

Кроме того, узлы типа TreeNode, содержащиеся в этом объекте имеют свойство «FullPath», возвращающее полный путь к этому узлу из корня. Вы-

ставив объекту TreeView свойство PathSeparator, равное значению константы из объекта Node модели («\»), мы получаем полный путь к узлу из объекта TreeView точно таким же, как и путь, возвращаемый одноименным свойством FullPath объекта Node. Таким образом, свойство FullPath является ключом,

который однозначно определяет узел как в модели, так и во всех представлениях. Следует отдельно коснуться класса DrawnObject, который представляет собой глиф — рисуемый объект, отражающий один блок в иерархии. Класс содержит в качестве членов прямоугольник типа System.Drawing.Rectangle,

строковую переменную Name, отвечающую за имя объекта, переменную

NamePosition типа System.Drawing.Point, содержащую информацию о по-

зиции имени в соответствующем прямоугольнике, а так же строковое свойство Value — в нем хранится информация о соответствующем блоке иерархии в мо-

дели (полный путь к узлу, упоминавшийся выше «ключ»).

Также глиф позволяет определить то, как его рисовать. Это осуществляется через свойства Font, Pen и Brush, определяющие шрифт написания имени,

объект «перо», с помощью которого рисуется прямоугольник и объект «кисть», с использованием которого рисуется текст имени соответственно.

30

Соседние файлы в предмете [НЕСОРТИРОВАННОЕ]