روی خط زندگی

گشت و گذار من در هنر نرم افزار

روی خط زندگی

گشت و گذار من در هنر نرم افزار

Dry: don’t repeat yourself

خودتان را تکرار نکنید! و این یعنی همان Reusability. یعنی برنامه را طوری بنویسید که قطعات مختلف آن را بتوانید باز فراخوانی کنید. به صورت ساده یعنی، اگر یک قطعه کد نوشته اید که مثلا محاسبه معدل دانش آموزان را انجام می داد و در جای دیگری از برنامه، مجددا به محاسبه معدل نیاز داشتید، قطعه کد را کپی نکنید، بلکه آن را در یک تابع قرار دهید و در هر دو جا آن را فراخوانی کنید.


YAGNI: you ain’t gonna need it

تا زمانی که لازم نشده ایجادش نکن. و این یعنی «مشکلات فردا را همان فردا حل خواهیم کرد، امروز به مشکلات امروز بپردازیم». در واقع تا زمانی که به وجود یک قابلیت نیازی نیست آن را پیاده سازی نکنیم. ممکن است که بگویید «خوب شاید بعدا لازم بشه»، یا «فردا لازمش دارم»، اما تجربه نشان داده که نرم افزار ها پر است از کد هایی که در هیچ جا استفاده نشده اند و این یعنی کاهش خوانایی برنامه و افزایش پیچیدگی کد.


KISS: keep it simple, stupid

ساده بنویس! اصولا ساده نگاه داشتن کد به خوانایی کد برنامه و کاهش زمان دیباگ کمک شایانی می کند، اما ساده نوشتن همیشه راحت نیست. در واقع بیشتر اوقات سخت است. این اصل هم در طراحی و هم در توسعه سیستم باید لحاظ شود.


لیست کامل این مباحث فلسفی را می توانید در اینجا ببینید:

List_of_software_development_philosophies


۱ نظر موافقین ۱ مخالفین ۰ ۰۹ خرداد ۹۴ ، ۱۹:۱۴
حسین گویا

در بسیاری از اوقات، برنامه نویسان و توسعه دهندگان، تنها تفاوت بین Interface و abstract class را در این می دانند که یک Interface پیاده سازی ندارد ولی abstract class می تواند رفتار ها یا در واقع متد ها را پیاده سازی کند. اما این تنها تفاوت این دو نیست و به واقع این دو از نقطه نظر ماهیت با هم تفاوت دارند و نه پیاده سازی.


وقتی یک کلاس از یک Interface ارث بری می کند، در واقع به مانند آن است که یک قرارداد را امضا می کند. کلاس با ارث بری از این Interface به ما تضمین می دهد که متد های آن را من پیاده سازی خواهم کرد و این یعنی من این رفتار ها را دارم. بدین جهت است که اگر به اسم Interface ها دقت کرده باشید، عموما به able، Provider و مانند آن ختم می شوند، مانند ICloneable . حتی آن کاراکتر «I» که در ابتدای این نام می آید اذعان می کند که من می توانم! یا من فراهم می کنم!

در مستندات راهنمای مایکروسافت، برای نام گذاری Interface ها توصیه شده که از نام ها، اصطلاحات یا صفت هایی استفاده شود که بیان کننده رفتاری باشد که آن Interface به کلاس ها القا می کند.


و اما abstract class.

وقتی به یک مفهوم از دیدگاه abstraction نگاه می کنیم، نتیجه آن پیاده سازی آن مفهوم در قالب یک abstract class است. در واقع یک abstract class مفهوم مجازی یک واقعیت است. مفهومی که ممکن است در دنیای واقعی وجود مستقیم نداشته باشد ولی کلاس هایی که از آن به ارث می روند در دنیای واقعی وجود دارند. مثلا وقتی می گوییم «نمایش دهنده» یک مفهوم مبهم به ذهن متبادر می شود و نه یک تصویر مشخص. ولی در دنیای واقعی اشیایی هستند که ماهیت این مفهوم را در خود دارند، مانند تلویزیون یا مانیتور کامپیوتر. برای همین به کلاس هایی که از یک abstract class ارث بری می کنند می گوییم: concrete class یعنی کلاس های واقعی! 


در واقع اگر بخواهیم در روابط ارث بری از دیدگاه کلاس پدر به مساله نگاه کنیم، به لحاظ ماهیتی، یک interface یک مجموعه رفتار مرتبط را به اشتراک می گذارد مانند IPrintable ولی یک abstract class یک مفهوم مجازی را به ما عرضه می کند مانند Person.

و اگر بخواهیم از دیدگاه فرزندان به مساله نگاه کنیم، کلاس هایی که از یک Interface ارث بری می کنند، در واقع می گویند ما می توانیم فلان کار را انجام دهیم یا ما این رفتار را با خود به همراه داریم و کلاس هایی که از یک abstract class ارث بری می کنند به ما می گویند ما پیاده سازی واقعی یک مفهوم مجازی هستیم.

۴ نظر موافقین ۰ مخالفین ۰ ۰۵ خرداد ۹۴ ، ۲۰:۵۳
حسین گویا

همان طور که قبلا گفتیم، گام دوم در فرآیند تحلیل و طراحی به شیوه شی گرایی، تحلیل مساله و شرح و بسط آن است. برای این منظور با توجه به متدولوژی مورد استفاده می توان از UseCase و یا UserStory استفاده نمود. در ادامه به اختصار این دو را توضیح می دهیم:


Use Case چیست؟

با توجه به تعریف ویکی پدیا، Use Case لیستی از مراحل است که به شرح تعاملات یک کنشگر (Actor) با سیستم می پردازد. برای نوشتن یک Use Case شیوه های مختلفی وجود دارد از شیوه های بسیار مقرراتی که به طور مثال متدولوژی RUP پیشنهاد می کند تا گفتگو های آزاد به اصطلاح پینگ پونگی بین کنشگر (Actor) با سیستم.


به صورت کلی یک Use Case شامل سه بخش است:

1)عنوان: هدف از این مورد کاربرد (UseCase) چیست؟

2)کنشگر (Actor): چه کسی در این مورد با سیستم تعامل دارد؟

3)سناریو: شرح تعاملات کنشگر با سیستم


توجه داشته باشید که کنشگر (Actor) می تواند یک راهبر سیستم، کاربر سیستم و یا حتی یک وسیله (مانند یک ربات) یا سیستم دیگر باشد. 

نمونه ای از یک مورد کاربرد (Use Case):

عنوان: انتقال وجه

کنشگر: مشتری

سناریو: 

  • مشتری گزینه انتقال وجه را انتخاب می کند.
  • سیستم کاربر را به صفحه انتقال وجه هدایت می کند.
  • مشتری اطلاعات کارت بانکی و مبلغ مورد نظر را وارد می کند.
  • سیستم اطلاعات را ارزیابی می کند.
  • سیستم با استفاده از شبکه شتاب مشخصات کاربر انتقال گیرنده را بررسی می کند.
  • ....

توجه داشته باشید که در اینجا شرح Use Case به صورت دیالوگ های پینگ پونگی آمده است و می توان این شرح را حتی به صورت یک پاراگراف ساده توضیح داد. در صورتی که پیش شرایط یا قواعد خاصی برای این Use Case وجود داشته باشد هم می توان آنها را در انتهای سناریو تحت عناوینی چون پیش شرط یا محدوده اجرا یا غیره ذکر کرد. برای اطلاعات بیشتر می توان به مستندات RUP در مورد Use Case مراجعه کرد.


User Story چیست؟

در متدولوژی هایی مانند Scrum به جای Use Case از User Story استفاده می شود. User Story معمولا بسیار ساده تر از Use Case است و سعی دارد همان کار Use Case را به صورت موجزتر و دقیق تر انجام دهد. شکل کلی یک User Story به قرار زیر است:

به عنوان (یک کنشگر مثلا راهبر)

من می خواهم (هدف از این کنش)

تا (نتیجه مورد انتظار و ارزشی که برای کنشگر ایجاد می کند)


به طور مثال یک User Story نمونه می تواند به شکل زیر باشد:

به عنوان یک مشتری

من می خواهم با مراجعه به سایت بانک بتوانم امکان انتقال وجه به حساب شخص دیگری را به صورت آنلاین داشته باشم

تا مجبور به مراجعه به شعبه بانک نباشم.


لازم به ذکر است که انتخاب Use Case یا User Story به موارد زیادی منجمله قواعد متدولوژی مورد استفاده و یا رویکرد شما به عمق و شیوه تحلیل مساله بستگی دارد. ممکن است برای یک پروژه تصمیم بگیرید از Use Case استفاده کنید و برای پروژه دیگری از User Story و هیچ نسخه ای در این خصوص نمی توان پیچید.


۰ نظر موافقین ۰ مخالفین ۰ ۳۱ ارديبهشت ۹۴ ، ۲۱:۴۷
حسین گویا

در مورد تحلیل نیازمندی ها را در مطالب قبلی صحبت کردیم. حال برای راحت تر شدن روند تحلیل نیازمندی ها به خصوص در مورد پروژه ها و سیستم های بزرگ، در مورد چک لیستی صحبت می کنیم که این روند را تسهیل کرده و به ما کمک می کند که چیزی را از قلم نیاندازیم.

این چک لیست را به اختصار FURPS و در روایت جدید تر +FURPS گویند. همان طور که گفتیم این چک لیست فقط یک یادآوری است که به ما می گوید آیا تا کنون در مورد این مطلب فکر کرده ای؟ آیا به این مطلب از این زاویه نگاه کرده ای؟ حال به شرح هر کدام از موارد FURPS می پردازیم:

  • Functional Requirements: همان نیاز مندی های کارکردی (یا تصریحی) است که در مطلب قبلی بدان اشاره شد.
  • Usability: مانند مستندات راهنما، مستندات آموزشی.
  • Reliability: برنامه ریزی برای آنچه که در زمان از کار افتادن سیستم باید انجام دهیم. مثلا اگر بانک اطلاعاتی از کار بیافتد چه گونه سرویس دهی به کاربران قطع نشود.
  • Performance: سیستم به چه حجمی از کاربران باید پاسخ دهد. زمان مناسب پاسخ دهی سیستم چقدر باید باشد.
  • Supportability: پشتیبانی سیستم پس از اجرا به چه نحوی خواهد بود. آیا به سیستم های جانبی دیگری برای پشتیبانی نیاز داریم، به طور مثال آیا برای کمک به کاربران سیستم، یک سیستم FAQ طراحی شده است؟


در روایت دیگری از این چک لیست، مطالب دیگری بدان اضافه شده است که اصطلاحا بدان +FURPS گویند. این مطالب به قرار زیر است:

  • Design Requirement: به طور مثال سیستم باید برای موبایل و سیستم عامل اندروید طراحی شود.
  • Implementation Requirement: مثلا بانک اطلاعاتی سیستم چه باشد، SQL یا Oracle. و یا به طور مثال زبان برنامه نویسی سیستم چه باشد Java یا C#. 
  • Interface Requirement: این مورد تنها محدود به رابط کاربری نبوده و به این مطلب اشاره می کند که ارتباطات این سیستم با سایر سیستم ها چگونه است. به طور مثال برای یک وبلاگ آیا نیاز به RSS وجود دارد.
  • Physical Requirement: به طور مثال چه آرایشی از شبکه و سرورها برای اجرای سیستم مورد نیاز است. آیا سیستم به یک وب-کم احتیاج دارد؟


توجه داشته باشید که نیازی نیست که همه نیازمندی های پروژه در همان ابتدا مشخص باشد. در واقع هیچگاه این اتفاق نخواهد افتاد. نیازمندی ها در طول پروژه تغییر خواهند کرد و اصولا متدولوژی های مبتنی بر تکرار (Iterative) بر همین مبنا پایه گذاری شده اند. یادمان باشد، در طول اجرای پروژه باید همواره پذیرای تغییر در نیازمندی ها باشیم.


۰ نظر موافقین ۰ مخالفین ۰ ۲۴ ارديبهشت ۹۴ ، ۲۰:۱۶
حسین گویا

همان طور که در مطلب قبل گفتیم، اولین گام در تحلیل و طراحی شی گرا، جمع آوری نیازمندی ها است که از آن می توان با عنوان تحلیل نیازمندی ها هم نام برد. در این مرحله مشخص می کنیم که از دید کارفرما و نیز تیم توسعه، سیستم چه کارهایی را باید انجام دهد. چرا می گوییم از دید کارفرما و تیم توسعه! اگر با فرآیند های ممیزی ایزو آشنایی داشته باشید، می دانید که از دیدگاه ایزو، نیازمندی های مشتری بر دو قسم است:

  • نیازمندی های تصریحی: نیازمندی های که مشتری راسا می گوید. مثلا رنگ ماشین خاکستری باشد.
  • نیازمندی های تلویحی: نیازمندی هایی که مشتری رسما نمی گوید ولی سیستم باید طبیعتا داشته باشد. مثلا یک خودرو طبیعتا باید سیستم ترمز داشته باشد.

در نرم افزار نیز نیازمندی ها به نوعی بر همین مبنا تقسیم می شوند:

  • نیازمندی های کارکردی (Functional Requirement)
  • نیازمندی های غیر کارکردی (Non Functional Requirement)

نیازمندی های کارکردی مشخص می کند که سیستم چه کاری باید انجام دهد اما نیازمندی های غیر کارکردی به مواردی می پردازد که ممکن است صراحتا گفته نشود ولی طبیعتا باید در سیستم لحاظ گردد. نیاز مندی های غیر کارکردی بر اقسام زیر است:

  1. راهنمای سیستم (Help): مستنداتی و آموزش هایی که برای یادگیری عملکرد سیستم مورد نیاز است.
  2. پشتیبانی (Support): آیا سیستم پس از اجرا به پشتیبانی نیاز دارد. اگر کسی ساعت دو نیمه شب با سیستم کار کند و به مشکل بر بخورد چه باید بکند.
  3. قوانین و مقررات (Legal): چه قوانین و مقرراتی بر پروژه حاکم است. مثلا قوانین کشوری یا وزارت خانه ای خاص که سیستم برای آن نوشته می شود.
  4. کارایی (Performance): سیستم به چه حجمی از کاربران باید پاسخ گو باشد و به قول معروف Response Time سیستم چه قدر باید باشد. مثلا ذات یک سیستم ثبت نام کنکور با سیستم ثبت نام یک آموزشگاه موسیقی متفاوت است.
  5. امنیت (Security): امنیت مقوله ای است که ممکن است بنا به نوع سیستم از نیاز مندی های اصلی باشد صراحتا گفته شود و یا جزو نیازمندی های غیر کارکردی و تلویحی لحاظ شود.

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

  • سیستم باید تنها به کاربرانی اجازه ورود بدهد که قبلا ثبت نام کرده اند.
  • سیستم باید در زمان ثبت نام کاربر، اطلاعات کلمه عبور را برای وی از طریق پیامک ارسال کند.
  • سیستم باید به کاربر اجازه ارسال پیامک به گروه های انتخابی از افراد را بدهد.
  • سیستم باید احراز هویت افراد را با کد ملی آنها از طریق سیستم ثبت احوال انجام دهد.

نمونه هایی از نیازمندی های غیر کارکردی به قرار زیر است:

  • یک راهنمای استفاده آنلاین برای کاربران تهیه شود و روی سایت قرار گیرد.
  • در صفحه ورود به سیستم (لاگین) یک Captcha قرار گیرد تا از حمله Brute force جلوگیری شود.
  • سیستم باید بتواند همزمان به یک صد هزار کاربر آنلاین پاسخ گو باشد.

۰ نظر موافقین ۰ مخالفین ۰ ۱۰ ارديبهشت ۹۴ ، ۱۹:۲۰
حسین گویا

وقتی می گوییم Object Oriented Analysis and Design منظور چیست و چه تفاوتی با Object Oriented Programming یا همان OOP دارد؟


در واقع برای پیاده سازی یک سیستم، ابتدا باید آن را بشناسیم. این فرآیند شناخت هم می تواند از اصول و قواعد شی گرایی تبعیت کند. بیایم به مفاهیم این کلمات نگاهی بیاندازیم:

Analysis (تحلیل): فهمیدن آن که مشکل چیست و چه راه حلی برای حل آن وجود دارد.

Design (طراحی): طراحی کردن مساله و برنامه ریزی برای حل آن.

Programming (برنامه نویسی): ساخت و پیاده سازی راه حل.

در این مجال، بحث کوتاهی خواهیم داشت پیرامون فرآیند تحلیل و طراحی از جنس شی گرا.


برای پیاده سازی یک پروژه، ابتدا باید بدانیم که کلاس های اصلی ما که همان دامین مساله را تشکیل می دهند، کدامند؟ برای پاسخ به این سوال از فرآیند تحلیل و طراحی شی گرا استفاده می کنیم. نتیجه نهایی این فرآیند آن است که کلاس های اصلی ما کدامند و چه کاری انجام می دهند. برای نایل شدن به این هدف باید پنج گام را طی نماییم:

گام اول) شناسایی و جمع آوری نیازمندی ها

طبیعتا برای طراحی و پیاده سازی سیستم ابتدا باید بدانیم مشتری یا همان کارفرما چه می خواهد و چه انتظاراتی از سیستم دارد.


گام دوم) شرح و بسط مساله

یعنی سیستمی که می خواهیم بنویسیم چه کاری را می خواهد انجام دهد و چه امکاناتی دارد. برای انجام این مهم تکنیک ها و مستندات مختلفی وجود دارد. از قبیل Use Case و User Story


گام سوم) مشخص کردن اشیا وEntity  های اصلی 

این ها همان بازیگران اصلی سیستم هستند که با مشخص شدن آنها، گام اول برای طراحی کلاس ها را برداشته ایم. برای طی این مرحله از همان مستنداتی که در گام دوم ایجاد شده اند استفاده می کنیم (مانند Use Case و User Story) تا مفاهیم و اجزای اصلی سیستم که دامین پروژه را تشکیل می دهند، را بیابیم.


گام چهارم) طراحی ارتباطات و تعاملات این اجزا با یکدیگر

حال که در گام سوم اجزا را شناختیم، باید ارتباطات و تعاملات این اجزا را با هم و با جهان بیرون از سیستم، بیابیم. برای این کار می توانیم از نمودار های تعاملی UML مانند Swim lane و Sequence Diagram استفاده کنیم. این نمودار ها به ما کمک می کنند که وظایف و مسئولیت های اجزا و Object های مختلف سیستم را بهتر بشناسیم.


گام پنجم) طراحی کلاس دیاگرام (Class Diagram)

در این گام به نتیجه دلخواه که همانا طراحی نمودار کلاس ها می باشد رسیده ایم. این طراحی هم شامل کلاس ها و رفتار هایشان است و هم شامل اصول و قواعد طراحی شی گرا مانند Inheritance، Abstraction .


توجه داشته باشید که این پنج گام را تنها یکبار طی نخواهیم کرد و در هر گذار (Iteration یا Sprint) از عمر یک پروژه ممکن است دوباره این گام ها یا چند عدد از آنها را مجددا طی کنیم تا شناخت بهتری نسبت به سیستم بدست آوریم.


۰ نظر موافقین ۰ مخالفین ۰ ۲۷ فروردين ۹۴ ، ۲۲:۰۷
حسین گویا

چند ریختی در سطح کلان یعنی ما رفتار مناسب را در هنگام استفاده از یک شی داشته باشیم. یک مثال خوب، عملگر جمع (+) است. مثال های زیر را در نظر بگیرید:

  1. 2+3
  2. ‘a’+’b’
  3. “Hello” + “world”

در مثال اول عملگر جمع در حال جمع دو عدد است، در مثال دوم همین عملگر در حال جمع دو کاراکتر و در مثال سوم در حال جمع دو رشته است. این معنای همان رفتار مناسب در زمان استفاده است. ما در زمان استفاده تغییری در عملگر ایجاد نمی کنیم ولی عملگر جمع رفتار مناسب را از خودش نمایش می دهد.

دو شکل از چند ریختی یا همان Polymorphism وجود دارد:

شکل اول) Static Polymorphism

چند ریختی ثابت، در سطح توابع وجود دارد و همان overloading است. بدان معنا که یک تابع با چند مدل از ورودی ها پیاده سازی می شود و در زمان فراخوانی بنا به پارامتر ارسالی تابع مناسب اجرا می شود. مانند:

Add (int a, int b)

Add  (string a, string b)


شکل دوم) Dynamic Polymorphism

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


۱ نظر موافقین ۰ مخالفین ۰ ۱۰ فروردين ۹۴ ، ۱۹:۴۵
حسین گویا

شاید اصلی ترین ایده در مفاهیم شی گرایی وراثت است. با وراثت می توان یک کلاس را به چندین کلاس توسعه داد بدون آنکه کلاس اصلی ما دستخوش تغییر شود. این یکی از بهترین اشکال برای Code Reuse می باشد. وقتی یک کلاس از کلاس دیگری به ارث می رود، بدون آنکه نیاز به کد نویسی باشد، کلیه رفتار ها و ویژگی های آن کلاس را به ارث می برد (البته با توجه به دسترسی های تعریف شده برای رفتار ها، تنها رفتار هایی با سطح دسترسی public و protected به ارث می روند).


در شکل زیر کلاس های Student و Employee از کلاس Person ارث بری کرده اند. به کلاس Person می گوییم Superclass و به کلاس های Student و Employee می گوییم Subclass.


یکی از مهترین فواید استفاده از وراثت آن است که با اعمال تغییرات در کلاس پدر، تمامی کلاس های فرزند که از کلاس پدر به ارث رفته اند، بدون هیچ کاری تغییرات را دریافت می کنند.

لازم به ذکر است که در برخی از زبان ها مانند ++C امکان ارث بری از چندین کلاس وجود دارد، در واقع یک کلاس فرزند می تواند چندین پدر داشته باشد!، ولی در زبان هایی مانند #C و Java هر کلاس تنها از یک کلاس می تواند ارث بری داشته باشد و امکان وراثت چندگانه وجود ندارد. لازم به ذکر است که وراثت چندگانه علی رقم آزادی عملی که به توسعه گر می دهد، مشکلاتی را ایجاد می کند (از جمله افزایش سطح پیچیدگی یا Complexity ) که بحث آن در این مقال نمی گنجد.

۰ نظر موافقین ۰ مخالفین ۰ ۲۱ اسفند ۹۳ ، ۲۰:۴۰
حسین گویا

یک مانیتور را تجسم کنید. برای روشن کردن این مانیتور چه می کنید؟ آیا کاری با خازن ها و برد الکترونیکی آن دارید؟ مسلما نه! تنها کاری که باید انجام دهید فشردن یک دکمه است و مانیتور به تبع آن روشن می شود!

کپسوله سازی، همان طور که از نامش پیداست به معنای دسته بندی و جمع کردن یک مجموعه از ویژگی ها و رفتار ها در قالب یک مجموعه واحد می باشد. اما این تمام ماجرا نیست. جمع کردن این موارد در کنار هم به تنهایی مفهوم کپسوله سازی را نمی دهد. نکته ای که این مفهوم را تکمیل می کند، نحوه دسترسی و دستیابی به اعضای داخلی این مجموعه است. یک شی یا یک کلاس به عنوان یک کپسول، سعی می کند تمام ارتباطات با اعضای داخلی خود را محدود کند و در واقع جهان بیرون از مجموعه از ارتباطات و اعضای داخل این مجموعه خبر نداشته باشند (به این مهم Information Hiding می گویند). یک کپسول تنها چیزهایی را به دنیایی بیرون ارائه می دهد که واقعا نیاز باشد. توجه داشته باشید در دنیای برنامه نویسی منظور از جهان بیرون، لزوما استفاده کنندگان از نرم افزار نمی باشد. مثلا وقتی یک کامپوننت (Component) را کپسوله می کنیم، استفاده کنندگان از این کامپوننت سایر کامپوننت ها و کلاس های دیگر می باشند و نه کاربر نهایی.


در یک کلاس، پیاده سازی سطوح دسترسی به اجزای کلاس را توسط Access Modifier ها نظیر public، private، protected اعمال می کنیم. برای انجام یک عمل مانند خاموش روشن کردن مانیتور، تنها به یک متد که کل این فرآیند را مدیریت می کند اجازه می دهیم که از بیرون قابل دسترسی باشد و سایر جزییات را از دید بیرون مخفی می کنیم. این عمل مصداق کامل ایجاد یک جعبه سیاه (Black Box) است. اگر تکنولوژی روشن و خاموش کردن مانیتور عوض شود ( به طور مثال تغییر تکنولوژی از پلاسما به LCD و بعد به LED) دکمه خاموش و روشن کردن مانیتور همچنان همان کار قبلی را می کند، بدون آنکه ما دغدغه ای از بابت این تغییر داشته باشیم.


شاید برای شما هم این سوال پیش بیاید که چرا باید کد هایی را که خودم نوشته ام از دید خودم یا دوستان همکارم پنهان کنم. توجه داشته باشید که مخفی کردن اجزای داخلی یک کلاس از جهان بیرونی، به منظور حفظ امنیت صورت نمی گیرد، بلکه دغدغه اصلی اینجا کاهش وابستگی (Dependency) اجزا یا کامپوننت های مختلف یک سیستم از یکدیگر است. 


۱ نظر موافقین ۰ مخالفین ۰ ۱۴ اسفند ۹۳ ، ۱۹:۰۱
حسین گویا

مفهوم Abstraction یا همان انتزاع دیدگاهی انتزاعی به اشیا یا همان Object های می باشد. در دنیای واقعی وقتی می گوییم میز، یک انتزاع کلی از مفهوم میز به ذهن متبادر می شود. کلمه میز لزوما تصویر خاصی از یک میز در ذهن نمی سازد ولی وقتی می گوییم میز ناهارخوری، برای هر شخص با مقتضیات فکری که دارد یک تصویر از یک میز نهارخوری که احتمالا آن را در خانه دارد یا در جایی مشاهده کرده در ذهن ساخته می شود.

در دنیای مجازی ما، Object ها نمونه هایی از یک Class هستند. در واقع کلاس ها دیدگاه های انتزاعی به یک شی می باشند. توجه داشته باشید که در مورد مفهوم انتزاع یا Abstraction صحبت می کنیم و نه در مورد abstract class (در واقع abstract class ها خود دیدگاهی انتزاعی از یک class می باشد که در ادامه راجعه به آن هم صحبت می کنیم)

مثلا کلاسی که برای مدیریت یک حساب بانکی است حاوی اطلاعاتی به مانند زیر است:


کلاس حساب بانکی (مثلا بانک ملت) :

  • صفت ها (attributes)
    • شماره حساب
    • نام صاحب حساب
    • موجودی
    • نوع حساب (جام، کوتاه مدت، طلایی)
  • رفتار ها (behaviors)
    • افزایش موجودی
    • کاهش موجودی
    • افتتاح حساب
    • بستن حساب

کلاس حساب بانکی، یک مفهوم انتزاعی از حساب بانکی افراد (مثلا حساب بانکی موسسه خیریه کهریزک) می باشد. در واقع اینجا مشخص نیست که شماره حساب چند است و صاحب حساب کیست. این یعنی ما یک کلاس برای حساب بانکی احمد و یک کلاس برای حساب بانکی محمود ایجاد نمی کنیم، بلکه یک کلاس برای حساب بانکی ایجاد می کنیم.

وقتی از منظر انتزاعی یا Abstraction به اشیا و مسائل نگاه می کنیم به این معنی است که:
  • به چیز های ضروری و اساسی دقت می کنیم.
  • از جزییات و موارد بی ربط به اساس مساله پرهیز می کنیم.
در بسیاری از مصاحبه های استخدامی که تاکنون با برنامه نویسان مختلف انجام داده ام وقتی می پرسم: abstraction چیست؟ می گویند: «کلاسی است که هیچ پیاده سازی ندارد.». این در حالی است که تاکید می کنم که اولا ما در حوزه مفاهیم صحبت می کنیم و نه در حوزه پیاده سازی، دوما abstraction مفهومی است که abstract class از آن نشئت می گیرد و این دو را با هم اشتباه نگیرید. برای روشن تر شدن کمی به abstract class بپردازیم تا تفاوت آن با مفهوم abstraction مشخص شود.

فرض کنید در همان مثال حساب بانکی، بخواهیم یک موجودیت انتزاعی تر از این کلاس خلق کنیم که وابستگی به یک بانک خاص نداشته باشد. برای این منظور می بایست دیدگاه انتزاعی خود را یک پله ارتقا دهیم و آنچه که موجب وابستگی این کلاس به یک بانک خاص می باشد (در این مثال نوع حساب که ممکن اسن برای هر بانک متفاوت باشد) را حذف می کنیم و موجودی به نام abstract class را با توجه به موجودیت کلاس قبلی ایجاد می کنیم.

با توجه به این مطلب، پر واضح است که abstraction مفهومی است که abstract class بواسطه آن ایجاد می شود و نباید این دو را معادل هم گرفت.
۹ نظر موافقین ۱ مخالفین ۰ ۰۹ بهمن ۹۳ ، ۲۱:۰۰
حسین گویا