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


Мы поможем в написании ваших работ!



ЗНАЕТЕ ЛИ ВЫ?

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



 

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

 

Для создания модели такой структуры требуется добавить в проект модуль класса, в котором объявить пространство имен LinkedListLibrary:

 

using System;

using System.IO;

 

namespace LinkedListLibrary

{

public struct PData

{

   public long TabNom;

   public string Surname;

   public string Firstname;

   public string Lastname;

   public byte Age;

   public string Sex;

   public string Adress;

}

} // Конец пространства имен LinkedListLibrary

 

Для манипулирования данными списка в LinkedListLibrary объявлена статическая структура PData, включающая в себя семь полей списка. В дальнейшем при проведении каких-либо манипуляций с данными списка потребуется ссылаться на тип данных PData.

Каждый узел в списке приставляется объектом самоотносимого класса ListNode:

 

// Класс, представляющий один узел списка

class ListNode

{

   private PData data;

   private ListNode next;

 

// Конструктор для создания узла со ссылкой на dataValue - последний // узел в списке

   public ListNode(PData dataValue)

      : this(dataValue, null)

   { }

 

// Конструктор для создания узла со ссылкой на dataValue и на

// следующий узел в списке

   public ListNode(PData dataValue, ListNode nextNode)

   {

       data = dataValue;

       next = nextNode;

   }

 

   // свойство Next

   public ListNode Next

    {

       get

       {

           return next;

       }

       set

       {

           next = value;

       }

   }

 

   // свойство Data

   public PData Data

   {

       get

       {

           return data;

       }

       set

       {

           data = value;

       }

   }

} // Конец класса ListNode

 

Класс ListNode состоит из двух переменных элементов — data и next. Элемент data представляет собой структуру PData. В элементе next сохраняется ссылка на следующий объект класса ListNode в связанном списке.

Для организации собственно списка и манипуляций с ним используется объект класса List. В каждом объекте List инкапсулирован связанный список объектов ListNode. Класс List (см. листинг ниже) осуществляет доступ к переменным элемента ListNode посредством свойств Data и Next соответственно.

Класс List содержит элементы типа private — firstNode (ссылка на первый объект ListNode в классе List) и lastNode (ссылка на последний объект ListNode в классе List). Конструкторы класса инициализируют обе ссылки на null. Методы insertAtFront, insertAtBack, RemoveFromFront, RemoveFromBack являются основными методами класса List. В каждом из этих методов присутствует блок lock для обеспечения многопоточной безопасности объектов класса List при использовании в многопоточной программе. Если один поток модифицирует содержимое объекта класса List, тогда ни один другой поток не может одновременно модифицировать этот же объект. Метод isEmpty является предикатным методом, определяющим, пуст список или нет (т. е. ссылка на первый узел списка имеет значение null). Предикатные методы, как правило, проверяют условие, но не модифицируют объект, для которого они вызваны. Если список пуст, тогда метод isEmpty возвращает значение true; в противном случае возвращается значение false. Метод Print отображает содержимое списка. Метод Printf выводит содержимое списка в файл.

Рассмотрим подробно основные методы класса List.

Метод InsertAtFront размещает новый узел в начале списка. Данный метод состоит из трех шагов (показаны на рис. 6):

1. Вызов метода isEmpty для определения, пустой список или нет.

2. Если список пуст, задание элементов f irstNode и lastNode для обращения к новому объекту ListNode, инициализированному с insertltem. Конструктор ListNode(data) вызывает в строках 23—27 конструктор ListNode(data, next) для задания экземпляра переменной data для ссылки на объект, переданный в качестве первого аргумента, и для задания ссылке next значения null.

3. Если список не пустой, тогда новый узел "вплетается" в список заданием элемента firstNode для ссылки на новый объект класса ListNode, инициализированный с элементами insertltem и firstNode. При исполнении конструктора ListNode задается переменная экземпляра data для ссылки на объект PData, переданный в качестве первого аргумента, и выполняется вставка заданием ссылки next объекту ListNode, переданному в качестве второго аргумента.

 

На рисунке 6, а показан список и новый узел во время операции InsertAtFront до ввода нового узла в список. Пунктирные стрелки на рисунке 6, б иллюстрируют шаг 3 операции InsertAtFront, превращающий узел, содержащий 12, в первый узел нового списка.

               

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

 

Рисунок 6. Графическое представление операции InsertAtFront

 

Метод insertAtBack размещает новый узел в конец списка. Данный метод состоит из трех шагов (показаны на рисунке 7):

  1. Вызов метода isEmpty для определения, пустой список или нет.
  2. Если список пуст, задание элементов firstNode и lastNode для обращения к новому объекту ListNode, инициализированному insertItem. Конструктор ListNode вызывает ListNode с параметрами для задания экземпляра переменной data для ссылки на объект, переданный в качестве первого аргумента, и для задания ссылке next значения null.
  3. Если список не пустой, тогда новый узел "вплетается" в список заданием элементов lastNode и lastNode.next для ссылки на новый объект ListNode, инициализированный с элементом insertItem. При исполнении конструктора ListNode задается переменная экземпляра data для ссылки на объект PData, переданный в качестве первого аргумента, и ссылке next задается значение null.

 

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

 

 

б). вставка нового узла в конец списка
а). список и новый узел     Рисунок 7. Графическое представление операции InsertAtBack    

Метод RemoveFromFront удаляет первый узел из списка и возвращает ссылку на удаленные данные. Метод выдает исключение EmptyListException, если программист пытается удалить узел из пустого списка. В противном случае метод возвращает ссылку на удаленные данные. Данный метод состоит из четырех шагов (показаны на рисунке 1.5):

  1. Присвоение firstNode.Data (удаляемые из списка данные) ссылке removeItem.
  2. Если объекты, на которые ссылаются элементы firstNode и lastNode, являются одним объектом, тогда список имеет только один элемент перед попыткой удаления. В этом случае метод задает значение null элементам firstNode и lastNode для вывода из потока (удаления) узла из списка (список остается пустым).
  3. При наличии в списке более одного узла до операции удаления метод оставляет ссылку lastNode как есть и просто присваивает элемент firstNode.Next ссылке firstNode. Таким образом, firstNode делает ссылку на узел, который был вторым до вызова метода RemoveFromFront.
  4. Возвращение ссылки removeItem.

 

На рисунке 8, а показан список до операции удаления, а на рисунке 8, б— фактические манипуляции ссылкой.

а). список до удаления первого узла

 

б). изменение ссылки

 

Рисунок 8. Графическое представление операции RemoveFromFront.

 

Метод RemoveFromBack удаляет последний узел списка и возвращает ссылку на удаленные данные. Данный метод выбрасывает исключение EmptyListException, если программа делает попытку удаления узла из пустого списка. Метод состоит из нескольких шагов (рисунок 9):

  1. Присвоить lastNode.Data (удаляемые из списка данные) ссылку removeItem.
  2. Если объекты, на которые ссылаются firstNode и lastNode, являются одним объектом, тогда список имеет только один элемент перед попыткой удаления. В этом случае метод задает элементам firstNode и lastNode значение null для удаления узла из списка (список остается пустым).
  3. Если перед операцией удаления список содержит более одного узла, создать ссылку current класса ListNode и присвоить ей элемент firstNode.
  4. "Проход списка" ссылкой current до ссылки на предпоследний узел списка: цикл while присваивает current.Next ссылке current, пока current.Next не равно lastNode.
  5. После определения местоположения предпоследнего узла присвоить current элементу lastNode для удаления из списка последнего узла.
  6. Задать значение null свойству current.Next в новом последнем узле списка для обеспечения надлежащего завершения списка.
  7. Возвратить ссылку removeItem.

 

На рисунке 9, а представлен список до операции удаления, на рисунке 9, б — фактические манипуляции ссылкой.

а). список до удаления последнего элемента

б). изменение ссылки

 

Рисунок 9. Графическое представление операции RemoveFromBack

Работа с указанными записями.

 

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

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

 

Метод RemoveFrom(int n)

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

 

  1. Присвоить RemuveItem данные первой записи.
  2. Если первый узел является последним, то очистить список и выйти.
  3. Если «выбран» первый элемент, то следующий элемент сделать первым, то есть удалить первый элемент.
  4. Во всех остальных случаях перейти к элементу, предшествующему «выбранному».
  5. Сохранить данные следующего за текущим («выбранного») элемента.
  6. Если «выбранный» элемент является последним, то последним узлом сделать текущий и «заглушить» список (удалить последний элемент).
  7. Если «выбранный» элемент не последний, то ссылку next предыдущего элемента установить на элемент, следующий за «выбранным».
  8. Возвратить удаленные данные.

 

Метод EditRow(PData newItem, int posItem)

Метод RemoveFrom заменяет данные на статическую запись PData в указанной записи списка. Здесь метод выполняет поиск указанной записи списка, сохраняет ее данные, задает их как аргумент newItem и возвращает сохраненную запись.

Виртуальный вывод на консоль. Метод Print(string s, bool pak)

 

Метод Print сначала определяет степень заполнения списка. Если список пуст, тогда метод Print отображает строку, содержащую слово "Пустой" и название списка (name), после чего возвращает 0 и передает управление в вызывающий метод. В противном случае метод Print выдает данные в списке.

Вывод. Метод распечатывает строку s и название name. Затем создается ссылка current класса ListNode, которая инициализируется элементом firstNode. Пока ссылка current не равна null, в списке имеется несколько элементов. Следовательно, метод распечатывает элемент current.Data, после чего присваивает current.Next ссылке current для перехода к следующему узлу списка. После выполнения цикла, если pak истинно, то программа приостанавливается до нажатия любой клавиши. Метод возвращает количество узлов в списке.

 

Виртуальный вывод в файл. Метод Printf(string s)

Метод Printf также проверяет список на пустоту. Если список пуст, тогда метод отображает строку, что "Список с именем (name) пуст" и название списка, после чего возвращает false и передает управление в вызывающий метод. В противном случае метод Printf выводит данные в файл data(s).txt, где s – аргумент метода, представляющий собой следующий номер по порядку файлов формата «data*.txt» в исследуемой директории «D:\».

Для вывода в данный файл создается ссылка на пишущий поток. При помощи стандартного его метода WriteLine производится вывод названия списка и его элементов, подобно выводу в методе Print.

После цикла файл закрывается и возвращается true, означая успех произведенной операции вывода.

 

 

Обратите внимание, что если ссылка в последнем узле списка не имеет значения null, тогда рассмотренные алгоритмы будут предпринимать ошибочную попытку вывода после окончания списка. Алгоритм вывода одинаков для связанных списков, стеков и очередей.

 

Пространство имен LinkedListLibrary и класс List для представления односвязного списка:

 

using System;

using System.IO;

 

namespace LinkedListLibrary

{

// Определение класса List

public class List

{

   private ListNode firstNode;

   private ListNode lastNode;

   private string name;   // Имя списка

 

   // Построение пустого списка с заданным именем

   public List(string ListName)

   {

       name = ListName;

       firstNode = lastNode = null;

   }

 

   // Конструктор без параметров

   public List(): this("list") { }

 

   // Вставка узла в начало списка с проверкой списка на пустоту

   public void InsertAtFront(PData insertItem)

   {

       lock (this)

       {

           if (IsEmpty())

               firstNode = lastNode = new ListNode(insertItem);

           else

               firstNode = new ListNode(insertItem, firstNode);

       }

   }

 

   // Вставка узла в конец списка с проверкой списка на пустоту

   public void InsertAtBack(PData insertItem)

   {

       lock (this)

       {

           if (IsEmpty())

               firstNode = lastNode = new ListNode(insertItem);

           else

               lastNode = lastNode.Next = new ListNode(insertItem);

       }

   }

 

   // Удаление первого узла из списка

   public PData RemuveFromFront()

   {

       lock (this)

       {

           if (IsEmpty())

               throw new EmptyListException(name);

           PData RemuveItem = firstNode.Data;

           if (firstNode == lastNode)

               firstNode = lastNode = null;

           else

               firstNode = firstNode.Next;

 

           return RemuveItem;

       }

   }

 

   // Удаление последнего узла из списка

   public PData RemuveFromBack()

   {

       lock (this)

       {

           if (IsEmpty())

               throw new EmptyListException(name);

           PData RemuveItem = lastNode.Data;

           if (firstNode == lastNode)

               firstNode = lastNode = null;

           else

           {

               ListNode current = firstNode;

               while (current.Next!= lastNode)

                   current = current.Next;

 

               lastNode = current;

               current.Next = null;

           }

           return RemuveItem;

       }

   }

 

   // Удаление указанного узла из списка

   public PData RemuveFrom(int n)

   {

       lock (this)

       {

           if (IsEmpty())

               throw new EmptyListException(name);

           PData RemuveItem = firstNode.Data;

           if (firstNode == lastNode)

           {

               firstNode = lastNode = null;

               return RemuveItem;

           }

           if (n == 1)

           {

               firstNode = firstNode.Next;

           }

           else

           {

               ListNode current = firstNode;

               for (int i = 1; i < n - 1; i++)

               {

                   if (current.Next == lastNode) break;

                   current = current.Next;

               }

               RemuveItem = current.Next.Data;

               if (current.Next == lastNode)

               {

                   lastNode = current;

                   current.Next = null;

               }

               else current.Next = current.Next.Next;

           }

           return RemuveItem;

       }

   }

   // Специальные операции с записями

   // Заменяет указанную запсиь последней, остальные отбрасывает.

   public PData ChangeCurrentToLastAndCut(int n)

   {  

       lock (this)

       {

             ListNode currFirst = firstNode;

           ListNode currLast = lastNode;

           for (int i = 1; i < n; i++)

               currFirst = currFirst.Next;

 

           PData RemuveItem = currFirst.Data;

           if (firstNode!= lastNode)

               do

               {

                   currLast = currFirst;

                   while (currLast.Next!= lastNode)

                       currLast = currLast.Next;

 

                   currLast.Data = lastNode.Data;;

                   currLast.Next = null;

                   lastNode = currLast;

               } while (currLast!= currFirst);

           return RemuveItem;

       }

   }

 

   // Специальные операции с записями

   // Заменяет указанную запись следующей по списку и вовзращает

   // удаленные данные.

   public PData Left1(int n)

   {

       ListNode current = firstNode;

       for (int i = 1; i < n; i++)

           current = current.Next;

       if (current.Next == null) 

       {

           PData d = RemuveFromBack();

           return d;

       }

       else

       {

           PData d = current.Data;

           current.Data = current.Next.Data;

           if (current.Next.Next == null)

           {

               current.Next = null;

               lastNode = current;

           }

           return d;

       }

   }

 

   // Проверка спаска на пустоту

   public bool IsEmpty()

   {

       lock (this)

       {

           return firstNode == null;

       }

   }

 

   // Модификация записи списка

   public PData EditRow(PData newItem, int posItem)

   {

       ListNode current = firstNode;

       for (int i = 1; i < posItem; i++)

           current = current.Next;

       PData d = current.Data;

       current.Data = newItem;

       return d;

   }

 

      public void ClearList()

   {

       firstNode = lastNode = null;

   }

 

   // Вывод ФИО пенсионеров

   virtual public int PrintPension()

   {

       ListNode current = firstNode;

       Console.WriteLine("\nСписок сотрудников пенсионного возраста:");

       int n = 0;

       do

       {

         // Для мужчин

         if ((current.Data.Sex.ToUpper() == "М") && (current.Data.Age >= 60))

           {

               Console.WriteLine("{0} {1} {2}", current.Data.Surname, current.Data.Firstname, current.Data.Lastname);

               n++;

           }

         // Для женщин

         if ((current.Data.Sex.ToUpper() == "Ж") && (current.Data.Age >= 55))

           {

               Console.WriteLine("{0} {1} {2}", current.Data.Surname, current.Data.Firstname, current.Data.Lastname);

               n++;

           }

           current = current.Next;

       } while (current!= lastNode);

         return n;

   }

 

   // Вывод содержимого списка на консоль

   virtual public int Print(string s, bool pak)

   {

       lock (this)

       {

           if (IsEmpty())

           {

               Console.WriteLine("Пустой " + name);

               return 0;

           }

 

           Console.WriteLine(s + " " + name + ": ");

           ListNode current = firstNode;

           int n = 0;

           while (current!= null)

           {

               Console.Write(" {0} {1} {2} {3} {4} {5} {6}\n", current.Data.TabNom, current.Data.Surname, current.Data.Firstname, current.Data.Lastname, current.Data.Age, current.Data.Sex, current.Data.Adress);

               current = current.Next;

               n++;

           }

           if (pak)

           {

               Console.WriteLine("\n");

               Console.ReadKey();

           }

           return n;

       }

   }

    

   // Вывод содержимого списка в файл

   virtual public bool Printf(string s)

   {

       if (IsEmpty())

       {

          Console.Write(" Список " + name + " пустой, действие отменяется.");

          return false;

       }

 

       // FileInfo f = new FileInfo(@"D:\data" + s + ".txt");

       StreamWriter fs = new StreamWriter(@"D:\data" + s + ".txt");

 

       fs.WriteLine(name);

       ListNode current = firstNode;

       while (current!= null)

       {

           fs.Write("{0} {1} {2} {3} {4} {5} {6}" + Convert.ToChar(13), current.Data.TabNom, current.Data.Surname, current.Data.Firstname, current.Data.Lastname, current.Data.Age, current.Data.Sex, current.Data.Adress);

           current = current.Next;

       }

       fs.WriteLine();

       fs.Close();

       return true;

   }

 

} // Конец класса List

 

//Определение класса EmptyListException

public class EmptyListException: ApplicationException

{

   public EmptyListException(string name)

      : base("Список" + name + "пуст!")

   { }

}

 } // Конец пространства имен LinkedListLibrary

Задание

 

1. Составить программу на языке C# для обработки данных с помощью динамических структур данных в соответствии с индивидуальным заданием к лабораторной работе №.7 (табл. 10). В программе предусмотреть:

­ организацию заданного вида односвязного списка (табл. 13);

­ ввод с клавиатуры и добавление записей в список согласно его специфике;

­ удаление записей из списка согласно его специфике;

­ выполнение заданной операции с указанными записями;

­ вывод списка в соответствии с индивидуальным заданием.

2. Разработать блок-схему алгоритма метода Main.

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

 

Таблица 13. Варианты индивидуальных заданий к лабораторной работе №10

№ вар. Вид односвязного списка Операции с указанными записями Вывод списка пользователю
1 очередь изменение указанной записи на консоль
2 стек удаление указанной записи в файл
3 очередь добавление записи в указанную позицию в файл
4 стек изменение указанной записи на консоль
5 очередь добавление записи в указанную позицию на консоль
6 стек удаление указанной записи в файл
7 очередь удаление указанной записи в файл
8 стек изменение указанной записи на консоль
9 очередь добавление записи в указанную позицию на консоль
10 стек удаление указанной записи в файл

 


 

Лабораторная работа №11

 

Тема: Принудительное наследование. Абстрактные классы и абстрактные методы в C#

 

Цель: изучение принципов реализации базового принципа ООП «Наследование» на языке C# с применением абстрактных классов, освоение техники применения абстрактных классов для частичной реализации базовых классов при использовании принудительного наследования.

 

Теоретические положения

Абстрактный класс.

 

Предположим в базовом классе для какого-то наследуемого метода трудно придумать осмысленное наполнение. Например, реализация иерархии геометрических фигур от базового класса Figure, в котором определен метод Draw. Задачей этого метода является рисование фигуры, однако для Figure тело Draw придется, скорее всего, оставить пустым, так как нарисовать абстрактную фигуру достаточно проблематично. В этом случае может быть объявлен абстрактный метод без его наполнения каким-либо содержимым. Для этого нужно при объявлении метода указать модификатор abstract и не определить ему тела.

 

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

 

Абстрактный метод автоматически становится виртуальным, так что модификатор virtual при объявлении такого метода не нужен. Если же попытаться его указать произойдет ошибка на этапе компиляции. В классе потомке при реализации абстрактного метода в объявлении нужно будет указать ключевое слово override.

 

Рассмотрим пример:

using System;abstract class Figure{ // Абстрактный класс   public Figure(string n){          name=n;   }   private string name;   public abstract void Draw(); // Абстрактный метод   public void ShowName(){          Console.WriteLine(name);   }}class Rectangle:Figure{   int width;   int height;   public Rectangle(int height,int width):base("Прямоугольник"){          this.width = width;          this.height = height;   }   public override void Draw(){ // реализация абстрактного метода          for(int i=0;i<height;i++){                  for(int j=0;j<width;j++){                          Console.Write("*");                  }                  Console.WriteLine();          }   }} class Sample{   static void Main()    {          try{                  Rectangle rect = new Rectangle(3,8);                  rect.ShowName();                  rect.Draw();          }          catch(Exception e){                  Console.WriteLine(e.Message);          }          Console.Read();   }}

Вывод:

Прямоугольник************************

 

Unit-тесты на C#

 

Рассмотрим процесс создания, запуска и настройки набора модульных тестов с помощью платформы модульных тестов Майкрософт для управляемого кода и обозревателя тестов Visual Studio.

 

Рассмотрим простой пример создания unit-тестов. Для этого создается консольное приложение Calc, которое выполняет деление и суммирование чисел, и класс Calculator, в котором будут производиться математические операции:

 

using System;

using System.Collections.Generic;

using System.Linq;

using System.Text;

 

namespace Calc

{

// Выполнение простых математических действий над числами

public class Calculator

{

   public double Div(double n1, double n2)

   {

       // Проверка деления на "0"

       if (n2 == 0.0D)

           throw new DivideByZeroException();

       return n1 / n2;

   }

 

   // Получаем результат сложения чисел и их увеличения на единицу

   public double AddWithInc(double n1, double n2)

   {

       return n1 + n2 + 1;

   }

}

}

 

namespace Calc

{

class Program

{

   static void Main(string[] args)

   {

   }

}

}

 

Так, в методе Div производится операция деления числа n1 на число n2. Если передаваемое число n2 будет равняться нулю, то такая ситуация приведет к исключению. Для этого знаменатель этой операции проверяется на равенство нулю.

 

Метод AddWithInc производит сложение двух передаваемых чисел и инкрементацию полученного результата суммирования на единицу.

 

На следующем шаге необходимо добавить в решение проект тестов по шаблону Unit Test Project (.NET Framework) с именем CalcTests.

 

 

В созданный проект необходимо добавить ссылку на проект Calc (вкладка Проекты).

 

 

Пустой проект unit-тестов:

 

using System;

using Microsoft.VisualStudio.TestTools.UnitTesting;

using Calc;

 

namespace CalcTests

{

[TestClass]

public class UnitTest1

{

   [TestMethod]

   public void TestMethod1()

   {

   }

}

}

В проекте Calc содержатся 2 метода, которые надо протестировать на корректность работы. Для этого надо создать 3 теста, которые будут проверять операцию деления двух чисел, операцию деления на нуль и операцию сложения двух чисел и инкрементацию полученной суммы. Итоговый класс UnitTest1:

 

[TestClass]

public class UnitTest1

{

   // Тест проверки метода AddWithInc

   [TestMethod]

   public void AddWithInc_2Plus3Inc1_Returned6()

   {

       // arrange

       var calc = new Calculator();

       double arg1 = 2;

       double arg2 = 3;

       double expected = 6;

       // act

       double result = calc.AddWithInc(arg1, arg2);

       // assert           

       Assert.AreEqual(expected, result);

   }

 

   // Тест проверки метода Div

   [TestMethod]

   public void Div_4Div2_Returned2()

   {

       // arrange

       var calc = new Calculator();

       double arg1 = 4;

       double arg2 = 2;

       double expected = 2;

       // act

       double result = calc.Div(arg1, arg2);

       // assert           

       Assert.AreEqual(expected, result);

   }

 

   [TestMethod]

   [ExpectedException(typeof(DivideByZeroException),

"Недопустимая операция деления на ноль!")]

   public void Div_4Div0_ZeroDivException()

   {

       // arrange

       var calc = new Calculator();

       double arg1 = 4;

       double arg2 = 0;

       // act

       double result = calc.Div(arg1, arg2);

       // assert           

   }

 

}

 

В тесте AddWithInc_2Plus3Inc1_Returned6 создаются 3 переменные – аргументы, передаваемые в метод AddWithInc, и ожидаемый результат, возвращаемый этим методом. Результат выполнения метода будет записан в переменную result.

 

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

 

В тесте Div_4Div2_Returned2 также создаются два аргумента и ожидаемый результат выполнения метода Div. Если результат деления 4/2 в методе равен 2, то тест считается пройдённым. В противном случае — не пройденным.

 

Тест Div_4Div0_ZeroDivException будет считаться пройденным в случае возникновения исключения DivideByZeroException – деление на нуль. В отличие от двух предыдущих тестов, в этом тесте нет оператора Assert. Здесь обработка ожидаемого результата производится с помощью атрибута ExpectedException.

 

Если аргумент 2 равен нулю, то в методе Div возникнет исключение – деление на нуль. В таком случае тест считается пройденным. В случае, когда аргумент 2 будет отличен от нуля, тест считается проваленным.

 

Для запуска теста необходимо открыть окно Test Explorer (Test -> Windows -> Test Explorer) (Ctrl+, T). В появившемся окне можно увидеть 3 добавленных теста:

 

 

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

 

Задание

 

1. Изучить механизм применения абстрактных классов в языке C#.

2. Создать абстрактный класс Array, содержащий такие члены:

- N – число элементов в массиве;

- Ar r – указатель на массив;

- Init() – метод инициализации элементов массива случайными числами в заданном диапазоне;

- Calc() – абстрактный метод подсчета числового показателя на основе данных массива;

- PrintArray() – абстрактный метод вывода массива на экран;

- Processing() – абстрактный метод, выполняющий обработку массива.

Данные для реализации методов Init() выбрать из таблицы индивидуальных заданий к выполнению лабораторной работы №4 (см. табл. 6) согласно номеру своего варианта.

3. Создать производный класс Vector, реализующий заданную обработку и вывод на экран одномерного массива.

3.1. Вывод элементов массива должен осуществляться в одну строку через символ табуляции.

3.2. Задание на расчет показателя и обработку массива выбрать из таблицы индивидуальных заданий к выполнению лабораторной работы №4 (см. табл. 6) согласно номеру варианта.

4. Создать производный класс Matrix, реализующий заданную обработку и вывод на экран двумерного массива.

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

4.2. Задание на расчет показателя и обработку массива выбрать из таблицы индивидуальных заданий к выполнению лабораторной работы №9 (см. табл. 12) согласно номеру варианта.

5. Разработать класс Test для модульного тестирования реализаций методов Calc. Для создания тестовых массивов в классах Vector и Matrix реализовать конструктор, инициализирующий массив заданной размерности константными значениями.

6. Выполнить краткое описание работы составленной программы.

7. Сделать выводы.

 

Контрольные вопросы

 

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

2. Как реализовать наследование классов на языке C#?

3. Какие модификаторы прав доступа используются при наследовании и для чего?

4. Что такое родительский класс?

5. Что такое абстрактный класс?

6. Сколько потомков может быть у родительского класса?

7. Сколько родительских классов может наследовать класс-потомок?

8. Что такое включение, какого вида бывают включения?

9. В чем состоит идея принудительного наследования?

10. Раскрыть механизм наследования классов на конкретном примере.

11. Что такое модульное тестирование?

12. На каком этапе жизненного цикла ПО выполняется модульное тестирование?

13. Какие классы C# используются для реализации модульного тестирования?

14. Какими инструментами можно протестировать соответствие фактического и ожидаемого значений?

 


 

Лабораторная работа №12

 

Тема: Наследование типа «включение-делегирование». Классы-коллекции.

 

Цель: освоение составления и тестирования алгоритмов и объектно-ориентированных программ, использующих абстрактные структуры данных и абстрактные классы по принципу «включение-делегирование».

 

Теоретические положения

 



Поделиться:


Последнее изменение этой страницы: 2021-09-26; просмотров: 64; Нарушение авторского права страницы; Мы поможем в написании вашей работы!

infopedia.su Все материалы представленные на сайте исключительно с целью ознакомления читателями и не преследуют коммерческих целей или нарушение авторских прав. Обратная связь - 3.19.27.178 (0.479 с.)