Главная > Powershell > Классы в Powershell. Перегрузка конструктора

Классы в Powershell. Перегрузка конструктора

Продолжаем разбираться с тонкостями создания классов в Powershell. В прошлой статье мы поговорили о перегрузках, а сегодня поговорим о перегрузках конструкторов.

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

Как говорит Википедия:

Конструктор класса — специальный блок инструкций, вызываемый при создании объекта.

Рассмотрим на примере класса DateTime.

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

PS C:\> [DateTime]::new()
Не удается найти перегрузку для "new" и количества аргументов: "0".      

Т.е. экземпляр класса DateTime нельзя создать не указав ни один параметр.

Чтобы узнать возможные варианты вызова метода new() можно вызвать этот метод без скобок:

PS C:\> [DateTime]::new

OverloadDefinitions
-------------------
datetime new(long ticks)
datetime new(long ticks, System.DateTimeKind kind)
datetime new(int year, int month, int day)
datetime new(int year, int month, int day,
    System.Globalization.Calendar calendar)
datetime new(int year, int month, int day, int hour, int minute, int second)
datetime new(int year, int month, int day, int hour, int minute, int second,
    System.DateTimeKind kind)
datetime new(int year, int month, int day, int hour, int minute, int second,
    System.Globalization.Calendar calendar)
datetime new(int year, int month, int day, int hour, int minute, int second,
    int millisecond)
datetime new(int year, int month, int day, int hour, int minute, int second,
    int millisecond, System.DateTimeKind kind)
datetime new(int year, int month, int day, int hour, int minute, int second,
    int millisecond, System.Globalization.Calendar calendar)
datetime new(int year, int month, int day, int hour, int minute, int second,
    int millisecond, System.Globalization.Calendar calendar,
    System.DateTimeKind kind)      

Таким образом, чтобы метод new() класса DateTime отработал успешно, ему нужно передать один из вышеперечисленных наборов параметров. Например:

PS C:\> [DateTime]::new(2000, 3, 8)
8 марта 2000 г. 0:00:00

PS C:\> [DateTime]::new(2000, 3, 8, 12, 30, 15)
8 марта 2000 г. 12:30:15      

Это и есть перегрузка конструктора.

Если этот пример показался слишком громоздким, взгляните на то, как мы округляем. Методу Round() можно передать одно число, а можно больше:

PS C:\> [Math]::Round(5.97458)
6
PS C:\> [Math]::Round(5.97458, 2)
5,97      

Соответственно, если передать одно число – оно будет округлено до ближайшего целого, а если два – то первое число будет округлено до количества знаков после запятой, которое равно второму передаваемому числу.

Попробуем разобраться на примере нашего класса.

Напомню, что мы рассматривали класс, описывающий робота. Чтобы было проще, пока оставим только свойства:

Class Robot
{
    # Свойства
    [string]$Name
    [int]$Id
    
    # Дата создания объекта (для каждого своя)
    [DateTime]$Birthday = (Get-Date)
    
    # Скрытое свойство
    hidden [int]$StepCount
    
    # Статическое свойство
    # Дата создания класса (у всех экземпляров этого класса одинаковая)
    static [DateTime]$Inception = (Get-Date)
}      

При таком описании класса, все свойства нужно заполнять после того, как экземпляр класса уже создан (не считая дату создания):

PS C:\> $Verter = [Robot]::new()
PS C:\> $Verter.Id = 1
PS C:\> $Verter.Name = 'Verter'

PS C:\> $Verter
Name   Id Birthday           
----   -- --------           
Verter  1 03.08.2017 10:51:24      

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

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

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

Robot([string]$Id)
{
    $this.Id = $Id
}      

Напомню, что конструкция $this.ИмяСвойства используется, когда нужно обратиться к свойствам и методам класса из него самого.

Следует учитывать, что если теперь попробовать создать экземпляр класса без указания свойства Id мы получим ошибку:

PS C:\> $Verter = [Robot]::new()
Не удается найти перегрузку для "new" и количества аргументов: "0".      

Т.е. теперь при создании экземпляра нашего класса необходимо указать идентификатор:

PS C:\> $Verter = [Robot]::new(1)
PS C:\> $Verter

Name Id Birthday
---- -- --------
      1 03.08.2017 11:53:55      

Чтобы оставить возможность создавать экземпляры класса не указывая при создании идентификатор, нужно добавить пустой метод с названием класса:

Robot()
{}      

Таким образом мы уже перегрузили конструктор.

Добавим ещё одну перегрузку с возможностью задать роботу при рождении не только идентификатор, но и имя:

Robot([string]$Id, [string]$Name)
{
    $this.Id = $Id
    $this.Name = $Name
}      

Класс будет выглядеть так:

Class Robot
{
    # Свойства
    [string]$Name
    [int]$Id
    
    # Дата создания объекта (для каждого своя)
    [DateTime]$Birthday = (Get-Date)
    
    # Скрытое свойство
    hidden [int]$StepCount
    
    # Статическое свойство
    # Дата создания класса (у всех экземпляров этого класса одинаковая)
    static [DateTime]$Inception = (Get-Date)
    
    #region Перегрузка конструктора
    # Вызывается при указании [Robot]::new()
    Robot()
    {}

    # Вызывается при указании [Robot]::new(1)
    Robot([string]$Id)
    {
        $this.Id = $Id
    }

    # Вызывается при указании [Robot]::new(1, Verter)
    Robot([string]$Id, [string]$Name)
    {
        $this.Id = $Id
        $this.Name = $Name
    }
    #endregion
}
      

Теперь можно создавать экземпляры класса, заполняя свойства прямо в момент создания:

[Robot]::new()
[Robot]::new(1)
[Robot]::new(1, 'Verter')      

Наконец, теперь мы можем поставить создание роботов на поток, и одним махом создать свою собственную армию клонов:

$Clones = @()
foreach ($Id in 1..5)
{
    $Clones += [Robot]::new($Id)
}      

Если кто запутался – $Clones – это самый обыкновенный массив, каждый элемент которого содержит свой экземпляр класса. Управлять нашей армией клонов можно как по отдельности

$Clones[0].Go(3, 2)
$Clones[1].Go(5)
$Clones[2].Name = 'Walle'
$Clones[3].Name = 'Eva'      

Так и попробовать всей армией сразу:

$Question = 'Кто сегодня желает поработать? - Шаг вперёд'
if ($Question)
{
    $Clones.Go(1)
}

-
-
-
-
-      

Даже скрытое статическое свойство можно вывести для всех сразу и увидеть, кто сколько прошёл:

PS C:\> $Clones::StepCount
4
6
1
1
1      

Напоследок посмотрим как выглядит наш полный класс, включая все свойства, методы, перечисления и перегрузки:

# Перечисление - цвет
Enum ColorOfRobot
{
    Blue
    Green
    Red
}

# Перечисление - материал
Enum MaterialOfRobot
{
    Steel
}

# Класс, описывающий робота
Class Robot
{
    # Свойства
    [string]$Name
    [int]$Id
    
    # Дата создания объекта (для каждого своя)
    [DateTime]$Birthday = (Get-Date)
    
    # Скрытое свойство
    hidden [int]$StepCount
    
    # Статическое свойство
    # Дата создания класса (у всех экземпляров этого класса одинаковая)
    static [DateTime]$Inception = (Get-Date)
    
    # Метод, вызывающий улыбку
    Smile()
    {
        Write-Host ':)'
    }

    # Метод - шаг
    Go([int]$Step) 
    { 
        Write-Host ('-'*$Step)
        $this.StepCount += $Step 
    }

    # Метод - большой шаг
    Go([int]$Step, $StepSize)
    { 
        Write-Host (('-' + ' ' * $StepSize) *$Step)
        $this.StepCount += $Step 
    }

    # Перечисления: цвет и материал
    [ColorOfRobot]$Color
    static [MaterialOfRobot]$Material
    
    #region Перегрузка конструктора
    # Вызывается при указании [Robot]::new()
    Robot()
    {}

    # Вызывается при указании [Robot]::new(1)
    Robot([string]$Id)
    {
        $this.Id = $Id
    }

    # Вызывается при указании [Robot]::new(1, Verter)
    Robot([string]$Id, [string]$Name)
    {
        $this.Id = $Id
        $this.Name = $Name
    }
    #endregion
}      

Реклама
Рубрики:Powershell Метки: ,
  1. Комментариев нет.
  1. No trackbacks yet.

Добавить комментарий

Заполните поля или щелкните по значку, чтобы оставить свой комментарий:

Логотип WordPress.com

Для комментария используется ваша учётная запись WordPress.com. Выход / Изменить )

Фотография Twitter

Для комментария используется ваша учётная запись Twitter. Выход / Изменить )

Фотография Facebook

Для комментария используется ваша учётная запись Facebook. Выход / Изменить )

Google+ photo

Для комментария используется ваша учётная запись Google+. Выход / Изменить )

Connecting to %s

%d такие блоггеры, как: