این مقاله ترجمه مقاله دیگری از من در Medium هست
آیا تا حالا در مورد «declarative programming» یا «imperative programming» شنیدید ؟ احتمالا تا حالا تو کدهاتون از این نوع استایلهای برنامه نویسی استفاده کردید بدون اینکه حتی اسمشونو میدونستید !!!
حتی اگه تا حالا این در این موارد چیزی نشنیده باشید احتمالا از اونا استفاده کردید بدون اینکه تا حالا در موردشون چیزی شنیده باشید. اما اگر شنیدید تا حالا فکر کردید که اینا چی هستن ؟
پارادایمهای برنامه نویسی یک سری قاعده و متدولوژی هایی هستند که ساختار و پیادهسازی برنامه شما رو مشخص میکنند. همینطوری ما میتونیم زبان های برنامه نویسی رو بر اساس این قواعد دسته بندی کنیم.
به طور کلی دو نوع عاقده داریم :
در برنامهنویسی به روش Imperative ما به مراحل مورد نیاز برای انجام یک کار اهمیت میدیم و در مقابل در برنامهنویسی Declarative ما به نتیجه نهایی بدون اهمیت دادن به مراحل مورد نیاز توجه میکنیم
به این دو کد که با کاتلین نوشته شدهاند نگاه کنید ، میخوایم مجموع اعداد زوج درون یک آرایه رو به این دو شیوه حساب کنیم :
اولی به شیوه Imperative و دومی به شیوه Declarative نوشته شده . ما در کد اول برای محاسبه مقدار جمع اعداد زوج تمامی مراحل رو برای سیتسم شرح دادیم ولی در کد دوم بیشتر سعی کردیم از توابع خود کاتلین استفاده کنیم (و نمیدونیم پیاده سازی اونا چطوریه) و بیشتر به خروجی کار توجه داشتیم تا مراحل تولید اون خروجی !
به طور کلی اگه بخوام بگم Imperative روی چطور تمرکز داره و declarative روی چی !
به عنوان مثال اگه زبان SQL رو در نظر بگیرید این زبان یک زبان Declarative محسوب میشه ، چرا ؟ چون ما صرفا میگیم از فلان table بهمان row هایی رو با بیسار ویژگی به من نشون بده ! ما فقط به سیستم میگیم چی میخوایم و به SQL توضیحی نمیدیم که این مقادیر رو چطور باید برای ما محاسبه کنه !
ما انواع مختلفی از این نوع پارادایم (روش) ها داریم اما سه تای معروف اون این موارد هستند :
ما در برنامه نویسی procedural یک مجموعه ای از procedure ها (روش ها) داریم که در واقع همون توابع ما میتونن باشند و هر کدوم وظیفه معنی رو انجام میدن و برای رسیدن به خروجی مورد نظر باید یک سلسله از این روشها رو پشت سر هم انجام بدیم .
زبانهای زیادی هستند که میتونن از این نوع باشند مثل سی، جاوا، پاسکال و ... ولی اینجا یک مثال از پاسکال برای شما میزنم . دلیل اون هم اینه که در پاسکال ما علاوه بر تابع (function) یک رویه (procedure) هم داریم
تو پاسکال فرق این دو تا اینه که procedure خروجی نداره ولی function داره !
فرض کنید همون برنامه بالا رو برای محاسبه جمع اعداد زوج بخوایم بنویسیم :
همون طور که میبینید در برنامه نویسی procedural در پاسکال ما یک procedure به اسم CalculateSumOfEvenNumbers تعریف کردیم و برای رسیدن به خروجی مورد نظر اون رو اجرا میکنیم (چون برنامه ساده است فقط یک procedure داریم)
مسلما تا حالا صد تا کد به این روش زدید و فقط اسمشو نمیدونستید :)
تو برنامه نویسی Structured ما به یک ساختمار منظم از control flow اهمیت میدیم .
میتونیم این برنامه نویسی رو در سه اصل خلاصه کنیم :
سلسله مراتب : کد از بالا به پایین بر اساس یک سلسله مراتب به اجرا در میاد
انتخاب : همون شرایط کنترلی ما مثل if/else هستند
حلقه : حلقههای for و while و do while و ... که باعث میشن یک کد رو صد بار ننویسیم
در این پاردایم ما سعی میکنیم مساله رو به مسایل کوچک تر تقسیم کنیم ، خیلی از زبانها هستند که تو این پارادایم رو شامل میشن مثل سی ، جاوا ، کاتلین و ... (همون زبانهای لیست قبل مثلا)
سوالی که الان پیش میاد اینه که تفاوت procedural و structured چیه ؟ به نظر یکی میان ! مساله بیشتر اینه که برنامه نویسی structured در واقع نوعی برنامه نویسی procedural هست که از قابلیتهای بیشتری بهره میبره ، ما در برنامه نویسی structured بیشتر به ماژولار کردن و استفاده از control flow های پیشرفته اهمیت میدیم .
بیایید برنامه محاسبه فاکتوریل رو در زبان کاتلین به این دو شیوه کنار هم داشته باشیم :
همون طور که میبینید در تابع اول ما یک حلقه while داریم که با کمک اون فاکتوریل رو محاسبه میکنیم و تو تابع دوم از control flow های بیشتری استفاده کردیم . اگر عدد صفر یا یک باشه نیازی نیست که حلقه رو بررسی کنیم و مستقیم خروجی رو یک بر میگردونیم . همون طور خروجی رو مستقیم return میکنیم و مقدار خروجی رو تو یه متغیر نمیریزیم تا دوباره اون رو return کنیم (ساختار یافته تر کد میزنیم)
کل مبحث رو میتونم تو این عکس خلاصه کنم :
به نظر من تفاوت این دو پاردایم در واقع صفر و یکی نیست بلکه یک طیفه ، ما میتونیم بیشتر کد رو ساختار یافته بنویسیم و اون رو structured در نظر بگیریم و کمتر procedural !
بعضی از زبانهای برنامه نویسی مثل C از تایپی به نام structure پشتیبانی میکنند و بعضی از تایپی به نام class/object . تفاوت این دو در اینه که در structure ما یک مجموعه متغیر رو تحت عنوان یک ساختار جدید در نظر میگیریم ولی در object ما علاوه بر این مجموعه متغیر (ویژگیها) یک سری توابع (رفتارها) رو هم اضافه میکنیم .
در مورد ما اشیا موجود در دنیای واقعی رو مدل سازی میکنیم . مثلا کلاس «پرنده» یک نوع داره (کلاغ، قناری و ...) و یک سری تابع داره (پرواز کردن و راه رفتن) و خود پرنده نوعی «حیوان» هست که این کلاس «حیوان» دیگه تابع پرواز رو نداره و فقط راه رفتن رو داره .
به این مدل از برنامه نویسی ، برنامه نویسی شی گرا میگن و بر ۴ رکن استواره :
وراثت یا inheritance : یک پرنده یک نوع حیوان هست ، ما میتونیم دو شی داشته باشیم و رابطه والد و فرزند بین اونها برقرار کنیم ، کلاس فرزند همهی ویژگیها و رفتارهای کلاس والد رو به ارث میبره (و میتونه اونا رو تغییر یا اصلاح کنه) و همینطور میتونه ویژگیها و رفتارهای اضافه و خاص خودش رو داشته باشه
چندریختی یا polymorphism : برای یک رفتار میتونیم چنین پیاده سازی داشته باشیم . این پیاده سازی ها به دو نوع داینامیک (run-time) و استاتیک (compile-time) تقسیم بندی میشن ، مثلا ما میتونیم دو تابع با یک اسم یکسان و ورودیهای مختلف داشته باشیم (استاتیک) یا میتونیم یک تابع رو که در کلاس والد بوده در کلاس فرزند override کنیم (داینامیک)
در مثالی که میبینید ما یک شی از جنس والد داریم اما اون رو با نوع فرزند مقدار دهی میکنیم و چندریختی موجود نوع داینامیک هست و دلیل اون اینه که سیستم در حین اجرا تصمیم میگیره از کدوم تابع استفاده کنه (که اینجا از تابع کلاس فرزند استفاده خواهد کرد) .
در این یکی مثال نوع چندریختی از جنس استاتیک هست چون سیستم در زمان compile به این نتیجه خواهد رسید که از در وقتی به خط شماره ۱۳ یا ۱۴ رسید از کدوم تابع باید استفاده کنه .
کپسوله سازی یا encapsulation :
پنهان کردن اطلاعات و مشخصههای یک شی از یک شی دیگه و محدود کردن دسترسی به این مشخصهها به جز با توابع خاص (مثلا getter و setter)
دلیلی که برای این کار داریم در این مثال به خوبی نمایان هست ، ما نمیخوایم متغیر number مقادیر منفی داشته باشه پس این محدودیت رو در setter ایجاد کردیم ، همین طور شاید بخوایم وقتی کسی به number دسترسی پیدا میکنه یک کار اضافه (مثل log کردن یا ...) انجام بشه
انتزاع یا abstraction :
انتزاع در واقع مربوط به وراثت هست ، بعضی وقتا ما میخوایم پیچیدگی رو در اشیا کمتر کنیم ، مثلا به مثلا پرنده برمیگردیم ، هر پرنده یک نوع حیوان هست و در این انتزاع حیوان یک سری مشخصهها و رفتارها تعبیه شده (مثل راه رفتن) و دیگه لزومی نداره در کلاس پرنده پیاده سازی اونها رو تکرار کنیم (مگر اینکه به دلیلی بخوایم override انجام بدیم) و همچین یک سری رفتارهای انتزاعی مثل غذا خوردن (که میتونه برای پرنده دونه باشه و برای شیر گوشت) رو داریم که در کلاس والد صرفا تعریف اونها رو میاریم و کلاس فرزند رو مجبور میکنیم که پیاده سازی متناسب خودش رو برای اون تابع انجام بده . کلاس حیوان تو این مثال یک کلاس انتزاعی میشه پس ما هیچوقت نمیتونیم یک شی از حیوان داشته بشیم که با خود کلاس حیوان مقداردهی بشه ، بلکه میتونیم یک شی از کلاس حیوان داشته باشیم که با کلاس پرنده مقداردهی بشه .
ما انواع مختلفی از برنامه نویسی Declarative داریم ولی ۳ تای معروف اون این موارد هستند :
در برنامه نویسی functional ما به توابع ریاضی اهمیت میدیم (مثل f(x) = y) و المان های کلیدی مثل این دو مورد رو داریم
تغییر ناپذیری : ورودی یک تابع هیچگاه تغییر نمیکنه و از متغیرهای global هم استفاده نباید بکنیم. برای ساخت ورودی جدید باید خروجی یک تابع رو به داخل تابع دیگه پاس بدیم.
برنامه نویسی بازگشتی : از حلقه استفاده نمیکنیم و به جاش از توابع بازگشتی استفاده میکنیم ، اگه این مورد رو کنار تغییر ناپذیری بذارید میبینید که منطقی به نظر میاد . ما نمیخوایم متغیری مثل sum داشته باشیم که مرتبا تغییرش بدیم بلکه این sum رو میتونیم از راه بازگشتی حساب کنیم
اینجا یک مثال به زبان کاتلین داریم که همون برنامه محاسبه جمع اعداد زوج هست و از توابع بازگشتی استفاده کردیم .
باید مراقب باشید کی و کجا از تابع بازگشتی استفاده کنید چون این نوع توابع میتونن مقدار زیادی حافظه رو مصرف کنند و برنامه شما رو به سمت crash سوق بدن :)
توابع با اولیت بالاتر : شما میتونید یک تابع رو به عنوان ورودی یک تابع دیگه پاس بدید ، f(y) = z + 2 و y = x²
برنامه نویسی reactive بیشتر به eventها و جریان داده asynchronous (این لغات بهتره هیچوقت ترجمه نشن) اهمیت میده . هر زمان یک event داشته باشیم ، یک جریان داده جدید هم داریم و به این تغییرات واکنش یا react میکنیم .
این نوع برنامه نویسی بر اساس دیزان پترن observable ساخته میشه . ما یک سری observable داریم که یک جریان داده رو انتشار یا emit میکنند و یک سری observer داریم که این observableها رو subscribe میکنند تا بتونن نتیجه رو پردازش کنند .
همه چیز به صورت asynchronous اتفاق میفته ، یعنی ما میتونیم چندین observable داشته باشیم و این observable ها همدیگه رو block نمیکنند .
معمولا وقتی از این شیوه استفاده میکنیم از ابزار reactive extension بهره میبریم که مجموعه کاملی از توابع کمکی رو در اختیار ما قرار میدن و برای انواع زبان هم library دارن . مثلا یک توسعه دهنده جاوا از RxJava و یک توسعه دهنده ++C از RxCpp استفاده میکنه .
در واقع Rx مجموعه ای از extensionها و انواع مختلفی از observable رو برای استفاده ما قرار میده که ترکیبی از برنامه نویسی reacting و functional به حساب میاد ، ما میتونیم چندین extension رو برای تغییر دادههامون استفاده کنیم (مثل فیلتر یا ترکیب دادهها و ...)
به عنوان مثال کد زیر برای محاسبه مجموع اعداد زوج با این روش و با استفاده از Rx نوشته شده :
برنامه نویسی logic بر اساس formal logic صورت میگیره ولی این formal logic چی هست ؟ ما به طور کلی formal logic و informal logic داریم . در formal logic ما یک سری سمبل و در informal logic از زبان انسان استفاده میکنیم (فارسی و انگلیسی و ...) ، در formal logic ما قواعد مشخصی داریم که در نهایت ما رو به یکی از دو گزاره true یا false هدایت میکنند ولی در informal logic ما به کیفیت اهمیت میدیم نه درستی و غلطی !
مثلا اگه از شما بپرسن هوا امروز سرده شما در informal logic میتونی بگی یکم سرده یا خیلی سرده ولی در formal logic هوا یا سرد هست یا سرد نیست ! در واقع همون منطق بولی !
ما در برنامه نویسی به شیوه logic قواعد و گزارههای مطلق و الگوهایی رو داریم و خروجی رو بر اساس اونا بدست میاریم.
معروفی ترین زبان برنامه نویسی به این روش Prolog هست . یک مثال با هم ببینیم :
توی این مثال ما یک سری گزاره داریم ، john والد mary هست ، john والد lisa هست و الی آخر . یک سری گزاره دیگر هم داریم که john مرد هست ، mary زن هست و ... . حالا یک سری قوانین داریم که اگر شخصی والد شخص دیگه ای بود و مرد بود پس اون father به حساب میاد و اگر شخصی والد شخص دیگه ای بود ود زن بود اون شخص mother به حساب میاد .
مثلا اگر father(john, mary) به سیستم داده بشه خروجی true هست .
آدرس کانال تلگرامی ما : لینک
من رو در لینکدین ، اینستاگرام و یوتیوب دنبال کنید !!!