Главная » C# » Реализация ядра приложения управления освещением в Visual C# (Sharp)

0

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

Далее приводится пример  реализации метода DimLights для плавного понижения уровня освещения С ПОМОЩЬЮ класса LightingController:

public class LightingController {

public void DimLights(object grouping, double level) {

}

}

Данный метод применяется таким образом: LightingController controller = new LightingController(); object grouping = null;

controller.DimLights(grouping, 0.50);

Код пользователя явно создает экземпляр класса LightingController и также явно использует метод DimLights (). Но явное использование класса не позволяет измять код контроллера, не затрагивая при этом пользователей, т. к. существует теая связь между пользовательским кодом и ядром. Вот почему все это время я пртранно доказывал важность использования интерфейсов, концепций и реализаций. Но в данной ситуации с контроллером абсолютно ничего из этой теории не примяется на практике.

Причина для использования класса вытекает из примера в предыдущей главе и интерфейсов ITaxDeduction и ITaxIncome. В данном примере для каждого иерфейса была только одна реализация, и ни одну из этих реализаций не намечось изменять. Как было объяснено в предыдущей главе, интерфейсы можно бо бы представить в виде классов. Эта же логика применима и к контроллеру. Контроллер, в аспекте сигнатуры методов и свойств, не изменится особо и будет реализован только в одном экземпляре. Таким образом, интерфейс не является обязательным, и использование класса является вполне приемлемым подходом, который и применяется в данной главе. Но в некоторых ситуациях может быть желательным реализовать ядро в виде интерфейса, а не класса. Этот аспект раматривается   в  разд.   "Определение  ядра  в  виде   интерфейса,   а  не  класса"  далее в  этой  главе.

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

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

Сохранение коллекции с помощью связанного списка

В примерах в предыдущих главах коллекции объектов создавались с помощью маива, как показано в следующем примере:

МуТуреП array = new MyType[10]; array[0] = new MyType(); array[2]   =  new MyType();

В этом коде создается массив, который может содержать самое большее 10 элемеов (мутуре [ ю ]). Если нам потребуется сохранить большее число элементов, скем 20, то нужно будет создать  новый массив требуемого размера и скопировать содержимое старого массива в новый. Одной из особенностей массива является то, что значения его элементам присваиваются не обязательно в последовательном пядке. В данном примере значения были присвоены первому и третьему элементам массива, оставив нулевым значение второго элемента. Таким  образом,  код,  котый будет в цикле обрабатывать элементы массива, должен проверять их на нулое значение. Структура, созданная предыдущим кодом, показана на рис. 8.2.

Рис. 8.2. Массив ссылочных элементов

На рис. 8.2 показан очень важный аспект ссылочных типов: элемент массива сержит ссылку на объект, а не сам объект. Если бы массив был обычного типа, тда каждый из его элементов содержал бы весь объект, а не только ссылку на него.

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

class MyTypeArray { public MyType Elementl; public MyType Element2;

}

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

В связанном списке отдельные объекты связаны друг с другом и указывают на дрой близлежащий элемент. Элемент двунаправленного связанного списка содержит ссылки только на два других объекта: следующий и предыдущий. (Элемент однаправленного связанного списка указывает только на один другой объект — на следующий.)

В двунаправленном связанном списке тип всегда будет иметь два члена данных: Next и prev. Каждый из этих членов данных указывает на другой элемент списка (рис. 8.3). Для последовательной обработки элементов списка мы начинаем с левой или с правой стороны и переходим к члену данных Next или prev, соответственно. Далее приводится пример кода для такой обработки:

МуТуре curr = GetHeadOfList() ; while (curr != null) {

// Выполняется какая-либо операция с curr. curr = curr.Next;

}

Рис.  8.3.  Структура  двунаправленного  связанного  списка

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

ПРИМЕЧАНИЕ

В большинстве случаев используется класс List, но также существует класс LinkedList. Дополнительную    информацию    О классе    System.Collection.Generic .LinkedList дл я версии .NET можно найти в документации  MSDN  3.0.

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

Создание связанного списка

Можно создать отдельный код для каждого из членов данных Next и prev двунравленного списка, но  более  эффективным подходом будет определить базовый класс. Начальная структура класса BaseLinkedList (определяемого в библиотеке LibLightingSystem) ВЫГЛЯДИТ ТЭКИМ образом :

public abstract class BaseLinkedList { private BaseLinkedList _next; private BaseLinkedList _prev;

public BaseLinkedList Next { get {

return _next;

}

}

public BaseLinkedList Prev { get {

return _prev;

}

}

}

Базовый класс BaseLinkedList объявляется абстрактным, чтобы указать, что иользование данного класса подразумевает создание производных от него классов. Члены данных Prev и Next являются свойствами, которые могут только считывать значения частных членов данных _prev и _next.

Добавление и удаление элементов связанных списков

Написание кода для вставки и удаления объектов связанного списка требует осой внимательности, чтобы выполняемые в  нем  операции  не  повредили  список. Эту задачу не следует делегировать пользователям связанного списка, т. к. они мут непреднамеренно внести в него искажения. Далее приводится код для вставки и удаления объектов связанного списка. Данный код является частью класса BaseLinkedList.

public void Insert(BaseLinkedList item) { item._next = _next;

item._prev = this;

if (_next != null) {

_next._prev = item;

}

_next = item;

}

public void Removed {

9 Зак. 555

if (_next != null) {

_next._prev = _prev;

}

if (_prev != null) {

_prev._next = _next;

}

_next = null;

_prev = null;

}

Метод insert () предполагает, что объекты вставляются в список, содержащий хя бы один элемент. Для применения метода insert () требуется, по крайней мере, следующий код:

BaseLinkedList singleElement = GetHeadOfList(); BaseLinkedList anotherElement = CreateListElement(); singleElement.Insert(anotherElement);

При добавлении нового элемента первым делом членам данных _next и _prev обкта (т. е. элемента), добавляемого в список, присваиваются значения.

ПРИМЕЧАНИЕ

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

После того как членам данных элемента были присвоены значения, элемент вставляется в список. Для этого перенаправляется свойство _prev следующего элемента (если его значение не равно null), после чего свойству _next текущего элемента присваивается вставляемый объект.

Метод Remove () выполняет действия, обратные действиям метода insert (). Снала перенаправляются свойства _next и _prev предыдущего и следующего объеов (если их значения не равны null). После этого членам данных _next и _prev удаляемого элемента присваивается значение null.

ПРИМЕЧАНИЕ

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

Источник: Гросс  К. С# 2008:  Пер. с англ. — СПб.:  БХВ-Петербург, 2009. — 576 е.:  ил. — (Самоучитель)

По теме:

  • Комментарии