Сдам Сам

ПОЛЕЗНОЕ


КАТЕГОРИИ







Пример работы с полиморфным семейством классов





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

public void TestFoundDerivedReal(){ Found bs = new Found ("father", 777); Console.WriteLine("Объект bs вызывает методы класса Found"); bs.VirtMethod(); bs.NonVirtMethod(); bs.Analysis(); bs.Work(); Derived der = new Derived("child", 888, 555); Console.WriteLine("Объект der вызывает методы класса Derived"); der.DerivedMethod(); der.VirtMethod(); der.NonVirtMethod(); der.Analysis(); der.Work(); ChildDerived chider = new ChildDerived("grandchild", 999, 444); Console.WriteLine("Объект chider вызывает методы ChildDerived"); chider.VirtMethod(); chider.NonVirtMethod(); chider.Analysis(5); chider.Work();}

Результаты работы этого метода изображены на рис. 18.3.


Рис. 18.3. Полиморфизм семейства классов

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

Абстрактные классы

С наследованием тесно связан еще один важный механизм проектирования семейства классов - механизм абстрактных классов. Начну с определений.

Класс называется абстрактным, если он имеет хотя бы один абстрактный метод.

Метод называется абстрактным, если при определении метода задана его сигнатура, но не задана реализация метода.

Объявление абстрактных методов и абстрактных классов должно сопровождаться модификатором abstract. Поскольку абстрактные классы не являются полностью определенными классами, то нельзя создавать объекты абстрактных классов. Абстрактные классы могут иметь потомков, частично или полностью реализующих абстрактные методы родительского класса. Абстрактный метод чаще всего рассматривается как виртуальный метод, переопределяемый потомком, поэтому к ним применяется стратегия динамического связывания.

Абстрактные классы являются одним из важнейших инструментов объектно-ориентированного проектирования классов. К сожалению, я не могу входить в детали рассмотрения этой важной темы и ограничусь лишь рассмотрением самой идеи применения абстрактного класса. В основе любого класса лежит абстракция данных. Абстрактный класс описывает эту абстракцию, не входя в детали реализации, ограничиваясь описанием тех операций, которые можно выполнять над данными класса. Так, проектирование абстрактного класса Stack, описывающего стек, может состоять из рассмотрения основных операций над стеком и не определять, как будет реализован стек - списком или массивом. Два потомка абстрактного класса - ArrayStack и ListStack могут быть уже конкретными классами, основанными на различных представлениях стека.

Вот описание полностью абстрактного класса Stack:

public abstract class Stack{ public Stack() {} /// <summary> /// втолкнуть элемент item в стек /// </summary> /// <param name="item"></param> public abstract void put(int item); /// <summary> /// удалить элемент в вершине стека /// </summary> public abstract void remove(); /// <summary> /// прочитать элемент в вершине стека /// </summary> public abstract int item(); /// <summary> /// определить, пуст ли стек /// </summary> /// <returns></returns> public abstract bool IsEmpty();}

Описание класса содержит только сигнатуры методов класса и их спецификацию, заданную тегами <summary>. Построим теперь одного из потомков этого класса, реализация которого основана на списковом представлении. Класс ListStack будет потомком абстрактного класса Stack и клиентом класса Linkable, задающего элементы списка. Класс Linkable выглядит совсем просто:

public class Linkable{ public Linkable() { } public int info; public Linkable next;}

В нем - два поля и конструктор по умолчанию. Построим теперь класс ListStack:

public class ListStack: Stack{ public ListStack() { top = new Linkable(); } Linkable top; /// <summary> /// втолкнуть элемент item в стек /// </summary> /// <param name="item"></param> public override void put(int item) { Linkable newitem = new Linkable(); newitem.info = item; newitem.next = top; top = newitem; } /// <summary> /// удалить элемент в вершине стека /// </summary> public override void remove() { top = top.next; } /// <summary> /// прочитать элемент в вершине стека /// </summary> public override int item() { return(top.info); } /// <summary> /// определить, пуст ли стек /// </summary> /// <returns></returns> public override bool IsEmpty() { return(top.next == null); }}

Класс имеет одно поле top класса Linkable и методы, наследованные от абстрактного класса Stack. Теперь, когда задано представление данных, нетрудно написать реализацию операций. Реализация операций традиционна для стеков и, надеюсь, не требует пояснений.

Приведу пример работы со стеком:

public void TestStack(){ ListStack stack = new ListStack(); stack.put(7); stack.put(9); Console.WriteLine(stack.item()); stack.remove(); Console.WriteLine(stack.item()); stack.put(11); stack.put(13); Console.WriteLine(stack.item()); stack.remove(); Console.WriteLine(stack.item()); if(!stack.IsEmpty()) stack.remove(); Console.WriteLine(stack.item());}

В результате работы этого теста будет напечатана следующая последовательность целых: 9, 7, 13, 11, 7.

Классы без потомков

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

Интерфейсы

Слово "интерфейс" многозначное и в разных контекстах оно имеет различный смысл. В данной лекции речь идет о понятии интерфейса, стоящем за ключевым словом interface. В таком понимании интерфейс - это частный случай класса. Интерфейс представляет собой полностью абстрактный класс, все методы которого абстрактны. От абстрактного класса интерфейс отличается некоторыми деталями в синтаксисе и поведении. Синтаксическое отличие состоит в том, что методы интерфейса объявляются без указания модификатора доступа. Отличие в поведении заключается в более жестких требованиях к потомкам. Класс, наследующий интерфейс, обязан полностью реализовать все методы интерфейса. В этом - отличие от класса, наследующего абстрактный класс, где потомок может реализовать лишь некоторые методы родительского абстрактного класса, оставаясь абстрактным классом. Но, конечно, не ради этих отличий были введены интерфейсы в язык C#. У них значительно более важная роль.

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

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

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







Что способствует осуществлению желаний? Стопроцентная, непоколебимая уверенность в своем...

Что вызывает тренды на фондовых и товарных рынках Объяснение теории грузового поезда Первые 17 лет моих рыночных исследований сводились к попыткам вычис­лить, когда этот...

ЧТО И КАК ПИСАЛИ О МОДЕ В ЖУРНАЛАХ НАЧАЛА XX ВЕКА Первый номер журнала «Аполлон» за 1909 г. начинался, по сути, с программного заявления редакции журнала...

Система охраняемых территорий в США Изучение особо охраняемых природных территорий(ООПТ) США представляет особый интерес по многим причинам...





Не нашли то, что искали? Воспользуйтесь поиском гугл на сайте:


©2015- 2024 zdamsam.ru Размещенные материалы защищены законодательством РФ.