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

Содержание

Слайд 2

Интерфейсы Интерфейс (interface) – соглашение, определяющее поведение объекта. В нем задается

Интерфейсы

Интерфейс (interface) – соглашение, определяющее поведение объекта.
В нем задается набор

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

Синтаксис объявления интерфейса: [ атрибуты ] [ спецификаторы ] interface имя

Синтаксис объявления интерфейса:

[ атрибуты ] [ спецификаторы ] interface имя [

: предки ]
тело_интерфейса [ ; ]
Пример:
class Человек : IОбразованный, IВодитель
interface IОбразованный {Читат(); Писать();}
interface IВодитель {Завести(); Повернуть(); Затормозить()}
Слайд 4

Общие сведения об интерфейсе Интерфейс может наследовать свойства нескольких интерфейсов, в

Общие сведения об интерфейсе

Интерфейс может наследовать свойства нескольких интерфейсов, в

этом случае предки перечисляются через запятую.
Тело интерфейса составляют абстрактные методы, шаблоны свойств и индексаторов, а также события.
Интерфейс не может содержать константы, поля, операции, конструкторы, деструкторы, типы и любые статические элементы.
Слайд 5

Выбор между интерфейсом и наследованием Если некий набор действий имеет смысл

Выбор между интерфейсом и наследованием

Если некий набор действий имеет смысл только

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

Отличие интерфейса и абстрактного класса элементы интерфейса по умолчанию имеют спецификатор

Отличие интерфейса и абстрактного класса

элементы интерфейса по умолчанию имеют спецификатор доступа

public и не могут иметь спецификаторов, заданных явным образом;
интерфейс не может содержать полей и обычных методов — все элементы интерфейса должны быть абстрактными;
класс, в списке предков которого задается интерфейс, должен определять все его элементы, в то время как потомок абстрактного класса может не переопределять часть абстрактных методов предка (в этом случае производный класс также будет абстрактным);
класс может иметь в списке предков несколько интерфейсов, при этом он должен определять все их методы.
Слайд 7

Реализация интерфейса В C# поддерживается одиночное наследование для классов и множественное

Реализация интерфейса

В C# поддерживается одиночное наследование для классов и множественное — для

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

Пример interface IPlayer. // Интерфейс Игрок, //наследующие классы реализуют его по

Пример

interface IPlayer. // Интерфейс Игрок,
//наследующие классы реализуют его по разному:
   {
      void

play();
   }
   public class Ball: IPlayer
   {
      public void play()
      {
         Console.WriteLine("Игра в мяч");
      }
   }
Слайд 9

public class Guitar: IPlayer { public void play() { Console.WriteLine("Игра на гитаре"); } }

 public class Guitar: IPlayer
   {
      public void play()
      {
         Console.WriteLine("Игра на гитаре");
      }
   }

Слайд 10

Неявная реализация интерфейса interface IPlayer{ void play(); } class Ball: Iplayer{

Неявная реализация интерфейса

interface IPlayer{
void play();
}
class Ball: Iplayer{
public void play(){……..}; //

обязательно public!
}
Слайд 11

Явная реализация интерфейса class Ball: IPlayer{ void Iplayer. play() {…………….} //тут

Явная реализация интерфейса

class Ball: IPlayer{
void Iplayer. play() {…………….}
//тут спецификатор

public отсутствует, потому что попытка написать тут public карается
};
Слайд 12

При явной реализации вызов возможен лишь при явном приведении. Явная реализация

При явной реализации вызов возможен лишь при явном приведении.
Явная реализация интерфейса

означает, что вызов метода
интерфейса может происходить только через ссылку на интерфейс, но не может происходить через ссылку на класс, реализующий интерфейс.
Перед вызовом интерфейсного метода необходимо явно преобразовать ссылку на объект реализующего класса к ссылке на интерфейс. Концепция явной реализации полезна, например, при конфликте имен между унаследованными
интерфейсами.
В C# реализованные методы интерфейсов считаются по умолчанию «sealed» - запечатанными. В наследниках они перекрываются.
Слайд 13

Пример явной реализации интерфейса interface I1 { void Method(); } interface

Пример явной реализации интерфейса

interface I1
{
void Method();
}
interface I2

{
int Method();
}
class Test : I1, I2
{
public void Method()
{
Console.WriteLine("Реализация интерфейса I1");
}
Слайд 14

int I2.Method() // РЕАЛИЗУЕМ интерфейс явно { Console.WriteLine("Реализация интерфейса I2"); return

int I2.Method() // РЕАЛИЗУЕМ интерфейс явно
{
Console.WriteLine("Реализация интерфейса I2");

return 5;
}
}
class Program
{
static void Main(string[] args)
{
Test t = new Test();
t.Method();// реализация метода I1.Method() в классе Test ((I1)t).Method();// реализация метода I1.Method() в классе Test ((I2)t).Method();// реализация метода I2.Method() в классе Test
} // приводим к типу интерфейса явно реализованному
}// наш объект класса Test
}
Слайд 15

Результат работы программы

Результат работы программы

Слайд 16

Операция is При работе с объектом через объект типа интерфейса бывает

Операция is

При работе с объектом через объект типа интерфейса бывает необходимо

убедиться, что объект поддерживает данный интерфейс.
Проверка выполняется с помощью бинарной операции is. Она определяет, совместим ли текущий тип объекта, находящегося слева от ключевого слова is, с типом, заданным справа.
Результат операции равен true, если объект можно преобразовать к заданному типу, и false в противном случае. Операция обычно используется в следующем контексте:
if ( объект is тип )
{
// выполнить преобразование "объекта" к "типу"
// выполнить действия с преобразованным объектом
}
Слайд 17

Операция as Используется для проверки поддерживает ли данный тип тот или

Операция as

Используется для проверки поддерживает ли данный тип тот или иной

интерфейс, если да, то операция as выполняет преобразование к заданному типу, а если это невозможно, формирует результат null:
static void Act( object A )
{
IAction Actor = A as IAction;
if ( Actor != null ) Actor.Draw();
}
Обе рассмотренные операции применяются как к интерфейсам, так и к классам.
Слайд 18

Итоги Интерфейсы на С# обеспечивают разработку классов, у которых могут быть

Итоги

Интерфейсы на С# обеспечивают разработку классов, у которых могут быть общие

функции, но при этом они не являются частями одной и той же иерархии классов. Интерфейсы играют особую роль в разработке на С#, поскольку С# не поддерживает множественное наследование. Чтобы совместно использовать методы и свойства, классы могут реализовывать несколько интерфейсов. Операторы is и asпозволяют определить, реализован ли конкретный интерфейс конкретным объектом, что помогает предотвратить ошибки, связанные с использованием членов интерфейса. Наконец, явное именование членов и сокрытие имен позволяют управлять реализацией интерфейса и избежать многих ошибок.
Слайд 19

Пример public interface Apartment { double Area{get; set;} void GetInfo(); }

Пример

public interface Apartment
{
double Area{get; set;}
void GetInfo();
}

Слайд 20

public class ThreeRoom: Apartment { private double area; //площадь public int

public class ThreeRoom: Apartment
{
private double area; //площадь
public

int Area
{
get
{ return area;
}
set
{ area = value;
}
}
public void GetInfo()
{
Console.WriteLine("Это трехкомнатная квартира”);
}
}
Слайд 21

public interface Luxury { int Price{get; set;} void GetInfo(); }

public interface Luxury
{
int Price{get; set;}
void GetInfo();
}

Слайд 22

public class SuperThree: ThreeRoom, Apartment, Luxury { private double area; //

public class SuperThree: ThreeRoom, Apartment, Luxury
{
private double area; //

private int price; //цена
public double Area
{
get
{
return area;
}
set
{
area = value;
}
}
public void GetInfo()
{
Console.WriteLine("Это роскошная 3-х комнатная квартира".);
}
public int Price
{
get
{
return price;
}
set
{
price = value;
}
}
}
Слайд 23

void ThreeRoom.GetInfo() { Console.WriteLine("Это квартира".); } void Apartment.GetInfo() { Console.WriteLine("Эта квартира стоит кучу денег!".); }

void ThreeRoom.GetInfo()
{
Console.WriteLine("Это квартира".);
}
void Apartment.GetInfo()
{
Console.WriteLine("Эта квартира

стоит кучу денег!".);
}
Слайд 24

static void Main(string[] args) { SuperThree ob = new SuperThree(); ob.Price

static void Main(string[] args)
{
SuperThree ob = new SuperThree();

ob.Price = 1000000;
ob.Area = 450;
if (ob is Apartment)
{
Apartment tmp = (Apartment)ob;
tmp.GetInfo();
}
if (ob is Luxury)
{
Luxury tmp2 = (Luxury)ob;
tmp2.GetInfo();
}
Console.ReadLine();
}
Слайд 25

Использование стандартных интерфейсов Рассмотрим интерфейс ICloneable Если объект реализует данный интерфейс,

Использование стандартных интерфейсов

Рассмотрим интерфейс ICloneable

Если объект реализует данный интерфейс, значит его

(объект) можно копировать.
IEnumerable, IEnumerator- дают возможность простамтривать содержимое объекта с помощью конструкции foreach.
Массивы в C# работают с foreach благодаря тому что тип Array реализует интерфейсы IEnumerable, IEnumerator.
interface Icomparable
{
int ComparTo(object);
}
Слайд 26

class Money:ICloneable, IComparable { int som; public Money() { som =

class Money:ICloneable, IComparable
{
int som;
public Money()
{
som =

0;
}
public Money(int s)
{
som = s;
}
Слайд 27

using System; using System.Collections.Generic; using System.Linq; using System.Text; namespace ForLecture {

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace ForLecture
{
public int Som
{
set{som=value;}

get{return som;}
}
public override string ToString()
{
return som.ToString();
}
public object Clone()
{
return new Money(this.Som);
}
Слайд 28

int IComparable.CompareTo(object o) { Money tmp = (Money)o; if (this.som >

int IComparable.CompareTo(object o)
{
Money tmp = (Money)o;
if (this.som >

tmp.som) return 1;
if (this.som == tmp.som)
return 0;
else
return -1;
}
}
Слайд 29

class Program { static void Main(string[] args) { Console.WriteLine("Исходные данные"); Money

class Program
{
static void Main(string[] args)
{
Console.WriteLine("Исходные данные");
Money

ob1=new Money(100);
Console.WriteLine(ob1);
Money ob2 = new Money(200);
Console.WriteLine(ob2);
ob2 = (Money)ob1.Clone();
Слайд 30

Console.WriteLine("После клонирования"); Console.WriteLine(ob1); Console.WriteLine(ob2); Console.WriteLine("Изменяем свойства ob2.Som=500 "); ob2.Som = 500; Console.WriteLine(ob1); Console.WriteLine(ob2);

Console.WriteLine("После клонирования");
Console.WriteLine(ob1);
Console.WriteLine(ob2);
Console.WriteLine("Изменяем свойства ob2.Som=500 ");
ob2.Som = 500;
Console.WriteLine(ob1);

Console.WriteLine(ob2);
Слайд 31

Console.WriteLine("Изменяем свойства ob1.Som=500 ob2.Som=1500 "); ob1.Som = 500; ob2.Som = 1500; Console.WriteLine(ob1); Console.WriteLine(ob2); } } }

Console.WriteLine("Изменяем свойства ob1.Som=500 ob2.Som=1500 ");
ob1.Som = 500;
ob2.Som =

1500;
Console.WriteLine(ob1);
Console.WriteLine(ob2);
}
}
}
Слайд 32

Использование реализации интерфейса IComparable Console.WriteLine(" Массив объектов до сортировки"); Money[] mas


Использование реализации интерфейса IComparable
Console.WriteLine(" Массив объектов до сортировки");
Money[] mas

= new Money[4];
mas[0] = new Money(4000);
mas[1] = new Money(2000);
mas[2] = new Money(5000);
mas[3] = new Money(1000);
for (int i = 0; i < 4; i++)
Console.WriteLine(mas[i]);
Array.Sort(mas);
Console.WriteLine("Сортировка массива объектов");
for (int i = 0; i < 4; i++)
Console.WriteLine(mas[i]);
Console.ReadLine();
Слайд 33

class Money:ICloneable { int som; int key; public Money() { som

class Money:ICloneable
{
int som;
int key;
public Money()
{
som =

0;

public int CompareTo(Money o)
{
return key-o.key;
}
}
static void Main(string[] args)
{
List list=new List();
for(int i=0;i<10;i++)
list.Add(new Money());
………..
list.Sort();
}
Слайд 34

Клонирование объектов Клонирование – создание копии объекта. Копия объекта называется клоном

Клонирование объектов
Клонирование – создание копии объекта.
Копия объекта называется клоном
Виды клонирования
При

присваивании одного объекта ссылочного типа другому копируется
ссылка, а не сам объект.
Если необходимо скопировать в другую область памяти поля объекта, можно
Воспользоваться методом MemberwiseClone, который объект наследует от
kласса object. При этом объекты, на которые указывают поля объекта, в свою
Очередь являющиеся ссылками, не копируются. Это называется поверхностным
Клонированием.
Для создания полностью независимых объектов необходимо глубокое клонирование,
Когда в памяти создается дубликат всего дерева объектов.
Алгоритм глубокого клонирования является достаточно сложным, поскольку требует
рекурсивного обхода всех ссылок объекта и отслеживания циклических зависимостей.
Объект, имеющий собственные алгоритмы клонирования, должен объявляться как
наследник интерфейса IClonable и переопределять его единственныый метод Clone.