Найти в Дзене
"Мы"-Прогер

Изучаем C# - Пишем статические поля и методы. Паттерн Singleton

Мы уже умеем писать методы в классах. Обычные методы вызываются у объектов класса. Например, пусть мы имеем класс Point ("точка"): У него есть два конструктора (для создания точки с 0, 0 и с заданными x, y) и метод PrintMe(), который печатает координаты точки в консоль. Это значит, что если мы создадим объект этого класса, то у объекта внутри будет метод PrintMe(): Также внутри точки будут поля X и Y. Они создаются внутри каждой точки. Статические поля и методы отличаются от обычных тем, что они принадлежат не конкретному объекту класса, а классу как таковому. То есть, если мы создадим внутри класса Point статическое поле Count, то оно будет одно на всю программу. Благодаря этому мы можем подсчитать количество созданных точек: Для доступа к статическому полю/методу нужно использовать не созданный объект класса, а сам класс: Более того, мы можем сделать, чтобы каждая точка запоминала свой номер. Поскольку номер точки - это свойство, которое у каждой точки имеет своё значение, то это буд
Оглавление

Что такое статические поля и методы?

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

У него есть два конструктора (для создания точки с 0, 0 и с заданными x, y) и метод PrintMe(), который печатает координаты точки в консоль. Это значит, что если мы создадим объект этого класса, то у объекта внутри будет метод PrintMe():

-2

Также внутри точки будут поля X и Y. Они создаются внутри каждой точки.

Статические поля и методы отличаются от обычных тем, что они принадлежат не конкретному объекту класса, а классу как таковому. То есть, если мы создадим внутри класса Point статическое поле Count, то оно будет одно на всю программу. Благодаря этому мы можем подсчитать количество созданных точек:

Пример использования статического поля
Пример использования статического поля

Для доступа к статическому полю/методу нужно использовать не созданный объект класса, а сам класс:

В файле Program.cs
В файле Program.cs

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

-5

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

Паттерн Singleton

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

Один из самых распространённых из них - паттерн Singleton ("Одиночка"). Он позволяет сделать так, чтобы можно было создать не более одного объекта определённого класса, а также сделать этот объект видимым во всей программе.

Как догадаться до реализации этого паттерна? Во-первых, раз можно создать не более одного объекта, то конструктор должен быть сокрыт от вызова извне, то есть, должен быть private (иначе можно навызывать этот конструктор и наштамповать множество объектов). Далее, чтобы создать один объект, нужно всё-таки сделать видимым извне какой-то метод, который позволяет это сделать. Этот метод будет не конструктором, а тем, который вызывает конструктор. Внутри него должна быть проверка, создан ли уже объект. А поскольку мы должны уметь вызывать этот метод из любой части программы, то он должен быть статическим. Этот метод должен создавать и возвращать в ответ тот единственный объект. А что, если объект уже создан? Метод должен выдавать созданный объект, чтобы можно было работать с ним. Нам нужно запоминать где-то ранее созданный объект. Для этого используем статическое поле (объект один на программу, поэтому статическое поле как раз подойдёт).

Итого получаем:

-6

Каждый экземпляр содержит внутри себя Id, который генерируется случайно в конструкторе, чтобы можно было отличить один экземпляр от другого. Конструктор private. Статическое поле _instance хранит в себе объект, если он ранее был создан, или null. Статический метод GetInstance() с помощью поля _instance проверяет, был ли ранее создан объект, и создаёт при необходимости. Он же возвращает в ответ этот самый единственный объект.

Для получения объекта в любом месте кода можно использовать статический метод GetInstance() (принадлежит классу, а не объекту):

-7

Доступ к полю объекта из статического метода

В статическом методе GetInstance() мы имеем доступ к статическому полю _instance. Если бы это поле было не статическим, то мы бы не могли к нему обратиться. Например, мы не имеем доступа к полю Id (попробуйте набрать его - оно будет светиться ошибкой).

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

В Singleton мы имеем статическое поле _instance. К нему можно обратиться, потому что оно статическое. Но внутри себя оно хранит объект, и мы можем обратиться к этому объекту (например, распечатать _instance.Id). Если нам нужно как-то получать доступ к объектам из статического метода, можно использовать статические поля с коллекциями (например, списки или словари).

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

Далее

Методы расширения

Оглавление

Изучаем C# с нуля - Очень краткий курс - Оглавление
"Мы"-Прогер27 января