5505

Интерфейсы. Определение и реализация интерфейсов

Контрольная

Информатика, кибернетика и программирование

Интерфейсы В этом разделе рассматриваются интерфейсы за счет представления полного определения одного из интерфейсов, определенного Microsoft - System. IDisposable. Интерфейс IDisposable содержит один метод Dispose, предназначенный для...

Русский

2012-12-12

71.5 KB

9 чел.

Интерфейсы

В этом разделе рассматриваются интерфейсы за счет представления полного определения одного из интерфейсов, определенного Microsoft — System. IDisposable. Интерфейс IDisposable содержит один метод Dispose (), предназначенный для реализации классами, которые выполняют очистку кода:

public interface IDisposable

{void Dispose ( ); }

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

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

Также не допускается указывать модификаторы при определении членов интерфейса. Члены интерфейса всегда неявно являются public и не могут быть virtual или static. Это оставлено для реализации классам. Поэтому это нормально — указывать модификаторы доступа к членам интерфейса в реализующих их классах, что и делается в примерах настоящего раздела.

Возьмем, например, IDisposable. Если класс пожелает объявить, что он реализует метод Dispose(), то он должен будет реализовать интерфейс IDisposable, что в терминах С# означает, что он наследуется от IDisposable.

class  SomeClass:  IDisposable

{

//  Этот класс ДОЛЖЕН содержать реализацию метода

//  IDisposable.Dispose(),   иначе  вы получите  ошибку компиляции

public void Dispose()

{ // реализация метода Dispose()

}

//  остальная часть класса

}

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

IDisposable - сравнительно простой интерфейс, потому что определяет только один метод. Большинство интерфейсов содержат большее число методов.

Определение и реализация интерфейсов

Рассмотрим, как определять и использовать интерфейсы при разработке короткой программы, реализующей парадигму наследования интерфейсов. Пример описывает банковский счет. Предположим, вы пишете код, который в конечном итоге обеспечит компьютеризованный перевод денег между банковскими счетами. И предположим, что существует множество компаний, которые могут реализовывать банковские счета, но все они согласились с тем, что любые классы, представляющие банковские счета, должны реализовывать интерфейс IBankAccount, предусматривающий методы для внесения и съема денежных сумм, а также свойство, возвращающее баланс. Это тот интерфейс, который позволит внешнему коду распознать различные классы банковских счетов, реализующие различные формы таких счетов. Хотя целью этого является обеспечение взаимодействия банковских счетов между собой для перевода денег, пока мы не будем представлять эту возможность.

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

Для начала потребуется определить интерфейс IBankAccount:

using System;

using System.Collections.Generic;

using System.Text;

namespace InterfaceLibrary

{

   public interface IBankAccount

   {

       void PayIn(decimal amount);

       bool Withdraw(decimal amount);

       decimal Balance

       {

           get;

       }

   }

}

Обратите внимание на имя интерфейса — IBankAccount. Существует соглашение, что имя интерфейса традиционно начинается с буквы I, чтобы сразу было видно, что это интерфейс.

Идея заключается в том, что теперь вы имеете возможность писать классы, представляющие банковские счета. Эти классы не должны быть как-то связанными друг с другом; они могут быть полностью различными. Однако все они декларируют свое представление банковских счетов тем, что реализуют интерфейс IBankAccount.

Начнем с первого класса, описывающего сберегательный счет в Королевском Банке Венеры:

namespace InterfaceLibrary

{

   public class SaverAccount: IBankAccount

   {

       private decimal balance;

       public void PayIn(decimal amount)

       {

           balance += amount;

       }

       public bool Withdraw(decimal amount)

       {

           if (balance >= amount)

           {

               balance -= amount;

               return true;

           }

           else

           {

               Console.WriteLine("попытка списания суммы {0,6:C} банком Венеры не удалась", amount);

               return false;

           }

       }

       public decimal Balance

       {

           get

           {

               return balance;

           }

       }

       public override string ToString()

       {

           return String.Format("Банк Венеры: Баланс = {0,6:C}", balance);

       }

}

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

Единственной интересной строкой в этом коде является объявление класса:

public class  SaverAccount: IBankAccount 

Она объявляет, что SaverAccount наследуется от одного интерфейса, - '- IBankAccount, никакого другого базового класса не указано (что, конечно же, означает, что SaverAccount наследуется от System.Object). Кстати говоря, наследование интерфейсов совершенно независимо от наследования классов.

То, что SaverAccount наследуется от IBankAccount, означает, что у SaverAccount есть все члены IBankAccount. Но поскольку интерфейс сам по себе не реализует никакие из своих методов, SaverAccount должен предоставить их собственную реализацию. Если реализация любого из них пропущена, можно быть уверенным, что компилятор это заметит и "пожалуется". Вспомним также о том, что интерфейсы просто указывают на присутствие его членов. Решение о том, объявлять ли их virtual или abstract остается на совести класса (хотя абстрактные функции,  конечно же, допускаются только в абстрактных классах). Что касается данного конкретного примера, то и здесь нет никаких причин объявлять любую из функций интерфейса виртуальной.

Чтобы проиллюстрировать, как различные классы могут реализовать один и тот же интерфейс, предположим, что Планетарный Банк Юпитера также реализует собственный класс, представляющий банковские счета —

namespace InterfaceLibrary

{

   public class GoldAccount: IBankAccount

   {

       private decimal balance;

       public void PayIn(decimal amount)

       {

           balance += amount;

       }

       public bool Withdraw(decimal amount)

       {

           if (balance >= amount)

           {

               balance -= amount;

               return true;

           }

           else

           {

               Console.WriteLine("Попытка списания суммы {0,6:C} банком Юпитера не удалась", amount);

               return false;

           }

       }

       public decimal Balance

       {

           get

           {

               return balance;

           }

       }

       public override string ToString()

       {

           return String.Format("Банк Юпитера: Баланс = {0,6:C}", balance);

       }

   }

}

Мы не будем здесь рассматривать детали класса GoldAccount; в коде примера он будет практически идентичен реализации SaverAccount. Подчеркнем, что GoldAccount не имеет никакой связи с SaverAccount кроме того, что оба они реализуют один и тот же интерфейс.

Теперь, имея готовые классы, их можно протестировать. Во-первых, понадобится несколько операторов using:

using System;

using System.Collections.Generic;

using System.Text;

using System.IO;

using InterfaceLibrary;

namespace ApplicationInterface

{

   class Program

   {

       static void Main(string[] args)

       {

           string str = "";

           IBankAccount ven = new SaverAccount();

           IBankAccount jup = new GoldAccount();

           ven.PayIn(200);

           if (ven.Withdraw(300))

               Console.WriteLine(ven.ToString());

           if(ven.Withdraw(100))

               Console.WriteLine(ven.ToString());

           jup.PayIn(500);

           if (jup.Withdraw(600))

               Console.WriteLine(jup.ToString());

           if (jup.Withdraw(100))

               Console.WriteLine(jup.ToString());

           str = Console.ReadLine();

       

       }

   }

}

Этот код сгенерирует следующий вывод:

C: > BankAccounts

Главный момент, который следует здесь отметить — способ объявления обеих переменных как ссылок на IBankAccount. Это значит, что они могут указывать на любой экземпляр любого класса, реализующего интерфейс. Это также означает, что через эти ссылки вы можете вызывать только те методы, которые являются частью интерфейса. Если вам понадобится вызвать любые методы, реализованные классом, но не являющиеся частью интерфейса, то придется выполнить приведение ссылки к соответствующему типу. В примере кода вызывается метод ToString() (не объявленный в IBankAccount) без какого-либо явного приведения, просто потому, что ToString () - это метод Sysem.Object, поэтому компилятор С# знает о том, что он содерживается любым классом (иначе говоря, приведение любого интерфейса к Sysem.Object выполняется неявно).

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

IBankAccount[] accounts = new IBankAccount[2];

Accounts[0] = new SaverAccount( );

Accounts[1] = new GoldAccount( );

Однако отметим, что если попытаемся сделать что-то вроде такого:

Accounts[1] = new SomeOtherClass();  // SomeOtherClass не реализует

   //  IBankAccount:   НЕВЕРНО!!!

то получим следующую ошибку компиляции.

Производные интерфейсы

Интерфейсы могут быть унаследованы друг от друга — точно так же, как это делают классы. Эта концепция иллюстрируется ниже определением нового интерфейса ITransferBankAccount, который имеет те же средства, что и IBankAccount, но также определяет метод для перевода денег непосредственно на другой счет:

namespace InterfaceLibrary

{

 public interface ITransferBankAccount : IBankAccount

 {

   bool TransferTo(IBankAccount destination, decimal amount);

 }

}

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

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


 

А также другие работы, которые могут Вас заинтересовать

41946. Анализ напряженного состояния аппарата, нагруженного внутренним давлением и изгибающим моментом 410.71 KB
  В соответствии с этой теорией меридиональные и кольцевые напряжения возникающие в стенке цилиндрической оболочки составляют: ; ; МПа МПагде r – радиус оболочки по срединной поверхности r = 01055м Из приведенных соотношений видно что напряжения вызванные внутренним давлением р постоянны не зависят от положения сечения на оболочке. При изгибе колонны в её стенках возникают нормальные в меридиональном направлении а также касательные напряжения которыми в виду их малости можно пренебречь. Меридиональные напряжения определяются по...
41947. РОЗРАХУНОК ПРИПУСКІВ НА МЕХАНІЧНУ ОБРОБКУ ОПТИЧНИХ ДЕТАЛЕЙ 19.86 MB
  Обладнання для виконання лабораторної роботи Оптичні деталі: лінза призма. Припуск zt на товщину по осі заготовок лінз та пластин встановлюють від верхньої межі допуску на розмір готової деталі. Величину zt яка лежить в межах від 18 до 80 мм призначають в залежності від діаметра Do круглих або найбільшої сторони некруглих пластин: Припуск zd на діаметр встановлюють від номінального розміру готової деталі від 15 до 120 мм. Призначають zd так як і припуск на товщину по осі в залежності від діаметра деталі.
41948. Створення діаграми дій 175.84 KB
  Вивчення призначення методів побудови елементів діаграми дій. Хід роботи Створити на діаграмі дії переходи точку прийняттярішення контролючийперехід Привести линіїдіаграми до ортогональноговигляду.
41949. Изучение характеристик и определение параметров тиристоров 450.47 KB
  –Вольтамперная характеристика: а динистора б тринистора В отличие от динистора имеющего фиксированное напряжение включения у триодного тиристора Uвкл можно уменьшать увеличивая ток IУ тем самым управлять моментом его включения. Рисунок 3 – Тринистор выключаемый Недостатком такого выключения является большое значение обратного тока управляющего электрода которое приближается к значению коммутируемого тока тиристора. Отношение амплитуды тиристора к амплитуде импульса выключающего тока управляющего электрода называется...
41950. Створення основної діаграми класів 185.98 KB
  Створити основну діаграму класів рис. Створити приклад основної діаграми пакета Курсы рис.13 та приклад діаграмикласів принадлежащих различным пакетам рис.
41951. Відображення атрибутів та операцій класів, наслідування и агрегування на діаграмах класів 192.04 KB
  Создать диаграмму классов пакета Курсы и включить классы ПредложениеКурса Курс КонтрольПредложенияКурса в диаграмму классов. Обеспечить отображение всех атрибутов и операций на диаграмме классов. Создать диаграмму иерархии наследования классов Профессор и Студент. Переместить атрибуты по иерархии наследования классов и получить дерево наследования.
41952. ИССЛЕДОВАНИЕ ДИНАМИКИ СИСТЕМ АВТОМАТИЧЕСКОГО УПРАВЛЕНИЯ С ПРИМЕНЕНИЕМ ПАКЕТА MATLAB 83 KB
  Схема набора объекта управления. Исследование системы управления. Схема системы управления модели. выбранные коэффициенты усиления и времени интегрирования по каналу управления Ти=500 и К=0,04 приводят к устойчивой работы системы.
41953. Требования безопасности. Общие требования безопасности 1.59 MB
  Костромской государственный технологический университет 2011 Цель работы: приобретение навыков самостоятельных действий и поведения студентов направленных на сохранение жизни каждого пострадавшего до прибытия спасательных служб использование любого шанса для его спасения. Первую медицинскую помощь необходимо оказывать до прибытия медицинского персонала или до появления признаков жизни у пострадавшего или до появления признаков наступления биологической смерти трупных пятен окоченения. Наиболее эффективным способом искусственного...
41954. Социальная структура общества. Понятие и виды социальных групп 16.25 KB
  Социальная структура общества – это определенная форма устойчивых связей и отношений, обусловливающих создание социальных групп и институтов. Можно сказать, что социальная структура формирует стабильность и устойчивость общества. Согласно одному из множества определений, социальная структура представляет собой устойчивую связь элементов в социальной системе.