Powershell ฟังก์ชั่นพร้อมคลาสไม่ใช่ oxymoron ฉันรับประกันได้

เฮ้ ฮับ! ฉันขอเสนอการแปลบทความให้คุณทราบ “PowerShell ฟังก์ชั่นพร้อมคลาส
ฉันสัญญาว่ามันไม่ใช่สิ่งที่ตรงกันข้าม"
โดยคริสโตเฟอร์ คูช

กระบวนทัศน์การเขียนโปรแกรมเชิงวัตถุและเชิงฟังก์ชันอาจดูขัดแย้งกัน แต่ทั้งสองได้รับการสนับสนุนอย่างเท่าเทียมกันใน Powershell ภาษาโปรแกรมเกือบทั้งหมด ไม่ว่าจะใช้งานได้จริงหรือไม่ก็ตาม มีสิ่งอำนวยความสะดวกสำหรับการเชื่อมโยงค่าชื่อและค่าเพิ่มเติม คลาส เช่น โครงสร้างและบันทึก เป็นเพียงแนวทางเดียว หากเราจำกัดการใช้ Classes ไว้ที่การเชื่อมโยงชื่อและค่า และหลีกเลี่ยงแนวคิดการเขียนโปรแกรมเชิงวัตถุจำนวนมาก เช่น การสืบทอด ความหลากหลาย หรือความไม่แน่นอน เราสามารถใช้ประโยชน์จากสิ่งเหล่านี้ได้โดยไม่ทำให้โค้ดของเราซับซ้อน นอกจากนี้ ด้วยการเพิ่มวิธีการแปลงประเภทที่ไม่เปลี่ยนรูปแบบ เราจึงสามารถเสริมโค้ดการทำงานของเราด้วยคลาสได้

ความมหัศจรรย์ของวรรณะ

วรรณะเป็นหนึ่งในคุณสมบัติที่ทรงพลังที่สุดใน Powershell เมื่อคุณแปลงค่า คุณจะต้องอาศัยความสามารถในการเริ่มต้นและการตรวจสอบโดยนัยที่สภาพแวดล้อมเพิ่มให้กับแอปพลิเคชันของคุณ ตัวอย่างเช่น เพียงแค่ส่งสตริงใน [xml] ก็จะเรียกใช้สตริงผ่านโค้ด parser และสร้างแผนผัง xml ที่สมบูรณ์ เราสามารถใช้ Classes ในโค้ดของเราเพื่อจุดประสงค์เดียวกันได้

ส่งแฮชเทเบิล

หากคุณไม่มี Constructor คุณสามารถดำเนินการต่อได้โดยไม่ต้องใช้ Constructor โดยส่ง hashtable ให้กับประเภทคลาสของคุณ อย่าลืมใช้แอตทริบิวต์การตรวจสอบเพื่อใช้ประโยชน์จากรูปแบบนี้อย่างเต็มที่ ในเวลาเดียวกัน เราสามารถใช้คุณสมบัติการพิมพ์ของคลาสเพื่อเรียกใช้ตรรกะการเริ่มต้นและการตรวจสอบที่ลึกยิ่งขึ้น

class Cluster {
    [ValidatePattern("^[A-z]+$")]
    [string] $Service
    [ValidateSet("TEST", "STAGE", "CANARY", "PROD")]
    [string] $FlightingRing
    [ValidateSet("EastUS", "WestUS", "NorthEurope")]
    [string] $Region
    [ValidateRange(0, 255)]
    [int] $Index
}

[Cluster]@{
    Service       = "MyService"
    FlightingRing = "PROD"
    Region        = "EastUS"
    Index         = 2
}

นอกจากนี้ การหล่อยังช่วยให้ได้ผลลัพธ์ที่สะอาดอีกด้วย เปรียบเทียบผลลัพธ์ของอาร์เรย์แฮชเทเบิลของคลัสเตอร์ที่ส่งไปยังฟอร์แมต-ตารางกับสิ่งที่คุณจะได้รับหากคุณส่งแฮชเทเบิลเหล่านี้ลงในคลาสเป็นครั้งแรก คุณสมบัติของคลาสจะแสดงรายการตามลำดับที่กำหนดไว้เสมอ อย่าลืมเพิ่มคำสำคัญที่ซ่อนอยู่หน้าคุณสมบัติทั้งหมดที่คุณไม่ต้องการให้ปรากฏในผลลัพธ์

Powershell ฟังก์ชั่นพร้อมคลาสไม่ใช่ oxymoron ฉันรับประกันได้

หล่อแห่งความหมาย

หากคุณมีคอนสตรัคเตอร์ที่มีอาร์กิวเมนต์เดียว การส่งค่าให้กับประเภทคลาสของคุณจะส่งผ่านค่าไปยังคอนสตรัคเตอร์ของคุณ ซึ่งคุณสามารถเริ่มต้นอินสแตนซ์ของคลาสของคุณได้

class Cluster {
    [ValidatePattern("^[A-z]+$")]
    [string] $Service
    [ValidateSet("TEST", "STAGE", "CANARY", "PROD")]
    [string] $FlightingRing
    [ValidateSet("EastUS", "WestUS", "NorthEurope")]
    [string] $Region
    [ValidateRange(0, 255)]
    [int] $Index

    Cluster([string] $id) {
        $this.Service, $this.FlightingRing, $this.Region, $this.Index = $id -split "-"
    }
}

[Cluster]"MyService-PROD-EastUS-2"

โยนเข้าเส้น

คุณยังสามารถแทนที่เมธอดคลาส [string] ToString() เพื่อกำหนดตรรกะเบื้องหลังการแสดงสตริงของอ็อบเจ็กต์ได้ เช่น การใช้การแก้ไขสตริง

class Cluster {
    [ValidatePattern("^[A-z]+$")]
    [string] $Service
    [ValidateSet("TEST", "STAGE", "CANARY", "PROD")]
    [string] $FlightingRing
    [ValidateSet("EastUS", "WestUS", "NorthEurope")]
    [string] $Region
    [ValidateRange(0, 255)]
    [int] $Index

    [string] ToString() {
        return $this.Service, $this.FlightingRing, $this.Region, $this.Index -join "-"
    }
}

$cluster = [Cluster]@{
    Service       = "MyService"
    FlightingRing = "PROD"
    Region        = "EastUS"
    Index         = 2
}

Write-Host "We just created a model for '$cluster'"

ส่งอินสแตนซ์ที่ต่อเนื่องกัน

Cast ช่วยให้สามารถดีซีเรียลไลซ์ได้อย่างปลอดภัย ตัวอย่างด้านล่างจะล้มเหลวหากข้อมูลไม่ตรงตามข้อกำหนดของเราในคลัสเตอร์

# Валидация сериализованных данных

[Cluster]$cluster = Get-Content "./my-cluster.json" | ConvertFrom-Json
[Cluster[]]$clusters = Import-Csv "./my-clusters.csv"

วรรณะในรหัสการทำงานของคุณ

โปรแกรมเชิงฟังก์ชันขั้นแรกจะกำหนดโครงสร้างข้อมูล จากนั้นจึงนำโปรแกรมไปใช้ตามลำดับของการแปลงโครงสร้างข้อมูลที่ไม่เปลี่ยนรูป แม้จะมีความรู้สึกที่ขัดแย้งกัน แต่คลาสจะช่วยให้คุณเขียนโค้ดการทำงานได้จริง ด้วยวิธีการแปลงประเภท

Powershell ที่ฉันกำลังเขียนนั้นใช้งานได้หรือไม่

ผู้คนจำนวนมากที่มาจาก C# หรือภูมิหลังที่คล้ายกันกำลังเขียน Powershell ซึ่งคล้ายกับ C# ด้วยการทำเช่นนี้ คุณกำลังเปลี่ยนจากการใช้แนวคิดการเขียนโปรแกรมเชิงฟังก์ชัน และอาจได้รับประโยชน์จากการดำน้ำอย่างหนักในการเขียนโปรแกรมเชิงวัตถุใน Powershell หรือการเรียนรู้เพิ่มเติมเกี่ยวกับการเขียนโปรแกรมเชิงฟังก์ชัน

หากคุณพึ่งพาอย่างมากในการแปลงข้อมูลที่ไม่เปลี่ยนรูปโดยใช้ไปป์ไลน์ (|), Where-Object, ForEach-Object, Select-Object, Group-Object, Sort-Object ฯลฯ - คุณมีสไตล์การทำงานมากขึ้นและคุณจะได้รับประโยชน์จากการใช้ Powershell คลาสในสไตล์การใช้งาน

การใช้คลาสตามหน้าที่

วรรณะ แม้ว่าจะใช้ไวยากรณ์ทางเลือก แต่ก็เป็นเพียงการเชื่อมโยงระหว่างสองโดเมน ในไปป์ไลน์ คุณสามารถจับคู่อาร์เรย์ของค่าได้โดยใช้ ForEach-Object

ในตัวอย่างด้านล่าง Node Constructor จะถูกดำเนินการทุกครั้งที่ส่ง Datum และนี่ทำให้เรามีโอกาสเขียนโค้ดได้ไม่มากนัก ด้วยเหตุนี้ ไปป์ไลน์ของเราจึงมุ่งเน้นไปที่การสืบค้นและการรวมข้อมูลที่เปิดเผย ในขณะที่คลาสของเราจะดูแลการแยกวิเคราะห์และการตรวจสอบข้อมูล

# Пример комбинирования классов с конвейерами для separation of concerns в конвейерах

class Node {
    [ValidateLength(3, 7)]
    [string] $Name
    [ValidateSet("INT", "PPE", "PROD")]
    [string] $FlightingRing
    [ValidateSet("EastUS", "WestUS", "NorthEurope", "WestEurope")]
    [string] $Region
    Node([string] $Name) {
        $Name -match "([a-z]+)(INT|PPE|PROD)([a-z]+)"
        $_, $this.Service, $this.FlightingRing, $this.Region = $Matches
        $this.Name = $Name
    }
}

class Datum {
    [string] $Name
    [int] $Value
    [Node] $Computer
    [int] Severity() {
        $this.Name -match "[0-9]+$"
        return $Matches[0]
    }
}

Write-Host "Urgent Security Audit Issues:"
Import-Csv "./audit-results.csv" `
    | ForEach-Object {[Datum]$_} `
    | Where-Object Value -gt 0 `
    | Group-Object {$_.Severity()} `
    | Where-Object Name -lt 2 `
    | ForEach-Object Group `
    | ForEach-Object Computer `
    | Where-Object FlightingRing -eq "PROD" `
    | Sort-Object Name, Region -Unique

ชั้นบรรจุภัณฑ์เพื่อนำกลับมาใช้ใหม่

ไม่มีอะไรดีเท่าที่ดูเหมือน

น่าเสียดายที่โมดูลไม่สามารถส่งออกคลาสได้ในลักษณะเดียวกับฟังก์ชันหรือตัวแปร แต่มีเทคนิคบางอย่าง สมมติว่าคลาสของคุณถูกกำหนดไว้ในไฟล์ ./my-classes.ps1

  • คุณสามารถดอทซอร์สไฟล์ด้วยคลาส:. ./my-classes.ps1 สิ่งนี้จะดำเนินการ my-classes.ps1 ในขอบเขตปัจจุบันของคุณและกำหนดคลาสทั้งหมดจากไฟล์ที่นั่น

  • คุณสามารถสร้างโมดูล Powershell ที่ส่งออก API ที่กำหนดเอง (cmdlets) ทั้งหมดของคุณ และตั้งค่าตัวแปร ScriptsToProcess = "./my-classes.ps1" ในรายการโมดูลของคุณ โดยให้ผลลัพธ์เดียวกัน: ./my-classes.ps1 จะดำเนินการใน สภาพแวดล้อมของคุณ

ไม่ว่าคุณจะเลือกตัวเลือกใด โปรดทราบว่าระบบประเภทของ Powershell ไม่สามารถแก้ไขประเภทที่มีชื่อเดียวกันที่โหลดจากที่ต่างกันได้
แม้ว่าคุณจะโหลดคลาสที่เหมือนกันสองคลาสด้วยคุณสมบัติเดียวกันจากที่ต่างกัน คุณก็เสี่ยงที่จะประสบปัญหา

ทางข้างหน้า

วิธีที่ดีที่สุดในการหลีกเลี่ยงปัญหาการแก้ไขประเภทคืออย่าเปิดเผยคลาสของคุณแก่ผู้ใช้ แทนที่จะคาดหวังให้ผู้ใช้นำเข้าประเภทที่กำหนดโดยคลาส ให้ส่งออกฟังก์ชันจากโมดูลของคุณซึ่งจะขจัดความจำเป็นในการเข้าถึงคลาสโดยตรง สำหรับ Cluster เราสามารถส่งออกฟังก์ชัน New-Cluster ที่จะสนับสนุนชุดพารามิเตอร์ที่ใช้งานง่ายและส่งกลับ Cluster

class Cluster {
    [ValidatePattern("^[A-z]+$")]
    [string] $Service
    [ValidateSet("TEST", "STAGE", "CANARY", "PROD")]
    [string] $FlightingRing
    [ValidateSet("EastUS", "WestUS", "NorthEurope")]
    [string] $Region
    [ValidateRange(0, 255)]
    [int] $Index
}

function New-Cluster {
    [OutputType([Cluster])]
    Param(
        [Parameter(Mandatory, ParameterSetName = "Id", Position = 0)]
        [ValidateNotNullOrEmpty()]
        [string] $Id,
        [Parameter(Mandatory, ParameterSetName = "Components")]
        [string] $Service,
        [Parameter(Mandatory, ParameterSetName = "Components")]
        [string] $FlightingRing,
        [Parameter(Mandatory, ParameterSetName = "Components")]
        [string] $Region,
        [Parameter(Mandatory, ParameterSetName = "Components")]
        [int] $Index
    )

    if ($Id) {
        $Service, $FlightingRing, $Region, $Index = $Id -split "-"
    }

    [Cluster]@{
        Service       = $Service
        FlightingRing = $FlightingRing
        Region        = $Region
        Index         = $Index
    }
}

Export-ModuleMember New-Cluster

มีอะไรให้อ่านอีกบ้าง

เกี่ยวกับชั้นเรียน
PowerShell ป้องกัน
การเขียนโปรแกรมฟังก์ชั่นใน PowerShell

ที่มา: will.com

เพิ่มความคิดเห็น