Смекни!
smekni.com

Основы алгоритмизации и программирования 2 (стр. 21 из 32)

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

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

При представлении класса посредством UML вторая секция используется для изображения свойств и полей.

На рисунке 6.3 можно видеть представление нашего класса CupOfCoffee, в котором описано пять членов (неважно, свойств или полей – в UML между ними не существует никаких отличий), обсуждавшихся нами ранее. Каждое вхождение содержит следующую информацию.

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

касающаяся режима доступа (чтение/запись).

- Имя члена.

- Тип члена.

В качестве разделителя между именем и типом члена используется двоеточие.

5.2.2.Методы

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

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

В UML при описании объектов для изображения функций используется третья секция прямоугольника (см. рис. 6.4).

Используемый в этом случае синтаксис аналогичен применяемому для полей и свойств, за исключением того, что в конце строки указывается тип возвращаемого значения, а также приводятся параметры. В UML каждый параметр изображается с одним из следующих идентификаторов: in, out или inout. Эти идентификаторы используются для обозначения направления потока данных, при этом out и inout в первом приближении соответствуют применяемым в С# ключевым словам out и ref, описанным в главе 6. Идентификатор in примерно соответствует такому поведению С#, когда отсутствуют оба ключевых слова.

Настал момент, когда необходимо, наконец, объясниться. Мы использовали объекты, свойства и методы на всем протяжении этой книги. В действительности в С# и .NET Framework объектом может быть все, что угодно. Функция Main() в консольном приложении является методом класса. Все типы переменных, рассмотренных нами, являются классами. Каждая из использовавшихся команд представляет собой свойство или метод, например, <Строка>.Length, <Cтpoкa>.ToUpper() и т. д. В данном случае точка отделяет имя экземпляра объекта от свойства или от имени метода.

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

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

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

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

- создание объекта – состояние, когда происходит первоначальное создание экземпляра объекта. Такая инициализация известна под названием создания объекта и осуществляется конструктором объекта;

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

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

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

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

В С# конструктор можно вызвать, введя ключевое слово new. Например, мы можем создать объект типа string следующим образом:

string myString = new string();

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

string myString = new string('а', 10);

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

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

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

5.2.4.Деструкторы

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

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

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

Это означает, что не следует полагаться на деструктор в плане освобождения ресурсов, которые использовались экземпляром объекта, поскольку объект может оставаться неиспользуемым на протяжении длительного времени. Если используемые ресурсы критичны, то это может привести к возникновению проблем. Однако здесь имеется решение, и оно рассматривается в разделе "Удаляемые объекты" этой главы.

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

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