Две стратегии реализации интерфейса

Опишем некоторый интерфейс, задающий дополнительные свойства объектов класса:

public interface IProps{

void Prop1(string s);

void Prop2 (string name, int val);

}

Класс, наследующий интерфейс и реализующий его методы, может реализовать их явно, объявляя соответствующие методы класса открытыми:

public class Clain:IProps{

public Clain() {}

public void Prop1(string s) {

Console.WriteLine(s);

}

public void Prop2(string name, int val) {

Console.WriteLine("name = {0}, val ={1}", name, val);

}

}

 

Другая стратегия реализации состоит в том, чтобы некоторые методы интерфейса сделать закрытыми. Для реализации этой стратегии класс, наследующий интерфейс, объявляет методы без модификатора доступа, что по умолчанию соответствует модификатору private, и уточняет имя метода именем интерфейса:

public class ClainP:IProps{

public ClainP(){ }

void IProps.Prop1(string s) {

Console.WriteLine(s);

}

void IProps.Prop2(string name, int val) {

Console.WriteLine("name = {0}, val ={1}", name, val);

}

}

Есть два способа получения доступа к закрытым методам:

· Обертывание. Создается открытый метод, являющийся оберткой закрытого метода.

· Кастинг. Создается объект интерфейсного класса IProps, полученный преобразованием (кастингом) объекта исходного класса ClainP. Этому объекту доступны закрытые методы интерфейса.

Вот пример обертывания закрытых методов в классе ClainP:

public void MyProp1(string s){

((IProps)this).Prop1(s);

}

public void MyProp2(string s, int x){

((IProps)this).Prop2(s, x);

}

Как видите, методы переименованы и получили другие имена, под которыми они и будут известны клиентам класса. В обертке для вызова закрытого метода пришлось использовать кастинг, приведя объект this к интерфейсному классу IProps.

 

Преобразование к классу интерфейса

Создать объект класса интерфейса обычным путем с использованием конструктора и операции new нельзя, но можно объявить объект интерфейсного класса и связать его с настоящим объектом путем приведения (кастинга) объекта наследника к классу интерфейса. Это преобразование задается явно. Имея объект, можно вызывать методы интерфейса - даже если они закрыты в классе, для интерфейсных объектов они являются открытыми.

public void TestClainIProps(){

Console.WriteLine("Объект класса Clain вызывает открытые методы!");

Clain clain = new Clain();

clain.Prop1(" свойство 1 объекта");

clain.Prop2("Владимир", 44);

Console.WriteLine("Объект класса IProps вызывает открытые методы!");

IProps ip = (IProps)clain;

ip.Prop1("интерфейс: свойство");

ip.Prop2 ("интерфейс: свойство",77);

Console.WriteLine("Объект класса ClainP вызывает открытые методы!");

ClainP clainp = new ClainP();

clainp.MyProp1(" свойство 1 объекта");

clainp.MyProp2("Владимир", 44);

Console.WriteLine("Объект класса IProps вызывает закрытые методы!");

IProps ipp = (IProps)clainp;

ipp.Prop1("интерфейс: свойство");

ipp.Prop2 ("интерфейс: свойство",77);

}

 

Проблемы множественного наследования

При множественном наследовании классов возникает ряд проблем. Они остаются и при множественном наследованииинтерфейсов, хотя становятся проще. Рассмотрим две основные проблемы - коллизию имен и наследование от общего предка.

Коллизия имен

Проблема коллизии имен возникает, когда два или более интерфейса имеют методы с одинаковыми именами и сигнатурой. Здесь возможны две стратегии - склеивание методови переименование .

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

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

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

 

// Программа 5. Коллизии имен в интерфейсах

public interface IProps{

void Prop1(string s);

void Prop2 (string name, int val);

void Prop3();

}

public interface IPropsOne{

void Prop1(string s);

void Prop2 (int val);

void Prop3();

}

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

public class ClainTwo:IProps,IPropsOne {

// склеивание методов двух интерфейсов

public void Prop1 (string s) {

Console.WriteLine(s);

}

// перегрузка методов двух интерфейсов

public void Prop2(string s, int x) {

Console.WriteLine(s + "; " + x);

}

public void Prop2 (int x) {

Console.WriteLine(x);

}

// private реализация и переименование методов двух интерфейсов

void IProps.Prop3() {

Console.WriteLine("Метод 3 интерфейса 1");

}

void IPropsOne.Prop3() {

Console.WriteLine("Метод 3 интерфейса 2");

}

public void Prop3FromInterface1() {

((IProps)this).Prop3();

}

public void Prop3FromInterface2() {

((IPropsOne)this).Prop3();

}

}

public void TestCliTwoInterfaces(){

Console.WriteLine("Объект сlainTwo вызывает методы двух интерфейсов!");

ClainTwo claintwo = new ClainTwo();

claintwo.Prop1("Склейка свойства двух интерфейсов");

claintwo.Prop2("перегрузка.: ",99);

claintwo.Prop2(9999);

claintwo.Prop3FromInterface1();

claintwo.Prop3FromInterface2();

Console.WriteLine("Интерфейсный объект вызывает методы 1-го интерфейса!");

IProps ip1 = (IProps)claintwo;

ip1.Prop1("интерфейс IProps: свойство 1");

ip1.Prop2("интерфейс 1 ", 88);

ip1.Prop3();

Console.WriteLine("Интерфейсный объект вызывает методы 2-го интерфейса!");

IPropsOne ip2 = (IPropsOne)claintwo;

ip2.Prop1("интерфейс IPropsOne: свойство1");

ip2.Prop2(7777);

ip2.Prop3();

}

 


Понравилась статья? Добавь ее в закладку (CTRL+D) и не забудь поделиться с друзьями:  



double arrow
Сейчас читают про: