Интернет-журнал "Домашняя лаборатория", 2007 №9
Шрифт:
Два метода класса являются запросами, позволяющими извлечь ключ и элемент списка, который отмечен курсором:
public К Key
{
return (cursor.key);
}
public T Item
{
return(cursor.item);
}
Давайте рассмотрим теперь тестирующую процедуру — клиента нашего списка, демонстрирующую работу со списками, в которых элементы и ключи имеют разные типы:
public void TestConstraint
{
OneLinkList<int, string> list1 = new OneLinkList
<int, string>;
list1.add(33, "thirty three"); list1.add (22, "twenty two");
if (list1.findstart(33)) Console.WriteLine ("33 —
else Console.WriteLine("33 — не найдено!");
if (list1.findstart(22)) Console.WriteLine ("22 — найдено!");
else Console.WriteLine("22 — не найдено!");
if (list1.findstart(44)) Console.WriteLine ("44 — найдено!");
else Console.WriteLine("44 — не найдено!");
Person pers1 = new Person("Савлов", 25, 1500);
Person pers2 = new Person("Павлов", 35, 2100);
OneLinkList<string, Person> list2 = new OneLinkList
< string, Person>;
list2.add("Савл", pers1); list2.add("Павел", pers2);
if (list2.findstart("Павел")) Console.WriteLine ("Павел — найдено!");
else Console.WriteLine("Павел — не найдено!");
if (list2.findstart("Савл")) Console.WriteLine ("Савл — найдено!");
else Console.WriteLine("Савл — не найдено!");
if (list2.findstart("Иоанн")) Console.WriteLine ("Иоанн — найдено!");
else Console.WriteLine("Иоанн — не найдено!");
Person pers3 = new Person("Иванов", 33, 3000);
list2.add("Иоанн", pers3); list2.start ;
Person pers = list2.Item; pers.PrintPerson;
list2.findstart("Иоанн"); pers = list2.Item;
pers.PrintPerson;
}
Рис. 22.5. Поиск в списке с ограниченной универсальностью
Обратите внимание на строки, где создаются два списка:
OneLinkList<int, string> list1 = new OneLinkList<int, string>;
OneLinkList<string, Person> list2 = new OneLinkList< string, Person>;
У списка list1 ключи имеют тип int, у списка list2 — string. Заметьте, оба фактических типа, согласно обязательствам, реализуют интерфейс IComparable, у первого списка тип элементов — string, у второго — Person. Все работает прекрасно. Вот результаты вычислений по этой процедуре:
Как справиться с арифметикой
Представьте себе, что мы хотим иметь специализированный вариант нашего списка, элементы которого допускали бы операцию сложения и одно из полей которого сохраняло бы сумму всех элементов, добавленных в список. Как задать соответствующее ограничение на класс?
Как
Вот один из возможных выходов, предлагаемых в такой ситуации. Стратегия следующая: определим абстрактный универсальный класс Calc с методами, выполняющими вычисления. Затем создадим конкретизированных потомков этого класса. В классе, задающем список с суммированием, введем поле класса Calc. При создании экземпляров класса будем передавать фактические типы ключа и элементов, а также соответствующий калькулятор, но уже не как тип, а как аргумент конструктора класса. Этот калькулятор, согласованный с типом элементов, и будет выполнять нужные вычисления. Давайте приступим к реализации этой стратегии. Начнем с определения класса Calc;
public abstract class Calc<T>
{
public abstract T Add(T a, T b);
public abstract T Sub(T a, T b);
public abstract T Mult(T a, T b);
public abstract T Div(T a, T b);
}
Наш абстрактный универсальный класс определяет четыре арифметические операции. Давайте построим трех его конкретизированных потомков:
public class IntCalc: Calc<int>
{
public override int Add(int a, int b) { return (a + b);}
public override int Sub (int a, int b) { return (a — b);}
public override int Mult(int a, int b) { return (a * b);}
public override int Div(int a, int b) { return (a / b); }
}
public class DoubleCalc: Calc<double>
{
public override double Add(double a, double b)
{return (a + b);}
public override double Sub(double a, double b)
{return (a — b);}
public override double Mult(double a, double b)
{return (a * b);}
public override double Div(double a, double b)
{return (a / b);}
}
public class StringCalc: Calc<string>
{
public override string Add(string a, string b)
{return (a + b);}
public override string Sub(string a, string b)
{return (a);}
public override string Mult(string a, string b)
{return (a);}
public override string Div (string a, string b)
{return (a);}
}
Здесь определяются три разных калькулятора: один — над целочисленными данными, другой — над данными с плавающей точкой, третий — над строковыми данными. В последнем случае определена, по сути, только операция сложения строк (конкатенации).