Объектно-ориентированное программирование. Язык C#

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

Рубрика Программирование, компьютеры и кибернетика
Вид статья
Язык русский
Дата добавления 02.04.2021
Размер файла 318,6 K

Отправить свою хорошую работу в базу знаний просто. Используйте форму, расположенную ниже

Студенты, аспиранты, молодые ученые, использующие базу знаний в своей учебе и работе, будут вам очень благодарны.

Размещено на http://www.allbest.ru

Размещено на http://www.allbest.ru

Объектно-ориентированное программирование. Язык C#

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

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

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

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

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

После принятия решения о представлении конкретных типов данных это представление может применяться в последующих версиях данного приложения и даже в совершенно новых приложениях. Наличие подобного соглашения может значительно сократить время разработки. Этим можно объяснить пример с гоночным автомобилем, где таким соглашением является структурирование кода «двигателя», который позволяет легко подставлять новый код (новый двигатель), не возвращая его изготовителю. Помимо этого, двигатель после создания можно использовать и для других целей - например, в другом автомобиле или вовсе в подводной лодке.

Как видно из названия этой технологии, достигается это все с помощью объектов.

Что такое объект

Объект- это «строительный блок» в ООП-приложении. Такой строительный блок инкапсулирует часть приложения - процесс, порцию данных или какой-то более абстрактный объект.

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

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

Объекты в языке C# создаются из типов, как и хорошо знакомые составные переменные. Для типа объекта в ООП имеется специальное название -класс. Определения классов позволяют создавать объекты - т.е. реальные именованные экземпляры класса. Понятия «экземпляр класса» и «объект» эквивалентны.

важно понимать,

чем они отличаются термины «класс» и «объект». Помочь в этом может аналогия с гоночным автомобилем. Классом можно считать чертежи для изготовления автомобиля, а объектом -сам автомобиль, сделанный по этим чертежам.

Для работы с классами и объектами может использоваться язык UML (Unified Modeling Language -- унифицированный язык моделирования). Этот язык был специально разработан для моделирования программных систем -- от объектов, из которых они состоят, и операций, которые они выполняют, до предполагаемых способов их использования.

На рисунке для примера показано UML-представление класса принтера по имени Printer. Имя класса записано в самом верхнем разделе данного прямоугольника.

Рис. 1

Далее показано UML-представление экземпляра данного класса Printer по имени myPrinter.

Здесь в верхнем разделе записано имя экземпляра, а за ним, через двоеточие, имя его класса.

myPrinter : Printer

Рис. 2

Свойства и поля

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

Различные фрагменты содержащихся в объекте данных вместе образуют состояние этого объекта.

Например, пусть имеется класс объектов, представляющий чашку кофе и потому имеющий имя CupOfCoffee. При создании экземпляра (т.е. объекта) этого класса необходимо обеспечить его состояние, чтобы он был осмысленным. Для этого использующий данный объект код может с помощью свойств и полей задать сорт используемого кофе, содержится ли в кофе молоко и/или сахар, является ли кофе быстрорастворимым и т.д.Тогда каждый конкретный объект CupOfCofee будет иметь определенное состояние, например: «Чашка колумбийского кофе с молоком и двумя кусочками сахара».

Поля и свойства имеют типы, поэтому информация может в них храниться в виде значений string, int и т.д. Свойства отличаются от полей тем, что они не предоставляют непосредственный доступ к данным. Объекты могут ограждать пользователей от внутренних деталей своих данных, которые не обязательно взаимно однозначно представлены в существующих свойствах. Скажем, в поле для хранения информации о количестве кусочков сахара в экземпляре CupOfCoffee пользователи смогут помещать любые значения, ограниченные лишь пределами типа этого поля. То есть, например, в случае использования для хранения этих данных типа int пользователи смогут помещать в это поле любое значение в диапазоне от -2 147 483 648 до 2 147 483 647. Очевидно, что не все такие значения будут иметь смысл, особенно отрицательные, да и для слишком больших положительных может понадобиться чашка необычайно больших размеров. Использование свойства для хранения этой информации легко позволяет ограничить данное значение, скажем, только числами от 0 до 2.

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

Объект может четко определять и тип доступа к свойствам (для чтения и/или для записи). Некоторые свойства могут быть доступными только для чтения, т.е. они позволяют узнать их значения, но не изменять их (по крайней мере, непосредственно). Это часто бывает удобно для одновременного считывания нескольких фрагментов состояния. Например, класс CupOfCoffee может иметь доступное только для чтения свойство по имени Description (Описание), возвращающее строку с полной информацией о состоянии экземпляра этого класса. Конечно, эти сведения можно собрать и путем опроса нескольких свойств, но наличие такого свойства может сэкономить время и усилия. Аналогично ведут себя и свойства, доступные только для записи.

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

Доступность немного похожа на область видимости переменных. Например, приватные поля и свойства можно считать локальными для объекта, который ими владеет, а область видимости общедоступных полей и свойств охватывает и внешний для объекта код.

В UML-представлении класса имена свойств и полей отображаются во втором разделе, как показано на рисунке.

Рис. 3

На этом рисунке показано UML-представление класса CupOfCoffee, в котором определены пять членов (свойства или поля, поскольку в UML между ними нет никакой разницы). В каждой строке содержится следующая информация;

· доступность. Общедоступные члены помечены символом «+», а приватные - символом «-»;

· имя члена;

· тип члена.

Имена членов и их типы разделяются двоеточием.

Методы

Термином метод принято называть предоставляемую объектом функцию. Методы могут вызываться так же, как и любые другие функции, и так же возвращать значения и принимать параметры.

Методы применяются для доступа к функциональным возможностям объекта. Подобно полям и свойствам, они могут быть общедоступными или приватными, ограничивая при необходимости доступ к ним из внешнего кода. Нередко методы используют в своих действиях состояние объекта и обращаются к приватным членам. Например, в классе CupOfCoffee может быть определен метод AddSugar(), предоставляющий более понятный синтаксис для увеличения количества сахара, чем действия с соответствующим свойством Sugar.

В UML-представлении методы классов отображаются в третьем разделе прямоугольников.

Рис. 4

Синтаксис записи методов в UML похож на синтаксис полей и свойств, только дополнительно записываются параметры методов, а тип в конце означает возвращаемый тип.

Каждый параметр отображается в UML с одним из следующих идентификаторов: in, outили inout. Они обозначают направление потока данных, причем out и inout примерно соответствуют ключевым словам out и ref в языке C#, а in - стандартному поведению в языке C#, когда не указаны ни out, ни ref.

В языке C# и .NET Frameworkобъектом является все, что угодно.

Функция Main() в консольном приложении является методом класса. Каждый из типов переменных является классом. Каждая из команд, наподобие <строка>.Length, <строка>.ToUpper() и т.д. - это свойство или метод. (Символ точки здесь отделяет имя экземпляра объекта от имени свойства или метода; методы отличаются от свойств наличием скобок после них.)

Объекты встречаются повсюду, а синтаксис их использования обычно очень прост.

Жизненный цикл объекта

Каждый объект имеет четко определенный жизненный цикл. Помимо обычного состояния - использование объекта - этот жизненный цикл включает два важных этапа.

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

Уничтожение. При уничтожении объекта часто требуется выполнить какие-либо операции по зачистке, вроде освобождения памяти. За их выполнение отвечает функция-деструктор, которую часто называют просто деструктором.

Конструкторы

Простая инициализация объекта осуществляется автоматически. Например, не нужно подыскивать место в памяти для размещения нового объекта. Однако иногда бывает необходимо выполнить на этапе инициализации объекта дополнительные задачи - например, инициализировать хранимые в объекте данные. Для этого применяется конструктор.

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

В языке C# конструкторы вызываются с помощью ключевого слова new. К примеру, создать экземпляр объекта CupOfCoffee с помощью конструктора по умолчанию можно следующим образом:

CupOfCoffee myCup = new CupOfCoffee();

Объекты можно создавать и с помощью конструкторов, отличных от конструктора по умолчанию. Например, у класса CupOfCoffee может существовать такой конструктор, принимающий параметр для указания типа кофейных зерен:

CupOfCoffee myCup = new CupOfCoffee("Blue Mountain");

Конструкторы, подобно полям, свойствам и методам, могут быть общедоступными или приватными. Код, внешний по отношению к классу, не может создавать объекты с помощью приватного конструктора; он должен обязательно использовать общедоступный конструктор. Так можно, например, заставить пользователей классов применять конструктор, отличный от конструктора по умолчанию (сделав конструктор по умолчанию приватным).

Некоторые классы не имеют общедоступных конструкторов, т.е. создавать их экземпляры из внешнего кода невозможно (такие классы называются не создаваемыми).

Деструкторы

Деструкторы используются в .NET Framework для выполнения очистки при удалении объектов. Обычно какой-то особый код для деструктора не требуется; все, что нужно, делается автоматически. Однако можно добавить и специальные действия, если перед удалением объекта необходимо выполнять какие-либо важные операции. Например, после выхода переменной из области видимости она может быть не доступной из кода, но по-прежнему существовать где-то в памяти. Только при выполнении средой.NET сборки мусора такой экземпляр уничтожается полностью.

Статические члены классов и члены экземпляров классов

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

Например, статическими являются методы Console.WriteLine() и Convert.ToString(). Создавать экземпляры классов Console и Convert для них не нужно (да это и невозможно, т.к. конструкторы этих классов не являются общедоступными, как описывалось ранее).

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

Рис. 5

Статические конструкторы

Для применения статических членов класса может понадобиться сначала инициализировать их. Конечно, для статического члена можно указать начальное значение прямо в объявлении, но иногда нужна более сложная инициализация или, возможно, какие-то другие операции перед присваиванием значений или выполнением статических методов.

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

· при создании экземпляра класса, содержащего данный статический конструктор;

· при обращении к статическому члену класса, содержащему данный статический конструктор.

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

Статические классы

Часто бывает нужно использовать классы, содержащие только статические члены, для которых невозможно создавать объекты (вроде класса Console). Проще всего не делатьвсе конструкторы класса приватными, а использовать статический класс. Статический класс может содержать только статические члены и по своей сути не может содержать конструкторы экземпляров. Однако в нем могут быть статические конструкторы, как было сказано в предыдущем разделе.

Приемы объектно-ориентированного программирования

Интерфейсы

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

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

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

В приведенном ранее примере класса CupOfCoffee многие свойства и методы более общего назначения, вроде AddSugar(), Milk, Sugar и Instant, можно сгруппировать интерфейс с именем, скажем, IHotDrink (имена интерфейсов обычно начинаются с заглавной буквы I). Такой интерфейс можно применять для других объектов, например, объектов класса CupOfTea. Это позволило бы однотипно работать со всеми подобными объектами, хотя они могут иметь и собственные свойства (например, объекты CupOfCoffee - свойство BeanType, а объекты CupOfTea - свойство LeafType).

Интерфейсы, реализуемые для классов, изображаются в UML с помощью кружочков. На рисунке классы, реализующие интерфейс IHotDrink, вынесены в отдельный прямоугольник.

Рис. 6

Один класс может поддерживать несколько интерфейсов, а несколько классов могут поддерживать один и тот же интерфейс. Значит, интерфейсы упрощают жизнь для пользователей и других разработчиков. Например, предположим, что имеется код, в котором используется объект с определенным интерфейсом. Если не использовать другие свойства и методы этого объекта, один объект можно будет легко заменять другим (код из примера с интерфейсом IHotDrink, например, может работать как с экземплярами CupOfCoffee, так и с экземплярами CupOfTea). Кроме того, разработчик данного класса сам может выпустить его обновленную версию, и если она поддерживает уже используемый интерфейс, другой разработчик сможет легко применить новую версию в своем коде.

После публикации интерфейса, т.е. предоставления к нему доступа другим разработчикам или конечным пользователям, лучше не изменять его. Интерфейс можно считать своего рода контрактом между создателями класса и его потребителями, в котором создатели заявляют, что каждый класс, реализующий интерфейс X, будет поддерживать такие-то методы и свойства. Если интерфейс позже изменится - например, из-за обновления базового кода - экземпляры классов будут работать неправильно или вообще не смогут работать. Поэтому вместо этого рекомендуется создавать новый интерфейс, расширяющий возможности старого и имеющий другой номер версии, вроде X2. Такой подход уже стал стандартным, поэтому интерфейсы с пронумерованными версиями встречаются довольно часто.

Освобождаемые объекты

Один из интерфейсов особенно интересен - это интерфейс IDisposable. Объект, поддерживающий этот интерфейс, должен реализовать метод Dispose(), т.е. предоставить код для этого метода. Dispose() может вызываться тогда, когда объект уже больше не нужен (например, непосредственно перед его выходом за пределы области видимости),и должен использоваться для освобождения любых критических ресурсов, которые в противном случае могут оставаться занятыми вплоть до вызова метода деструктора во время сборки мусора. Это обеспечивает больший контроль над ресурсами, которыми пользуются объекты.

В языке C# имеется конструкция специально для эффективного применения этого метода.

Ключевое слово using позволяет инициализировать использующий критические ресурсы объект в кодовом блоке, при достижении конца которого автоматически вызывается метод Dispose():

<имяКласса><имяПеременной> = new <имяКласса>();

...

using (<имяПеременной>)

{

...

}

Объект <имяПеременной> можно создать и в составе оператора using:

using (<имяКласса><имяПеременной> = new <имяКласса>)

{

...

}

программирование процедурный интерфейс код

И в том, и в другом случае переменная <имяПеременной> будет доступна внутри блока using и автоматически удалена в его конце (т.е. по завершении выполнения кода этого блока будет автоматически вызван метод Dispose()).

Наследование

Наследование (inheritance) - один из самых важных механизмов в ООП. Любой класс может наследоваться от другого класса, а это значит, что он будет иметь все те члены, что и класс, от которого он унаследован. В терминологии ООП класс, от которого наследуется(порождается) другой класс, называется родительским или базовым классом. Классы в C# могут непосредственно наследоваться только от одного базового класса, хотя у того базового класса может быть собственный базовый класс и т.д.

Механизм наследования позволяет расширять или создавать конкретные классы от одного более общего базового класса. Например, возьмем класс, представляющий животное с фермы. Этот класс мог бы называться Animal (Животное) и обладать методами вроде EatFood() (Питаться) или Breed() (Плодиться). От него можно создать производный класс по имени Cow (Корова), который поддерживает все эти методы, но при этом имеет и собственные - например, Moo() (Мычать) и SupplyMilk() (Давать молоко). Другим производным классом может быть класс Chicken (Курица) с методами Cluck() (Кудахтать) иLayEgg() (Снести яйцо).

В UML наследование изображается стрелками.

Рис. 7

На рисунке возвращаемые типы членов для простоты не показаны.

При порождении от базового класса становится важным вопрос о доступности членов. Приватные члены базового класса недоступны из производного класса, а общедоступные(естественно) доступны. Но общедоступные члены доступны не только из производного класса, но и из внешнего кода. Поэтому если использовать только два этих уровня доступности, то невозможно создавать члены, доступные как из базового, так и из производного класса, но не из внешнего кода.

Для обхода этой проблемы существует третий уровень доступности -- protected (защищенный), при котором доступ к члену имеют только производные классы. Для внешнего кода уровень доступности protected идентичен уровню private.

Помимо уровня защиты, для члена можно определить и способ наследования. Члены базового класса могут быть виртуальными(virtual), а это означает то, что они могут переопределяться в наследующем их классе, т.е. производный класс может содержать альтернативную реализацию таких членов. Эта альтернативная реализация не отменяет исходной реализации, которая все так же доступна в рамках исходного класса, но она закрывает ееот внешнего кода. При отсутствии альтернативной реализации любой внешний код, обращающийся к члену через производный класс, автоматически использует реализацию этого члена из базового класса.

Виртуальные члены не могут быть приватными: ведь невозможно, чтобы член мог переопределяться в производном классе и в то же время не был доступен из этого производного класса.

В примере с классом Animal можно сделать виртуальным метод EatFood() и предоставить для него новую реализацию в каком-то производном классе, например, в Cow. На рисунке метод EatFood() отображается и в классе Animal,и в классе Cow; это указывает на то, что у каждого из классов имеется собственная реализация данного метода.

Рис. 8

Базовые классы могут также определяться как абстрактные(abstract). Создавать экземпляр абстрактного класса непосредственно нельзя; использовать такой класс можно только для создания порожденных классов. У абстрактных классов могут быть абстрактные члены, которые не могут иметь реализацию в базовом классе - она должна быть представлена в производных классах. Например, если бы класс Animal был абстрактным, то в UML-представлении он выглядел бы так, как показано на рисунке:

Рис. 9

Имена абстрактных классов записываются в UML курсивом (или выделяются пунктирной рамкой).

Разумеется, абстрактные базовые классы могут содержать реализации для своих членов, и так нередко и бывает. Невозможность создания экземпляра абстрактного класса не означает, что в нем нельзя инкапсулировать функциональные возможности.

И, наконец, классы могут быть запечатанными(sealed). Такие классы не могут выступать в роли базового класса и, следовательно, не могут иметь производных классов.

В языке C# имеется один общий базовый класс для всех объектов, имеющий имя object (это псевдоним для класса System.Object из .NET Framework).

Интерфейсы тоже могут наследоваться от других интерфейсов. Но, в отличие от классов, они могут наследоваться от нескольких базовых интерфейсов (так же, как и классы могут поддерживать несколько интерфейсов).

Полиморфизм

Одним из результатов наследования является наличие в производных классах методов и свойств, совпадающих с базовым классом. Поэтому для экземпляров классов с общим базовым типом часто возможно применять идентичный синтаксис. Например, при наличии у класса Animal метода EatFood() синтаксис для вызова этого метода из производных классов Cow и Chicken будет одинаковым:\

Cow myCow = new Cow();

Chicken myChicken = new Chicken();

myCow.EatFood();

myChicken.EatFood();

Полиморфизм (polymorphism) позволяет двинуться еще дальше: присваивать значение переменной производного типа переменной базового типа:

Animal myAnimal = myCow;

Приведение при этом не требуется. Далее можно просто вызывать методы базового класса через эту переменную:

myAnimal.EatFood();

Данная строка кода приведет к вызову реализации метода EatFood() из производного класса. Однако вызывать подобным образом методы, определенные в производном классе, нельзя. То есть следующий код работать не будет:

myAnimal.Moo();

Хотя можно привести переменную типа базового класса к типу производного класса и вызвать метод производного класса:

Cow myNewCow = (Cow)myAnimal;

myNewCow.Moo();

Эта операция приведения приведет к исключению, если тип исходной переменной не совпадает ни с типом Cow, ни с типом производного от него класса.

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

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

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

Например, предположим, что вместо базового класса Animal метод EatFood() помещен в интерфейс по имени IConsume. Этот интерфейс могут поддерживать оба класса -Cow и Chicken, - только каждый из них должен иметь свою реализацию метода EatFood(), поскольку интерфейсы не содержат реализаций. После этого к данному методу можно обращаться с помощью примерно такого кода:

Cow myCow = new Cow();

Chicken myChicken = new Chicken();

IConsume consumeInterface;

consumeInterface = myCow;

consumeInterface.EatFood();

consumeInterface = myChicken;

consumeInterface.EatFood();

Получается простой способ для однотипного вызова различных методов, который не зависит от общего базового класса. Например, такой интерфейс можно реализовать и в классе VenusFlyTrap (Мухоловка), порожденном не от класса Animal (Животное), а от класса Vegetable (Растение):

VenusFlyTrapmyVenusFlyTrap=newVenusFlyTrap();

IConsumeconsumeInterface;

consumeInterface=myVenusFlyTrap;

consumeInterface.EatFood();

В этом коде вызов consumeInterface.EatFood() приводит к вызову метода EatFood() класса Cow, или Chicken, или VenusFlyTrap -в зависимости от того, какой экземпляр будет присвоен переменной типа интерфейса.

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

В первом из предыдущих примеров интерфейс IConsume может поддерживаться как классом Animal, так и обоими классами Cow и Chicken. Следует учитывать, что классы с общим базовым классом не обязательно имеют общие интерфейсы, и наоборот.

Отношения между объектами

Наследование является простым отношением между объектами, когда базовый класс полностью отражен производным классом, и производный класс может также иметь доступ к внутренним деталям своего базового класса (через защищенные члены). Однако бывают и другие ситуации, в которых отношения между объектами более важны.

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

Коллекции. Один класс выступает в роли контейнера для нескольких экземпляров другого класса. Это похоже на массивы объектов, но у коллекций имеются и другие возможности: индексация, поиск, изменение размера и т.д.

Включение

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

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

Например, класс Cow может содержать класс Udder(Вымя) с общедоступным методом Milk() (Доить). Объект Cow может вызывать этот метод - например, в составе своего метода SupplyMilk(), но пользователям объекта Cow() такие детали не видны (и не важны).

Содержащиеся внутри других классы в UML могут изображаться с помощью связующих линий. В случае простого включения концы этих линий обозначаются единицами (1), что означает тип отношения один к одному (т.е., например, что один экземпляр Cow будет содержать один экземпляр Udder). Для большей наглядности экземпляр класса Udder может быть также изображен в виде приватного поля класса Cow, как показано на рисунке.

Рис. 10

Коллекции

Массивы предназначены для хранения нескольких переменных одинакового типа. То же самое можно делать и для объектов (и неудивительно: типы переменных на самом деле являются объектами).

Например:

Animal[] animals = new Animal[5];

Коллекция - это, по сути, массив, но с дополнительными возможностями. Коллекции реализуются в виде классов практически так же, как и другие объекты. Их имена часто представляют собой множественное число имени хранимых в них объектов: например, класс с именем Animals может содержать коллекцию объектов Animal.

Главное отличие от массивов состоит в том, что коллекции обычно реализуют дополнительные функции, вроде методов Add() и Remove() для добавления элементов в коллекцию и удаления из нее. У них также обычно имеется свойство Item, которое возвращает объект по его индексу. Довольно часто это свойство реализуется так, чтобы был возможен более сложный доступ. Например, класс Animals можно спроектировать так, чтобы обращаться к каждому конкретному объекту Animal по его имени.

В UML подобные отношения изображаются так, как показано на рисунке.

Рис. 11

Члены на этом рисунке не показаны, т.к. здесь рассматриваются отношения. Числа на концах связующих линий указывают, что один объект Animals содержит ноль или более объектов Animal.

Перегрузка операций

Операции можно применять для обработки переменных простых типов.

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

Например, в класс Animal можно добавить новое свойство Weight (Вес); тогда можно сравнивать вес животных с помощью такого кода:

if (cowA.Weight > cowB.Weight)

{

...

}

Перегрузка операций позволяет предоставить логику неявного использования свойства Weight, чтобы можно было написать так:

if (cowA > cowB)

{

...

}

Здесь операция «больше» (>) перегружена. Перегруженной называется такая операция, для которой был написан выполняющий ее код; этот код добавляется в определение одного из классов, для которого она должна выполняться. В предыдущем примере используются два объекта Cow, поэтому определение перегрузки операции содержится в классеCow. Аналогично можно перегружать операции и для работы с разными классами - тогда соответствующий код должен находиться в одном из определений классов (или в обоих).

Перегрузка возможна только для операций, существующих в языке C#: новые операции создавать нельзя. Однако реализации можно предоставлять как для унарных, так и для бинарных версий операции вроде +.

События

Объекты при их работе могут генерировать (и обрабатывать) события(event). События важны тем, что позволяют выполнять определенные действия в других частях кода - этим они похожи на исключения, но мощнее их. Например, при добавлении объекта Animal в коллекцию Animals может понадобиться выполнять определенный код, не являющийся ни частью класса Animals, ни частью того кода, который вызывает метод Add(). Для этого потребуется добавить в код обработчик события- особую функцию, которая вызывается при возникновении события. Кроме того, нужно настроить этот обработчик, чтобы он ожидал возникновения именно интересующего события.

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

Ссылочные типы и типы значения

Данные в C# сохраняются в переменной одним из двух способов, который зависит от типа переменной. Этот тип относится к одной из двух категорий: ссылка или значение.

Типы значения хранят себя и свое содержимое в одном месте в памяти.

Ссылочные типы хранят ссылку на другое место в памяти (называемое кучей(heap)), в котором и хранится их содержимое.

Одно из главных отличий между типами значения и ссылочными типами состоит в том, что типы значения всегда содержат значения, а ссылочные типы могут быть пустыми (null), т.е. вообще не содержать значения. Хотя можно создать тип-значение, ведущий себя в этом отношении подобно ссылочному типу (может быть нулевым), путем использования типов, допускающих нулевые значения (nullable), которые являются разновидностью обобщений (generics).

Единственными простыми ссылочными типами являются string и object, хотя неявно к ним относятся и массивы. Каждый создаваемый класс представляет собой ссылочный тип.

Главное отличие между структурами и классами состоит в том, что структуры представляют собой типы значения.

Размещено на Allbest.ru

...

Подобные документы

  • Почему C++. Возникновение и эволюция языка C++. Сравнение языков С++ и С. Эффективность и структура. Процедурное программирование. Модульное программирование. Абстракция данных. Объектно-ориентированное программирование. Улучшенный С.

    реферат [26,4 K], добавлен 03.06.2004

  • Объектно-ориентированное программирование как методология программирования, опирающаяся на инкапсуляции, полиморфизме и наследовании. Общая форма класса. Наследование как процесс, посредством которого один объект получает свойства другого объекта.

    презентация [214,9 K], добавлен 26.10.2013

  • Использование скриптового языка программирования для разработки web-приложений (сценариев). Изучение основ объектно-ориентированного программирования в языке PHP. Ознакомление со специальными методами для работы с классами. Назначение интерфейсов.

    контрольная работа [25,1 K], добавлен 14.03.2015

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

    презентация [912,2 K], добавлен 22.10.2013

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

    реферат [17,0 K], добавлен 15.04.2015

  • Характеристики и свойства языков программирования. Исследование эволюции объектно-ориентированных языков программирования. Построение эволюционной карты механизмов ООП. Разработка концептуальной модели функционирования пользовательского интерфейса.

    курсовая работа [2,6 M], добавлен 17.11.2014

  • Понятие алгоритма и его характеристики как основного элемента программирования. Формы представления алгоритмов, основные алгоритмические структуры. Структурное и событийно-ориентированное программирование. Объектно-ориентированное программирование.

    реферат [86,0 K], добавлен 17.07.2008

  • Понятие объектно-ориентированного программирования, общая характеристика языков высокого уровня. Разработка программного обеспечения для реализации компьютерной игры "пинбол" с помощью императивного программирования в среде Microsoft Visual Basic.

    курсовая работа [428,9 K], добавлен 19.09.2012

  • Особенности разработки программ для ЭВМ. Этапы планирования программы. Понятие и особенности алгоритмов. Средства, используемые для создания программ. Виды и классификация языков программирования. Структурное и объектно-ориентированное программирование.

    реферат [59,7 K], добавлен 19.08.2010

  • Характеристика модульного программирования: процедуры и функции, модули и их структура, открытые массивы и строки, нетипизированные параметры. Способы передачи параметров в подпрограммы в Borland Pascal. Объектно-ориентированное программирование.

    контрольная работа [28,9 K], добавлен 28.04.2009

  • Технологии программирования. Сущность объектно-ориентированного подхода к программированию. Назначение Си, исторические сведения. Алфавит, базовые типы и описание данных. Структуры и объединения. Операторы Си++. Функции. Библиотека времени выполнения.

    курс лекций [51,9 K], добавлен 03.10.2008

  • Разработка программы с использованием принципов объектно-ориентированного программирования на языке высокого уровня С средствами Microsoft Visual Studio 2010. Построение алгоритма реализации. Класс программы, инструкция по использованию программы.

    курсовая работа [1,0 M], добавлен 26.12.2013

  • Предмет исследования – современные методы разработки программ таких, как объектно-ориентированное программирование и визуальное проектирование, а также структурное и модульное программирование. C++ - универсальный язык программирования. Ключевые понятия.

    курсовая работа [1,1 M], добавлен 10.01.2009

  • Анализ объектно-ориентированного программирования, имитирующего способы выполнения предметов. Основные принципы объектно-ориентированного программирования: инкапсуляция, наследование, полиморфизм. Понятие классов, полей, методов, сообщений, событий.

    контрольная работа [51,7 K], добавлен 22.01.2013

  • Создание консольных приложений с использованием графического интерфейса пользователя. Содержание палитры компонентов программы С++ Builder. Использование возможностей объектно-ориентированного программирования, особенности редактора кода и форм в С++.

    лекция [27,0 K], добавлен 22.12.2010

  • Объектно-ориентированное программирование как новый подход к созданию приложений. Разработка Windows-приложения для поиска информации в хэш-таблице. Анализ использования хеширования для поиска данных и линейного зондирования для разрешения конфликтов.

    курсовая работа [915,5 K], добавлен 06.03.2016

  • Объектно-ориентированное программирование. Особенности использования формата CHM, его преимущества. Создание электронного учебника на тему "Язык программирования C++" с помощью компиляции html-страниц. Правильное сочетание тегов, структура документа.

    курсовая работа [1,0 M], добавлен 27.10.2012

  • Определение ООП, его основные концепции. Инкапсуляция как свойство системы, позволяющее объединить данные и методы, работающие с ними в классе. Пример наследования и полиморфизма. Чисто виртуальная функция. Особенности реализации, взаимодействие объектов.

    презентация [65,2 K], добавлен 05.01.2014

  • Процесс создания программы, разработка проекта программы и программирование. Лексическая обработка, синтаксический анализ, поэтапная генерация кода, использование библиотечного файла и кода. Стандартные функции библиотечного кода, математические ошибки.

    курсовая работа [26,4 K], добавлен 01.12.2009

  • Метод половинного деления при приближенном вычислении алгебраических и трансцендентных выражений. Решение системы уравнений методом Крамера. Блок-схема программы Glav. Описание стандартных и нестандартных процедур и функций, интерфейса. Численные примеры.

    курсовая работа [1,5 M], добавлен 29.07.2013

Работы в архивах красиво оформлены согласно требованиям ВУЗов и содержат рисунки, диаграммы, формулы и т.д.
PPT, PPTX и PDF-файлы представлены только в архивах.
Рекомендуем скачать работу.