چند نکته برای برنامه نویسی بهتر در #C
نویسنده :داریوش تصدیقی
مطالبی را که در این مقاله ملاحظه می فرمایید، صرفا روش ها و عملکردهایی است که اینجانب شخصا در پروژه هایم لحاظ کرده و می کنم. قضاوت درستی و یا نادرستی آنها با خواننده محترم می باشد.
- مسوولین مایکروسافت تاکید دارند در صورتیکه تداخلی (Conflict) در بکارگیری کلاس ها وجود نداشته باشد، همیشه فضاهای نامی (Namespace) را در بالای صفحات، با استفاده از کلمه Using مشخص نماییم. البته این گفته تا حدودی نیز صحیح می باشد و شاید اکثر دوستان نیز این قاعده را رعایت کرده و می کنند و اکثرا در بالای صفحات خود با عباراتی مانند نمونه های ذیل برخورد کرده اند:
Using System;
Using System.Windows.Forms;
ولی نظر اینجانب کاملا متفاوت است! اگر تمامی نمونه برنامه های اینجانب را چه در پروژه های در مقیاس کوچک و یا متوسط مشاهده نمایید، خواهید دید که حتی یک Using نیز در بالای صفحات وجود ندارد! علت این است که هر چند با توجه به پیشنهاد مایکروسافت، از نوشته شدن سورس کد اضافی، اجتناب می شود، ولی یادگیری فضاهای نامی کلاسهای پرکاربرد مایکروسافت، به شدت دچار اشکال می شود. اجازه دهید نمونه ای را مطرح نمایم. بارها مشاهده شده است که برنامه نویسان، برای حل مشکلی، نمونه سورس کدی را از اینترنت بدست می آورند و از آنجاییکه اکثر برنامه نویسان بی حوصله هستند، مگر خلاف آن ثابت شود! از کل سورس کد، تنها قسمت کوچکی را که تمایل دارند، کپی نموده و در برنامه خود Paste می کنند. زمانیکه برنامه را Compile می کنند، با هزاران خطا مواجه می شوند! و چون حوصله جستجو در اینترنت و MSDN را برای یافتن فضاهای نامی مناسب ندارند، کل فضاهای نامی سورس کد اولیه را کپی کرده و سورس کد خود را با حجمی بیهوده از فضاهای نامی مزین می کنند! تجربه ای که اینجانب و دیگر دوستانم در حذف تمامی فضاهای نامی به روش معمول داشته ایم، این بوده است که به لطف خداوند و به مرور زمان، تقریبا روی اکثر فضاهای نامی پرکاربرد مسلط شده و در این راستا با کلاسها و فضاهای نامی مفید دیگری نیز در حین کار آشنا شده ایم. لذا از این پس در تمامی سورس کدهایی که تقدیم حضور خواهد شد، هیچ گونه فضای نامی به گونه متعارف استفاده نخواهد شد!
- شاید خیلی از دوستان، قبل از برنامه نویسی با زبان های شیء گرا خصوصا #C با زبان های برنامه نویسی Structured مانند Foxpro و یا Event Oriented مانند Visual Basic و غیره آشنایی داشته باشند. در آن زبانها بسیار اتفاق افتاده است که برنامه نویسان تمایل داشته باشند تا قسمت هایی از سورس کد خود را در داخل یک زیر برنامه (Sub Routine) نوشته و در مکانهای مناسبی صدا (Call) نمایند. این تفکر کماکان با حفظ احتیاط در زبان های برنامه نویسی شیء گرا نیز قابل پیاده سازی می باشد. تعجب نکنید! تصور نکنید که برای هر کاری در زبانهای برنامه نویسی شیء گرا باید کلاسی خلق کرده و از آن شیئی ایجاد کرده تا بتوانید تابعی (متدی) از آنرا اجرا نمایید!. در زبان برنامه نویسی #C، شما می توانید کلاسی ایجاد کرده و در آن متد و یا متدهایی به صورت استاتیک (Static) تعریف نمایید. متدهای استاتیک مربوط به خود کلاس بوده و اساسا ارتباطی با اشیاء کلاس ندارند. لذا شما می توانید از طریق خود کلاس، تابع استاتیک مربوطه را اجرا نمایید. در صورتی که با Console Application کار کرده باشید، به کرات با دستوراتی به شکل ذیل مواجه شده اید:
System.Console.WriteLine("Hello World!");
در نمونه فوق، در فضای نامی System، کلاسی به نام Console وجود دارد که در داخل آن تابع استاتیکی به نام WriteLine در نظر گرفته شده است. در نمونه فوق شما نیازی به ایجاد شیئی از نوع کلاس Console برای به اجرا درآوردن تابع WriteLine ندارید!
با توجه به مطالب فوق، شاید در یک پروژه واقعی ایجاد توابعی که چندان ارتباطی با مفهوم کلاس و شیء و غیره ندارند، بسیار ضروری باشد. ما اینگونه پیشنهاد می کنیم:
معمولا بهتر است که در هر پروژه یک کلاس با نام Globals و یا Publics و یا Utilities به شکل ذیل تعریف نمایید:
public sealed class Utilities
{
private Utilities(){}
}
و سپس تمامی توابعی که تمایل دارید به طور کاملا مستقل اجرا شوند را به صورت استاتیک در داخل آن تعریف نمایید:
public sealed class Utilities
{
private Utilities(){}
public static bool CreateFolder(string pathName)
{
bool blnResult = true;
return(blnResult);
}
}
در تکمیل مطالب فوق، عنوان چند نکته ضروری می باشد:
اول آنکه در تعریف این کلاس، از کلمه sealed استفاده شده است. بکارگیری این کلمه بدین معنی است که از این کلاس نمی توان Inherit کرد، که بدیهی است ارث بری از چنین کلاسی که تنها با یک سری توابع استاتیک تعریف شده است، چندان کار عاقلانه ای نباشد.
دوم آنکه سازنده (Constructor) این کلاس به صورت Private تعریف شده است. علت این امر آن است که ما نه تنها تمایل نداریم بلکه به طور کلی معنی ندارد که کاربر (کسی که از این Library استفاده می کند) بتواند از این کلاس شیئی بسازد.
- یکی از مواردی که شاید در برنامه نویسی مفید باشد، ایجاد کلاس ها در فضاهای نامی مناسب و لایه ای است، که البته در این زمینه اختلاف نظرهایی نیز وجود دارد. اجازه دهید موضوع را با یک مثال توضیح دهیم. فرض کنید که می خواهیم یک Library در رابطه با مدیریت فایل ها و پوشه ها مانند ایجاد پوشه، تغییر نام پوشه، حذف پوشه و غیره ایجاد نماییم و تصور کنید که برای انجام این عمل، به کلاسی با نام Utilities به شکل تعریف شده در مطلب قبلی نیاز داشته باشیم. حال سوال این است که این کلاس را در چه فضای نامی تعریف نماییم:
راه حل اول: برخی بر این عقیده اند، برای اینکه بکارگیری Library آسان تر باشد، بهتر است در همان فضای نامی که مایکروسافت تعریف کرده است، مشخص شود:
namespace System.IO
{
public sealed class Utilities
{
private Utilities(){}
public static bool CreateFolder(string pathName)
{
bool blnResult = true;
return(blnResult);
}
}
}
یکی از مزیت هایی که در این روش مستتر می باشد این است که کاربری که سالها با فضای نامی System.IO کار کرده، برای استفاده از کلاس Utilities شما، دیگر نیازی به مطالعه فضاهای نامی که در مستندات خود مشخص کرده اید، نخواهد داشت! و به راحتی می تواند در قسمت های مختلف برنامه، از کلاس شما استفاده نماید:
System.IO.Utilities.CreateFolder("C:\\Temp ");
راه حل دوم: راه حل دوم نیز بی شباهت به راه حل اول نمی باشد، در این روش به جای استفاده از کلمه System از نام شخص یا شرکت سازنده استفاده می شود و به ازای هر یک از لایه های فضای نامی یک پوشه در ریشه پروژه ایجاد می شود. به عنوان نمونه تصور کنید که شرکت ایران خودرو تمایل دارد که یک Library به شکل فوق ایجاد نماید. در این صورت ابتدا در ریشه پروژه، یک پوشه به نام IranKhodro ایجاد کرده و در داخل آن پوشه دیگری به نام IO ایجاد می نماید و سپس در داخل پوشه IO کلاسی به شکل ذیل ایجاد می نماید:
namespace IranKhodro.IO
{
public sealed class Utilities
{
private Utilities(){}
public static bool CreateFolder(string pathName)
{
bool blnResult = true;
return(blnResult);
}
}
}
در این نمونه نیز کاربر به راحتی می تواند با سابقه ذهنی که از فضاهای نامی مایکروسافت دارد و تنها با جایگزینی کلمه System به IranKhodro به تابع مورد نظر خود دسترسی پیدا کند:
IranKhodro.IO.Utilities.CreateFolder("C:\\ Temp");
که البته اینجانب به شخصه، روش دوم را بیشتر می پسندم.
- شرمنده! می دانم که خسته شده اید!! ولی یه چند لحظه تحمل کنید تا این نکته آخر را نیز خاطر نشان نمایم. به عنوان حسن ختام، پیشنهاد می کنم که تمامی توابعی که تعریف می کنید، چه توابعی که به صورت استاتیک تعریف می کنید و چه توابعی که به صورت غیر استاتیک تعریف می نمایید، باید (بهتر است) به صورت امری تعریف کرده و با یک فعل آغاز نمایید. این مطلب در ادبیات شیء گرایی بسیار حائز اهمیت می باشد. به عنوان نمونه بکارگیری توابعی که با کلماتی همچون Get, Put, Set و غیره آغاز می شوند، بسیار مناسب تر می باشد.
قسمت دوم
مطالبی را که در این مقاله ملاحظه می فرمایید، صرفا روش ها و عملکردهایی است که اینجانب شخصا در پروژه هایم لحاظ کرده و می کنم. قضاوت درستی و یا نادرستی آنها با خواننده محترم می باشد.
- هرچند که در زمان طراحی و پیاده سازی کلاسها، امکان تعریف فیلدهای Public وجود دارد، ولی به عنوان یک برنامه نویس حرفه ای به هیچ وجه از فیلدهای Public استفاده ننمایید!. حال ممکن است از خود سوال نمایید که چگونه می توان فیلدهای Public را شبیه سازی نمود؟ بسیار ساده است! شما بهتر است فیلدهایی را که می خواهید Public تعریف نمایید، به صورت Private تعریف نموده و برای قابل دسترس بودن آنها به طور متناظر از Property استفاده نمایید:
روش نادرست:
public int Age;
روش صحیح:
private int _age;
public int Age
{
get
{
return(_age);
}
set
{
_age = value;
}
}
توجه: دلایل عدم استفاده از فیلدهای Public بسیار زیاد می باشد و از حوصله این مقاله خارج است.
- یکی دیگر از مواردی که در زمان طراحی و پیاده سازی کلاس ها حائز اهمیت می باشد، نحوه نامگذاری متغیرها می باشد. البته لازم به ذکر است که استانداردهای متفاوتی در این زمینه وجود دارد که شخصا استاندارد ذیل را مطلوب تر ارزیابی کرده و بسیار علاقه مندم که دیگر دوستان، ما را با استانداردهای دیگری نیز آشنا نمایند. استانداردی که در ذیل عنوان خواهد شد، یکی از استانداردهای استفاده شده در زبان برنامه نویسی Java بوده که طبعا بکارگیری آن در زبان برنامه نویسی #C، خالی از لطف نمی باشد:
1- در این استاندارد، اسامی فیلدهای Public و Property ها با حرف اول بزرگ آغاز شده و بقیه حروف، به صورت کوچک نوشته می شوند. مانند کلمات: Age و FullName
دقت کنید که اگر نام فیلد مانند FullName از چند کلمه تشکیل شده باشد، قاعده مذکور در مورد هر کلمه صادق می باشد.
2- فیلدهای Private و Protected مانند فیلدهای Public و Property ها بوده و تنها تفاوت آنها این است که حرف اول، اولین کلمه آن با حروف کوچک آغاز گردد و قبل از آن از Underline استفاده می شود. مانند کلمات: age_ و fullName_
3- پارامترهای ورودی توابع نیز مانند فیلدهای Public و Property ها تعریف شده و تنها کافی است که حرف اول، اولین کلمه آن با حروف کوچک آغاز گردد. مانند کلمات: age و fullName
4- متغیرهای تعریف شده در داخل توابع و Block ها نیز مانند فیلدهای Public و Property ها تعریف شده و تنها کافی است که مشخصه یا نوع آنها، ترجیحا با سه حرف کوچک در قبل از آنها قرار بگیرد. مانند کلمات: intAge و strFullName
نمونه ذیل را با هم می بینیم:
public class Person
{
private string _fullName;
public string FullName
{
get
{
return(_fullName);
}
set
{
_fullName = value;
}
}
public Person(string fullName)
{
string strFullName = "Dariush Tasdighi!";
if(fullName == "")
FullName = strFullName;
else
FullName = fullName;
}
}