1629295407-c61bfe4caba98380ea3e7cdae6295416 (846200), страница 59
Текст из файла (страница 59)
Интерфейсы, структуры и перечисления321}val +=2; return val;public void reset() {val = start;}}public void setStart(int x) {start = x;val = start;}Как видите, класс ByTwos реализует все три метода, определенные интерфейсомISeries. Иначе и быть не может, поскольку классу не разрешается создавать частичнуюреализацию интерфейса.Рассмотрим пример, демонстрирующий использование класса ByTwos, Вот его код:// Демонстрация использования интерфейса,// реализованного классом ByTwos.using System;class SeriesDemo {public static void Main() {ByTwos ob = new ByTwos();for(int i=0; i < 5; i++)Console.WriteLine("Следующее значение равно " +ob.getNext() );Console.WriteLine("\nПереход в исходное состояние.");ob.reset();for(int i=0; i < 5; i++)Console.WriteLine("Следующее значение равно " +ob.getNext() );}}Console.WriteLine("\nНачинаем с числа 100.");ob.setStart(100);for(int i=0; i < 5; i++)Console.WriteLine("Следующее значение равно " +ob.getNext());Чтобы скомпилировать программу SeriesDemo, необходимо включить в процесскомпиляции файлы, которые содержат классы ISeries, ByTwos и SeriesDemo.
Длясоздания выполняемой программы компилятор автоматически скомпилирует все три файла.Если эти файлы называются, например, ISeries.cs, ByTwos.cs и SeriesDemo.cs, топрограмма скомпилируется посредством выполнения такой командной строки:>csc SeriesDemo.cs ISeries.cs ByTwos.csЕсли вы используете интегрированную среду (IDE) Visual Studio, добавьте все этитри файла в свой C#-проект. Вполне допустимо также поместить их в один файл.322Часть I. Язык C#Вот результаты выполнения этой программы:.Следующее значение равно 2Следующее значение равно 4Следующее значение равно 6Следующее значение равно 8Следующее значение равно 10Переход в исходное состояние.Следующее значение равно 2Следующее значение равно 4Следующее значение равно 6Следующее значение равно 8Следующее значение равно 10Начинаем с числа 100.Следующее значение равно 102Следующее значение равно 104Следующее значение равно 106Следующее значение равно 108Следующее значение равно 110В классах, которые реализуют интерфейсы, можно определять дополнительныечлены.
Например, в представленную ниже версию класса ByTwos добавлен методgetPrevious(), который возвращает предыдущее значение ряда.// Реализация интерфейса ISeries с дополнительно// определяемым методом getPrevious().class ByTwos : ISeries {int start;int val;int prev;public ByTwos() {start = 0;val = 0;prev = -2;}public int getNext() {prev = val;val += 2;return val;}public void reset() {val = start;prev = start = 2;}public void setStart(int x) {start = x;val = start;prev = val - 2;}}// Метод, не объявленный в интерфейсе ISeries.public int getPrevious() {return prev;}Глава 12.
Интерфейсы, структуры и перечисления323Обратите внимание на то, что добавление метода getPrevious() потребоваловнесения изменений в реализацию методов, определенных интерфейсом ISeries. Нопоскольку интерфейс для этих методов остается прежним, при изменении не разрушаетсякод, написанный ранее. В этом и заключается одно из достоинств использованияинтерфейсов.Как упоминалось выше, интерфейс может реализовать любое количество классов.Рассмотрим, например, класс Primes, который генерирует ряд простых чисел.
Обратитевнимание на то, что его способ реализации интерфейса ISeries в корне отличается отиспользуемого классом ByTwos.// Использование интерфейса ISeries для реализации// ряда простых чисел.class Primes : ISeries {int start;int val;public Primes() {start = 2;val = 2;}public int getNext() {int i, j;bool isprime;val++;for(i = val; i < 1000000; i++) {isprime = true;for(j = 2; j < (i/j + 1); j++) {if((i%j)==0) {isprime = false;break;}}if(isprime) {val = i;break;}}return val;}public void reset() {val = start;}}public void setStart(int x) {start = x;val = start;}Здесь важно понимать, что, хотя классы Primes и ByTwos генерируют разные рядычисел, оба они реализуют один и тот же интерфейс ISeries. И в этом нет ничегоудивительного, поскольку каждый класс волен решить эту задачу так, как “считает”нужным.324Часть I.
Язык C#Использование интерфейсных ссылокВозможно, вы будете несколько удивлены, узнав, что можно объявить ссылочнуюпеременную интерфейсного типа. Другими словами, можно создать переменную-ссылку наинтерфейс. Такая переменная может ссылаться на любой объект, который реализует ееинтерфейс. При вызове метода для объекта посредством интерфейсной ссылки будетвыполнена та версия указанного метода, которая реализована этим объектом. Этот процессаналогичен использованию ссылки на базовый класс для доступа к объекту производногокласса (см. главу 11).Использование интерфейсной ссылки демонстрируется в следующем примере. Здесьиспользуется одна и та же интерфейсная переменная-ссылка, чтобы вызывать методы дляобъектов как класса ByTwos, так и класса Primes.// Демонстрация использования интерфейсных ссылок.using System;// Определение интерфейса.public interface ISeries {int getNext(); // Возвращает следующее число ряда.void reset(); // Выполняет перезапуск.void setStart(int x);// Устанавливает начальное// значение.}// Используем интерфейс ISeries для генерирования// последовательности четных чисел.class ByTwos : ISeries {int start;int val;public ByTwos() {start = 0;val = 0;}public int getNext() {val +=2;return val;}public void reset() {val = start;}}public void setStart(int x) {start = x; val = start;}// Используем интерфейс ISeries для построения// ряда простых чисел.class Primes : ISeries {int start;int val;Глава 12.
Интерфейсы, структуры и перечисления325public Primes() {start = 2;val = 2;}public int getNext() {int i, j;bool isprime;val++;for(i = val; i < 1000000; i++) {isprime = true;for(j = 2; j < (i/j + 1); j++) {if((i%j)==0) {isprime = false;break;}}if(isprime) {val = i;break;}}return val;}public void reset() {val = start;}public void setStart(int x) {start = x;val = start;}}class SeriesDemo2 {public static void Main() {ByTwos twoOb = new ByTwos();Primes primeOb = new Primes();ISeries ob;for(int i=0; i < 5; i++) {ob = twoOb;Console.WriteLine("Следующее четное число равно " + ob.getNext());ob = primeOb;Console.WriteLine("Следующее простое число равно " +ob.getNext());}}}Вот результаты выполнения этой программы:Следующее четное число равно 2Следующее простое число равно 3Следующее четное число равно 4Следующее простое число равно 5326Часть I.
Язык C#Следующее четное число равно 6Следующее простое число равно 7Следующее четное число равно 8Следующее простое число равно 11Следующее четное число равно 10Следующее простое число равно 13В методе Main() объявляется переменная ob как ссылка на интерфейс ISeries.Это означает, что ее можно использовать для хранения ссылок на любой объект, которыйреализует интерфейс ISeries. В данном случае она служит для ссылки на объекты twoObи primeOb, которые являются экземплярами классов ByTwos и Primes, соответственно,причем оба класса реализуют один и тот же интерфейс, ISeries.Важно понимать, что интерфейсная ссылочная переменная “осведомлена”" только ометодах, объявленных “под сенью” ключевого слова interface. Следовательно,интерфейсную ссылочную переменную нельзя использовать для доступа к другимпеременным или методам, которые может определить объект, реализующий этотинтерфейс.Интерфейсные свойстваКак и методы, свойства определяются в интерфейсе без тела.
Ниже приведен форматспецификации свойства.// Интерфейсное свойствотип имя{get;set;}Свойства, предназначенные только для чтения или только для записи, содержаттолько get- или set-элемент, соответственно.Рассмотрим еще одну версию интерфейса ISeries и класса ByTwos, в котором дляполучения следующего элемента ряда и его установки используется свойство.// Использование свойства в интерфейсе.using System;public interface ISeries {// Интерфейсное свойство.int next {get; // Возвращает следующее число ряда.set; // Устанавливает следующее число ряда.}}// Реализация интерфейса ISeries.class ByTwos : ISeries {int val;public ByTwos() {val = 0;}// Получаем или устанавливаем значение ряда.public int next {get {Глава 12.
Интерфейсы, структуры и перечисления327val +=2;return val;}set {val = value;}}}// Демонстрируем использование интерфейсного свойства.class SeriesDemo3 {public static void Main() {ByTwos ob = new ByTwos();}}// Получаем доступ к ряду через свойство.for(int i=0; i < 5; i++)Console.WriteLine("Следующее значение равно " +ob.next);Console.WriteLine("\nНачинаем с числа 21");ob.next = 21;for(int i=0; i < 5; i++)Console.WriteLine("Следующее значение равно " +ob.next);Результаты выполнения этой программы таковы:Следующее значение равно 2Следующее значение равно 4Следующее значение равно 6Следующее значение равно 8Следующее значение равно 10Начинаем с числа 21Следующее значение равно 23Следующее значение равно 25Следующее значение равно 27Следующее значение равно 29Следующее значение равно 31Интерфейсные индексаторыВ интерфейсе можно определить и индексатор.
Объявление индексатора винтерфейсе имеет следующий формат записи:// Интерфейсный индексатортип_элемента this[int индекс]{get;set;}Индексаторы, предназначенные только для чтения или только для записи, содержаттолько get- или set-метод, соответственно.Предлагаем еще одну версию интерфейса ISeries, в который добавлен индексатор,предназначенный только для чтения элемента ряда.328Часть I. Язык C#// Добавление в интерфейс индексатора.using System;public interface ISeries {// Интерфейсное свойство.int next {get; // Возвращает следующее число ряда.set; // Устанавливает следующее число ряда.}// Интерфейсный индексатор.int this[int index] {get; // Возвращает заданный член ряда.}}// Реализация интерфейса ISeries.class ByTwos : ISeries {int val;public ByTwos() {val = 0;}// Получаем или устанавливаем значение с помощью// свойства.public int next {get {val += 2;return val;}set {val = value;}}}// Получаем значение с помощью индексатора.public int this[int index] {get {val = 0;for(int i=0; i<index; i++)val += 2;return val;}}// Демонстрируем использование интерфейсного индексатора.class SeriesDemo4 {public static void Main() {ByTwos ob = new ByTwos();// Получаем доступ к ряду посредством свойства.for(int i=0; i < 5; i++)Console.WriteLine("Следующее значение равно " +ob.next);Глава 12.