Для того чтобы лучше понять операцию извлечения интерфейса, давайте рассмотрим пример. Предположим, что вы анализируете свой код и замечаете, что некоторые ваши объекты имеют аналогичные свойства и методы. Предположим, что объекты Customer, Vendor, Manufacturer, SalesAgent и Product содержат свойства Id, Name и Description, a также методы Load, Save и Delete. В этом случае вам следует рассмотреть возможность извлечения этой общности в стандартный интерфейс, который будет реализовываться каждым из ваших объектов. Посмотрим, как в этом отношении нам может помочь операция рефакторинга Extract Interface.
Сначала вы помещаете курсор на целевой класс, члены которого вы хотите извлечь. Для нашего примера выберите класс Customer. Вызов операции Extract Interface выдаст одноименное диалоговое окно. На рис. 9.17 показано это диалоговое окно для данного примера.
Обратите внимание, что сначала вы определяете имя для интерфейса. По умолчанию инструмент рефакторинга называет интерфейс именем класса после буквы 1 (от англ. interface)— в нашем случае это будет iCustomer. Конечно, мы хотим использовать собственный интерфейс, поэтому мы изменим название на iDomainObject.
Рис. 9.17. Извлечение интерфейса
Диалоговое окно Extract Interface показывает также сгенерированное имя и новое название файла для интерфейса. Сгенерированное имя — это просто полностью квалифицированное имя интерфейса. Оно будет использоваться классом для реализации интерфейса. Текстовое поле New File Name показывает имя файла C# для интерфейса.. Все извлеченные интерфейсы приводят к созданию нового файла. Инструмент рефакторинга старается поддерживать соответствие имени интерфейса и имени файла.
Последнее, что необходимо сделать, — это выбрать те члены объекта, которые вы хотите опубликовать как интерфейс. Конечно, в этом списке отображаются только открытые члены. Для данного примера выберите следующие открытые члены: Id, Name, Description, Load, Save И Delete.
Нажатие кнопки OK приведет к генерированию интерфейса. Единственное изменение, которое происходит в классе Customer — это то, что теперь он реализует новый интерфейс, как показано в следующей строке кода:
public class Customer : BusinessDomain.IDomainObject
Затем интерфейс извлекается в новый файл. В листинге 9.4 показан извлеченный интерфейс.
string Name { get; set; } void Save();
}
Следующий шаг нашего примера— это реализация нового интерфейса во всех объектах. Это придется делать без помощи рефакторинга. Однако Visual Studio предоставляет смарт- тег для реализации интерфейса. На рис. 9.18 показан смарт-тег, который получен в результате ввода iDomainObject после объявления класса Vendor.
В данном случае у вас есть два варианта: реализовать интерфейс или явно реализовать интерфейс. Первый вариант проверяет текущий класс в поиске применимых реализаций. Второй вариант генерирует код, который явно вызывает элементы интерфейса. Он помещает весь этот код в область для данного интерфейса. Эта возможность может быть очень полезна в том случае, когда вы делаете заглушку для нового класса, основанного на интерфейсе. Следующие строки кода дают пример явного объявления членов интерфейса:
void IDomainObject.Load(int id) {
throw new NotImplementedException();
}