إن Powershell الوظيفي مع الفئات ليس تناقضًا لفظيًا، وأنا أضمن ذلك

يا هبر! أقدم انتباهكم إلى ترجمة المقال "PowerShell الوظيفية مع الفصول الدراسية.
أعدك أنه ليس تناقضًا لفظيًا"
بواسطة كريستوفر كوتش.

قد تبدو نماذج البرمجة الشيئية والوظيفية متعارضة مع بعضها البعض، ولكن كلاهما مدعومان بشكل متساوٍ في Powershell. تحتوي جميع لغات البرمجة تقريبًا، سواء كانت وظيفية أم لا، على تسهيلات لربط قيمة الاسم الممتد؛ الفئات، مثل الهياكل والسجلات، هي مجرد نهج واحد. إذا قصرنا استخدامنا للفئات على ربط الأسماء والقيم، وتجنبنا مفاهيم البرمجة الشيئية الثقيلة مثل الميراث، أو تعدد الأشكال، أو قابلية التغيير، فيمكننا الاستفادة من فوائدها دون تعقيد التعليمات البرمجية الخاصة بنا. علاوة على ذلك، من خلال إضافة طرق تحويل النوع غير القابلة للتغيير، يمكننا إثراء الكود الوظيفي الخاص بنا بالفئات.

سحر الطوائف

تعد الطوائف إحدى أقوى الميزات في Powershell. عندما تقوم بإلقاء قيمة، فإنك تعتمد على إمكانيات التهيئة والتحقق الضمنية التي تضيفها البيئة إلى تطبيقك. على سبيل المثال، سيؤدي مجرد إرسال سلسلة في [xml] إلى تشغيلها من خلال كود المحلل اللغوي وإنشاء شجرة xml كاملة. يمكننا استخدام الفئات في الكود الخاص بنا لنفس الغرض.

إرسال جداول التجزئة

إذا لم يكن لديك مُنشئ، فيمكنك الاستمرار بدونه عن طريق إرسال جدول تجزئة إلى نوع الفصل الخاص بك. لا تنس استخدام سمات التحقق لتحقيق الاستفادة الكاملة من هذا النمط. في الوقت نفسه، يمكننا استخدام خصائص الفئة المكتوبة لتشغيل منطق التهيئة والتحقق بشكل أعمق.

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
}

بالإضافة إلى ذلك، يساعد الصب في الحصول على مخرجات نظيفة. قارن مخرجات مصفوفة تجزئة الكتلة التي تم تمريرها إلى Format-Table مع ما تحصل عليه إذا قمت بإدخال جداول التجزئة هذه في الفصل لأول مرة. يتم دائمًا إدراج خصائص الفئة بالترتيب الذي تم تعريفها به هناك. لا تنس إضافة الكلمة الأساسية المخفية قبل كل تلك الخصائص التي لا تريد ظهورها في النتائج.

إن Powershell الوظيفي مع الفئات ليس تناقضًا لفظيًا، وأنا أضمن ذلك

صب المعاني

إذا كان لديك مُنشئ يحتوي على وسيطة واحدة، فسيؤدي إرسال قيمة إلى نوع الفصل الخاص بك إلى تمرير القيمة إلى مُنشئك، حيث يمكنك تهيئة مثيل لفصلك

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.

في المثال أدناه، يتم تنفيذ مُنشئ العقدة في كل مرة يتم فيها إرسال مرجع مرجعي، وهذا يمنحنا الفرصة لتجنب كتابة قدر لا بأس به من التعليمات البرمجية. ونتيجة لذلك، يركز مسارنا على الاستعلام عن البيانات التعريفية وتجميعها، بينما تعتني فصولنا بتحليل البيانات والتحقق من صحتها.

# Пример комбинирования классов с конвейерами для 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 التي تقوم بتصدير جميع واجهات برمجة التطبيقات المخصصة (cmdlets) وتعيين المتغير ScriptsToProcess = "./my-classes.ps1" في بيان الوحدة الخاصة بك، مع نفس النتيجة: سيتم تنفيذ ./my-classes.ps1 في بيئتك .

أيًا كان الخيار الذي تختاره، ضع في اعتبارك أن نظام الكتابة الخاص بـ Powershell لا يمكنه حل الأنواع التي تحمل نفس الاسم والتي تم تحميلها من أماكن مختلفة.
حتى إذا قمت بتحميل فئتين متطابقتين لهما نفس الخصائص من أماكن مختلفة، فإنك تخاطر بالوقوع في مشاكل.

الطريق الى الامام

أفضل طريقة لتجنب مشكلات دقة الكتابة هي عدم عرض فئاتك للمستخدمين مطلقًا. بدلاً من توقع قيام المستخدم باستيراد نوع محدد للفئة، قم بتصدير دالة من الوحدة النمطية الخاصة بك مما يلغي الحاجة إلى الوصول إلى الفئة مباشرة. بالنسبة إلى المجموعة، يمكننا تصدير وظيفة المجموعة الجديدة التي ستدعم مجموعات المعلمات سهلة الاستخدام وإرجاع المجموعة.

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

المصدر: www.habr.com

إضافة تعليق