ویرگول
ورودثبت نام
علی کاویانی
علی کاویانیمهندس ارشد توسعه نرم افزار مجموعه صباایده، فیلیمو، آپارات | Staff Engineer @Sabaidea,
علی کاویانی
علی کاویانی
خواندن ۴ دقیقه·۶ سال پیش

ترکیب به جای وراثت در زبان Go

زبان برنامه نویسی Go با به کار گیری از یک تایپ سیستم انعطاف پذیر،امکان استفاده مجدد از کد رو با کمترین میزان تلاش در اختیار برنامه نویس قرار میدهد. البته که زبان Go هنوز هم یک زبان شئ گراست ولی بدون مشکلات همیشگی این زبانها!
اگر شماهم چندین روز رو درگیر برنامه ریزی برای کلاسهای abstract و interface های مرتبط به اونها در یک برنامه پیچیده جاوا و یا ++C بوده باشید، از سادگی تایپ سیستم Golang لذت خواهید برد.

برنامه نویسهای Go با استفاده از الگوی طراحی Composition به سادگی میتوانند یک تایپ رو به صورت embed در یک تایپ دیگر وارد کنند تا بتوانند از تمام امکانات تایپ مبدا استفاده کنند، البته به خاطر داشته باشیم که زبان های برنامه نویسی دیگری هم از Composition استفاده میکنند ولی اغلب آنها عمیقا به ارث بری وابسته اند که استفاده از این امکان رو در این زبان ها مشکل و پیچیده میکنه.

در زبان Go تایپها ترکیب شده از تایپ های کوچکترند که در تضاد با مدل های سنتی ارث بری هستند.

خوب برای اینکه با این مفهوم بهتر آشنا بشیم با مثال همیشگی Duck شروع میکنیم.

type Duck struct { ID int64 Name string }

حالا میتونیم برای Duck struct یک متود هم برای خوردن به شکل زیر تعریف کنیم.

func (d *Duck) Eat() { fmt.Println(&quotDuck %s eats!&quot, d.Name) }

بسیار عالی! اگه در نظر داشته باشیم یه struct غاز وحشی هم داشته باشیم که خیلی شبیه به اردک باشه ولی رنگ های مختلفی دارند و قراره رنگهاشون رو هم ذخیره کنیم چی ؟ زبان Go ارث بری نداره ولی از ترکیب (Composition) پشتیبانی می‌کند

type Mallard struct { Duck Color string }

با Embed کردن استراکچر Duck در Mallard میتونیم به خصیصه های `ID` و `Name` دسترسی پیدا کنیم

duck := new(Duck) duck.ID = 1 duck.Name = &quotRick&quot mallard := new(Mallard) mallard.Color = &quotGreen&quot // copy info: mallard.Name = duck.Name mallard.ID = duck.ID // or even better mallard.Duck = *duck

البته که برای Mallard struct هم میتونیم متدهای مختص به خودش رو ایجاد کنیم.

func (m *Mallard) Sleep() { fmt.Println(&quot%s Mallard %s sleeps!&quot,m.Color, m.Name) }

حالا با اینکار Mallard ما هم میتونه غذا بخوره و هم میتونه بخوابه !

mallard.Eat() malled.Sleep() // Duck Ruck eats! // Green Mallard Rick sleeps!

اگه به چشم شئ گرایی به نتیجه نگاه کنیم، خروجی کار خیلی شبیه به ارث بری به نظر میرسه ولی در اصل اجرای اون کاملا بر اساس قاعده ترکیب یا composition هست.

به قول یکی از دوستان خوبم که میگه :

اگه میخواهی یک زبان رو به روش درست درک کنی بهتره به نحوه توسعه پکیج ها و کامپوننت های داخلی همون زبان نگاه کنی !

و برای زبان Golang این نقل قول خیلی کارایی داره!

یکی از روشهای خیلی متداول در پکیج های داخلی Golang برای lock کردن ساختارهای داده ها استفاده از همین الگوی طراحی composition هست برای مثال در کتابخانه cache ساختار hashDebug درون خود sync.Mutex را ضمیمه کرده پس هرجا برای تغییر مپ m نیاز به قفل کردن وجود داشته باشد کافیه با اجرای دستور hashDebug.Lock از قابلیت Lock که به واسطه sync.Mutex به دست آورده استفاده کنه.

// hashDebug holds the input to every computed hash ID, // so that we can work backward from the ID involved in a // cache entry mismatch to a description of what should be there. var hashDebug struct { sync.Mutex m map[[HashSize]byte]string } // reverseHash returns the input used to compute the hash id. func reverseHash(id [HashSize]byte) string { hashDebug.Lock() s := hashDebug.m[id] hashDebug.Unlock() return s }
gogolangcompositionگوگولنگ
۱۴
۱
علی کاویانی
علی کاویانی
مهندس ارشد توسعه نرم افزار مجموعه صباایده، فیلیمو، آپارات | Staff Engineer @Sabaidea,
انتشارات GoLang
انتشارات GoLang
انتشارات GoLang امیدوار است با تدوین، انتشار و ترجمه مقاله های به روز زبان برنامه نویسی Go Lang قدمی هر چند کوچک در جهت کمک به توسعه دهندگان پارسی زبان بردارد. از همه علاقه مندان دعوت می شود که مقاله های ارزشمند خود را در این انتشارات منتشر کنند.
شاید از این پست‌ها خوشتان بیاید