Наследование интерфейсов Интерфейсные свойства


Download 0.67 Mb.
bet3/8
Sana18.06.2023
Hajmi0.67 Mb.
#1571717
1   2   3   4   5   6   7   8
Bog'liq
Абстракатные классы

Пример 2.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace ConsoleApplication1
{
// Создаем абстрактный класс
abstract class UserInfo
{
protected string Name;
protected byte Age;
public UserInfo(string Name, byte Age)
{
this.Name = Name;
this.Age = Age;
}
// Абстрактный метод
public abstract string ui();
}
class UserFamily : UserInfo
{
string Family;
public UserFamily(string Family, string Name, byte Age) : base (Name, Age)
{
this.Family = Family;
}
// Переопределяем метод ui
public override string ui()
{
return Family + " " + Name + " " + Age;
}
}
class Program
{
static void Main(string[] args)
{
UserFamily user1 = new UserFamily("Erohin", "Alexandr", 26);
Console.WriteLine(user1.ui());
Console.ReadLine();
} }}
В данном примере создается абстрактный класс UserInfo в котором инкапсулируется абстрактный метод ui(), который, в свою очередь, переопределяется в классе UserFamily.
Следует отметить, что в абстрактные классы вполне допускается (и часто практикуется) включать конкретные методы, которые могут быть использованы в своем исходном виде в производном классе. А переопределению в производных классах подлежат только те методы, которые объявлены как abstract.

Интерфейсы


Для начала ознакомимся с формальным определением типа интерфейса. Интерфейс (interface)представляет собой не более чем просто именованный набор абстрактных членов. Абстрактные методы являются чистым протоколом, поскольку не имеют никакой стандартной реализации. Конкретные члены, определяемые интерфейсом, зависят от того, какое поведение моделируется с его помощью. Это действительно так. Интерфейс выражает поведение, которое данный класс или структура может избрать для поддержки. Более того, каждый класс (или структура) может поддерживать столько интерфейсов, сколько необходимо, и, следовательно, тем самым поддерживать множество поведений.
Слово "интерфейс" многозначное и в разных контекстах оно имеет различный смысл. В данной лекции речь идет о понятии интерфейса, стоящем за ключевым словом interface. В таком понимании интерфейс - это частный случай класса. Интерфейс представляет собой полностью абстрактный класс, все методы которого абстрактны. От абстрактного класса интерфейс отличается некоторыми деталями в синтаксисе и поведении. Синтаксическое отличие состоит в том, что методы интерфейса объявляются без указания модификатора доступа. Отличие в поведении заключается в более жестких требованиях к потомкам. Класс, наследующий интерфейс, обязан полностью реализовать все методы интерфейса. В этом - отличие от класса, наследующего абстрактный класс, где потомок может реализовать лишь некоторые методы родительского абстрактного класса, оставаясь абстрактным классом. Но, конечно, не ради этих отличий были введены интерфейсы в язык C#. У них значительно более важная роль.
Нетрудно догадаться, что в библиотеках базовых классов .NET поставляются сотни предопределенных типов интерфейсов, которые реализуются в различных классах и структурах. Например, в состав ADO.NET входит множество поставщиков данных, которые позволяют взаимодействовать с определенной системой управления базами данных. Это означает, что в ADO.NET на выбор доступно множество объектов соединения (SqlConnection, OracleConnection, OdbcConnection и т.д.).
В интерфейсе ни у одного из методов не должно быть тела. Это означает, что в интерфейсе вообще не предоставляется никакой реализации. В нем указывается только, что именно следует делать, но не как это делать. Как только интерфейс будет определен, он может быть реализован в любом количестве классов. Кроме того, в одном классе может быть реализовано любое количество интерфейсов.
Для реализации интерфейса в классе должны быть предоставлены тела (т.е. конкретные реализации) методов, описанных в этом интерфейсе. Каждому классу предоставляется полная свобода для определения деталей своей собственной реализации интерфейса. Следовательно, один и тот же интерфейс может быть реализован в двух классах по-разному. Тем не менее в каждом из них должен поддерживаться один и тот же набор методов данного интерфейса. А в том коде, где известен такой интерфейс, могут использоваться объекты любого из этих двух классов, поскольку интерфейс для всех этих объектов остается одинаковым. Благодаря поддержке интерфейсов в С# может быть в полной мере реализован главный принцип полиморфизма: один интерфейс — множество методов.
Интерфейсы объявляются с помощью ключевого слова interface. Ниже приведена упрощенная форма объявления интерфейса:
interface имя{возвращаемый_тип имя_метода1 (список_параметров); возвращаемый_тип имя_метода2 (список_параметров);// ... возвращаемый_тип имя_метода(список_параметров);}
где имя — это конкретное имя интерфейса. В объявлении методов интерфейса используются только их возвращаемый_тип и сигнатура. Они, по существу, являются абстрактными методами. Как пояснялось выше, в интерфейсе не может быть никакой реализации. Поэтому все методы интерфейса должны быть реализованы в каждом классе, включающем в себя этот интерфейс. В самом же интерфейсе методы неявно считаются открытыми, поэтому доступ к ним не нужно указывать явно.
Помимо методов, в интерфейсах можно также указывать свойства, индексаторы и события. Интерфейсы не могут содержать члены данных. В них нельзя также определить конструкторы, деструкторы или операторные методы. Кроме того, ни один из членов интерфейса не может быть объявлен как static.
Как только интерфейс будет определен, он может быть реализован в одном или нескольких классах. Для реализации интерфейса достаточно указать его имя после имени класса, аналогично базовому классу. Ниже приведена общая форма реализации интерфейса в классе:
class имя_класса : имя_интерфейса {// тело класса}
где имя_интерфейса — это конкретное имя реализуемого интерфейса. Если уж интерфейс реализуется в классе, то это должно быть сделано полностью. В частности, реализовать интерфейс выборочно и только по частям нельзя.
В классе допускается реализовывать несколько интерфейсов. В этом случае все реализуемые в классе интерфейсы указываются списком через запятую. В классе можно наследовать базовый класс и в тоже время реализовать один или более интерфейс. В таком случае имя базового класса должно быть указано перед списком интерфейсов, разделяемых запятой.
Методы, реализующие интерфейс, должны быть объявлены как public. Дело в том, что в самом интерфейсе эти методы неявно подразумеваются как открытые, поэтому их реализация также должна быть открытой. Кроме того, возвращаемый тип и сигнатура реализуемого метода должны точно соответствовать возвращаемому типу и сигнатуре, указанным в определении интерфейса.
В приведенном ниже коде определен интерфейс IScalableи классTextObject, который реализует этот интерфейс. Это означает, что класс содержит реализацию всех функций, объявленных в интерфейсе:
public class DiagramObject { interface IScalable { void ScaleX(float factor); void ScaleY(float factor); }
// Объект диаграммы, который также реализует интерфейс IScalable public class TextObject: DiagramObject, IScalable { public TextObject(string text) { this.text = text; } // реализуем ISclalable.ScaleX() public void ScaleX(float factor) { // ... } // реализуем ISclalable.ScaleY() public void ScaleY(float factor) { // ... } private string text; }
class Test { public static void Main() { TextObject text = new TextObject("Hello"); IScalable scalable = (IScalable) text; scalable.ScaleX(0.5F); scalable.ScaleY(0.5F); } }
Этот код описывает систему отображения диаграмм. Все объекты наследуются от DiagramObject, поэтому они содержат стандартный набор функций для отображения диаграмм (они не показаны в этом примере). Некоторые из объектов могут быть масштабированы, поэтому они реализуют интерфейсIScalable.
Имя интерфейса упоминается вместе с именем базового класса для TextObject. Это указывает на то, чтоTextObjectреализует данный интерфейс. Это означает, что для каждой функции, содержащейся в интерфейсе,TextObject должен иметь соответствующую функцию. У членов интерфейса нет модификаторов доступа; класс, который реализует интерфейс, должен сам устанавливать уровень доступа члена интерфейса.
Когда объект реализует интерфейс, ссылка на интерфейс может быть получена с помощью приведения типа ссылки к типу интерфейса (как это было сделано в приведенном выше примере). Эту ссылку можно использовать, чтобы вызвать функции интерфейса.
Этот пример мог быть сделан и с использованием абстрактных методов. Можно было поместить методы ScaleX()иScaleY()в классDiagramObjectи сделать их виртуальными.
Как правило, заранее неизвестно, поддерживает ли объект какой-нибудь интерфейс. Поэтому прежде чем выполнить приведение к типу интерфейса необходимо убедиться, что объект реализует нужный интерфейс.
interface IScalable { void ScaleX(float factor); void ScaleY(float factor); } public class DiagramObject { public DiagramObject() {} } public class TextObject: DiagramObject, IScalable { public TextObject(string text) { this.text = text; } // реализуем ISclalable.ScaleX() public void ScaleX(float factor) { Console.WriteLine("ScaleX: {0} {1}", text, factor); // здесь делаем необходимые вычисления } // реализуем ISclalable.ScaleY() public void ScaleY(float factor) { Console.WriteLine("ScaleY: {0} {1}", text, factor); // здесь делаем необходимые вычисления } private string text; }
class Test { public static void Main() { DiagramObject[] dArray = new DiagramObject[100]; // инициализируем массив с помощью классов, наследующих DiagramObject. // некоторые из них реализуют IScalable.

Download 0.67 Mb.

Do'stlaringiz bilan baham:
1   2   3   4   5   6   7   8




Ma'lumotlar bazasi mualliflik huquqi bilan himoyalangan ©fayllar.org 2024
ma'muriyatiga murojaat qiling