واجهة sort.Interface
جزء من قسم البرمجة كائنية التوجه في رحلة GO على Coddy. الدرس 74 من 107.
توفر حزمة sort مثالًا ممتازًا آخر على التصميم القائم على الواجهات. لفرز مجموعة مخصّصة، يجب أن ينفّذ نوعك sort.Interface:
type Interface interface {
Len() int
Less(i, j int) bool
Swap(i, j int)
}تمنح هذه الأساليب خوارزمية الفرز كل ما تحتاج إليه: طول collection، وطريقة لمقارنة elements، وطريقة لتبديلها. إليك كيفية جعل شريحة من البنى المخصصة قابلة للفرز:
type Person struct {
Name string
Age int
}
type ByAge []Person
func (a ByAge) Len() int { return len(a) }
func (a ByAge) Less(i, j int) bool { return a[i].Age < a[j].Age }
func (a ByAge) Swap(i, j int) { a[i], a[j] = a[j], a[i] }
func main() {
people := []Person{
{"Alice", 30},
{"Bob", 25},
{"Carol", 35},
}
sort.Sort(ByAge(people))
fmt.Println(people)
// [{Bob 25} {Alice 30} {Carol 35}]
}تتمثل الفكرة الأساسية في إنشاء نوع مُسمّى (ByAge) استنادًا إلى شريحتك. يتيح لك ذلك تعريف سلوكيات فرز مختلفة للبيانات نفسها. يمكنك إنشاء ByName مع تنفيذ مختلف لـ Less للفرز أبجديًا بدلًا من ذلك.
بمجرد أن يفي نوعك بالواجهة sort.Interface، فإنه يعمل تلقائيًا مع sort.Sort() وsort.Reverse() وsort.IsSorted().
التحدي
سهللنَبْنِ نظامًا قابلًا للفرز لمخزون المنتجات يوضّح قوة sort.Interface في Go! ستنشئ نوع Product وتنفّذ استراتيجيات فرز متعددة، مما يسمح بفرز المجموعة نفسها بطرق مختلفة.
ستُنظّم الشيفرة عبر ملفين:
product.go: عرّف نوع المنتج وتنفيذات الفرز الخاصة به.أنشئ بنية
Productبثلاثة حقول:Name(من النوع string)، وPrice(من النوع float64)، وQuantity(من النوع int).أنشئ نوعين مُسمّيين بالاعتماد على
[]Product:ByPrice- لفرز المنتجات حسب السعر بترتيب تصاعديByQuantity- لفرز المنتجات حسب الكمية بترتيب تنازلي (الكمية الأكبر أولًا)
يحتاج كل نوع إلى تنفيذ الأساليب الثلاثة المطلوبة بواسطة
sort.Interface:Len()، وLess(i, j int)، وSwap(i, j int). يحدّد الأسلوبLessترتيب الفرز لكل نوع.main.go: أنشئ مخزون المنتجات وفرزه.اقرأ وضع الفرز (
priceأوquantity)، ثم اقرأ العدد متبوعًا بتفاصيل المنتجات. يُقدَّم كل منتج في ثلاثة أسطر: الاسم، والسعر، والكمية.أنشئ شريحة من المنتجات، وفرزها باستخدام نوع الفرز المناسب بناءً على الوضع، ثم اطبع كل منتج بهذا التنسيق:
[Name]: $[Price] (x[Quantity])اعرض الأسعار بمنزلتين عشريتين.
ستُقدَّم المدخلات التالية:
- السطر 1: وضع الفرز (
priceأوquantity) - السطر 2: عدد المنتجات
- الأسطر التالية: تفاصيل المنتج (الاسم، والسعر، والكمية - ثلاثة أسطر لكل منتج)
على سبيل المثال، عند إعطاء:
price
3
Laptop
999.99
5
Mouse
29.99
50
Keyboard
79.99
25ينبغي أن يكون الناتج:
Mouse: $29.99 (x50)
Keyboard: $79.99 (x25)
Laptop: $999.99 (x5)وعند إعطاء:
quantity
3
Laptop
999.99
5
Mouse
29.99
50
Keyboard
79.99
25ينبغي أن يكون الناتج:
Mouse: $29.99 (x50)
Keyboard: $79.99 (x25)
Laptop: $999.99 (x5)لاحظ كيف يمكن فرز بيانات المنتج نفسها بطرق مختلفة بمجرد استخدام نوع مُسمّى مختلف. وبمجرد أن تستوفي أنواعك متطلبات sort.Interface، فإنها تعمل بسلاسة مع sort.Sort() من المكتبة القياسية.
جرّب بنفسك
package main
import (
"bufio"
"fmt"
"os"
"sort"
"strconv"
"strings"
)
func main() {
reader := bufio.NewReader(os.Stdin)
// اقرأ وضع الترتيب
var mode string
fmt.Fscanln(reader, &mode)
// اقرأ عدد المنتجات
var count int
fmt.Fscanln(reader, &count)
// اقرأ المنتجات
products := make([]Product, count)
for i := 0; i < count; i++ {
name, _ := reader.ReadString('\n')
name = strings.TrimSpace(name)
priceStr, _ := reader.ReadString('\n')
priceStr = strings.TrimSpace(priceStr)
price, _ := strconv.ParseFloat(priceStr, 64)
qtyStr, _ := reader.ReadString('\n')
qtyStr = strings.TrimSpace(qtyStr)
quantity, _ := strconv.Atoi(qtyStr)
products[i] = Product{Name: name, Price: price, Quantity: quantity}
}
// TODO: رتّب المنتجات بناءً على الوضع
// إذا كان الوضع هو "price"، استخدم النوع ByPrice
// إذا كان الوضع هو "quantity"، استخدم النوع ByQuantity
// استخدم sort.Sort() مع النوع المناسب
// TODO: اطبع كل منتج بالتنسيق:
// [Name]: $[Price] (x[Quantity])
// استخدم fmt.Printf مع %.2f لتنسيق السعر
}
يتضمن هذا الدرس اختبارًا قصيرًا. ابدأ الدرس للإجابة عليه وتتبّع تقدمك.
جميع دروس البرمجة كائنية التوجه
1أساسيات الـ OOP في Go
الملفات الخارجيةمساحة العمل والـ Modules في Goالـ Packages والـ Importsالأسماء المصدرة مقابل غير المصدرةمقدمة إلى الـ OOP في Goالـ Structs كـ Classesتعريف الـ Methods في الـ Structsالـ Pointer Receivers مقابل الـ Value Receiversتهيئة الـ Structدوال الـ Constructorمراجعة - آلة حاسبة بسيطة4الواجهات
مقدمة في الواجهاتالتنفيذ الضمنيالواجهة كعقدالواجهة الفارغة (any)تأكيد النوع (Type Assertion)تبديل النوع (Type Switch)تركيب الواجهاتواجهات Stringer و Errorمراجعة - حاسبة الأشكال7التغليف
الحقول المصدرة وغير المصدرةالتغليف على مستوى الحزمةدوال الـ Getter والـ Setterإخفاء المعلومات في Goملخص - سجلات الطلاب10الأنواع العامة (Go 1.18+)
مقدمة في الأنواع العامةمعاملات الأنواعقيود الأنواعالـ Structs العامةحل بديل للـ Methods العامةملخص - المجموعات العامة13أنماط التصميم - الجزء الأول
مقدمة في أنماط التصميمنمط Singletonنمط Factoryنمط Abstract Factoryنمط Observerنمط Strategy2تعمق في الأنواع و Structs
الأنواع الأساسية والمركبةتعريفات الأنواع المخصصةStruct TagsStructs مجهولةStructs متداخلةالقيم الصفرية والافتراضيةمراجعة - دفتر العناوين5التركيب بدلاً من الوراثة
لماذا لا تدعم Go الوراثةأساسيات تضمين الـ Structترقية الـ Methodتضمين عدة Structsالتضمين مقابل التجميعحجب الـ Methods المضمنةملخص - الهيكل الهرمي للموظفين8معالجة الأخطاء و OOP
واجهة errorأنواع الأخطاء المخصصةتغليف الأخطاء (fmt.Errorf)أخطاء Sentinelerrors.Is() و errors.As()Panic و Defer و Recoverملخص - File Parser11المكتبة القياسية والبرمجة كائنية التوجه (OOP)
io.Reader و io.Writerواجهة sort.Interfaceواجهة fmt.Stringerencoding/json مع Structsواجهة http.Handlerمراجعة - نماذج REST API14أنماط التصميم - الجزء الثاني
نمط الأمرنمط المحولنمط المزيننمط طريقة القالبنمط الحالةنمط التركيبMiddleware كنمط مزين3المؤشرات والذاكرة
أساسيات المؤشرات في Goالمؤشرات إلى الـ Structsالتمرير بالقيمة مقابل التمرير بالمرجعدالة ()newGarbage Collection في Goملخص - بناء Linked List6تعدد الأشكال في Go
تعدد الأشكال عبر InterfacesDuck Typing في Goقواعد استيفاء الـ Interfaceمجموعات متعددة الأشكالحقن التبعيةمراجعة - معالج الدفع9التزامن والبرمجة كائنية التوجه (OOP)
أساسيات الـ Goroutinesالقنوات (Channels) والاتصالالقنوات المخزنة (Buffered) مقابل غير المخزنةجملة Selectsync.Mutex و sync.RWMutexsync.WaitGroupتصميم الـ Structs الآمنة للخيوط (Thread-Safe)مراجعة - Worker Poolتدرّب بنفسك: مترجم Go عبر الإنترنت