فرهاد شیری جمعه 24 فروردین 1397 09:05 بعد از ظهر نظرات ()
با سلام!
میخواهم درباره برنامه نویسی ماژولار و همچنین اینکه چگونه کد بنویسیم که از دوباره کاری و تکرار جلوگیری بشه!
و کد هایی که مینویسیم قابلیت استفاده مجدد داشته باشه و اصلا چطوری این تفکر تو خودمون تقویت کنیم که از این تکنیک ها همیشه استفاده کنیم تا برنامه هایی هرچه بهتر و مستحکم تر و بهینه تر و قابل اعتماد تولید بکنیم .
و برای اینکه به این هدف نزدیکتر شویم طی آموزشی کاربردی کلاس هایی طراحی خواهیم کرد و از آن ها برای کدنویسی شی گرا استفاده خواهیم کرد.
و نکته اینکه در ویژوال فاکس پرو، تمامی دستاورد های شی گرایی به طور کامل امکان استفاده وجود ندارد، برای اینکه اساسا ویژوال فاکس پرو یک محیط توسعه نرم افزار نیست بلکه یک پایگاه داده NATIVE فوق العاده کارا و قوی هست که در طول سالهای گذشته برخی امکانات برنامه نویسی شی گرایی به آن اضافه شده است آن هم به دلیل اینکه از والد خود که زبان قدرتمند سی پلاس پلاس می باشد به ارث برده است .
همانطور که می دانید شی گرایی از چهار بخش تشکیل شده است .
1- وراثت
2- پلی مورفیسم (چند ریختی)
3- نهان سازی
4- تجرید

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

نکته برنامه نویسی :
البته در تعریف کلاسها در ویژوال فاکس امکان پیاده سازی (IMPLEMENTS) از یک لایبرری DLL(dynamic link library) وجود دارد و همچنین امکان استفاده از توابع  لایبرری پیاده سازی شده نیز وجود دارد.


کلاس ارتباط ویژوال فاکس پرو با SQL SERVER (قسمت اول)
البته این نکته رو هم اضافه کنم فرض رو بر این داریم که شما دانشجوی عزیز قبلا مباحث آموزشی این وبلاگ رو مشاهده کردید و حداقل آشنایی هم با ویژوال فاکس پرو دارید.!
1- اولین گام یه متا فایل کلاس به نام SqlManagment.vcx (آموزش ساخت کلاس رو دوست خوبم آقای حسین زاده توی همین وبلاگ کاملا توضیح دادن) البته نام حتما نباید این باشد هر نامی که مایل هستید استفاده نمایید. و یک کلاس جدید داخل این متا فایل به نام daLayer با نوع custom ایجاد نمایید.
DEFINE CLASS dalayer AS custom
      Height = 18
    Width = 18
    Protected evaloeconect = 0
    Protected affectedrec = 0
""= Protected lcconstr 
Protected decryptcs = .F
"" = Name
   ENDDEFINE

و در این کلاس Property های مورد نیاز را تعریف میکنیم توجه داشته باشید که در وی فاکس تعریف یک خصیصه (Property) با سه نوع دستیابی قابل تعریف می باشند.
1- Public : (که بصورت پیش فرض هم نوشته نمی شود همراه با نام خصیصه) یعنی تمامی متدهای کلاس به آن دسترسی خواهند داشت و همچنین تمامی آبجکتهایی که ساخته می شوند امکان دسترسی خواندن و نوشتن این خصیصه ها را خواهند داشت .
2- Protected : یعنی فقط متدهای کلاس می توانند دسترسی نوشتن داشته باشند از بیرون کلاس فقط دسترسی خواندن وجود دارد.
3- Hidden : یعنی فقط متدهای کلاس قابلیت خواندن و نوشتن را دارند از بیرون کلاس حتی دسترسی خواندن هم وجود ندارد.
دسترس های شماره 2 و 3 امکان کپسوله کردن اطلاعات درون کلاس را برای ما پیاده سازی میکنند.
حالا شاید سوال کنید که پس چگونه به این مقادیر کپسوله شده دسترسی داسته باشیم از آنها اطلاعات بخوانیم و اطلاعات بنویسیم در سایر زبانهای شی گرا از روشهای مختلفی این کار صورت میگیرد که متدهای (Set/Get) از معروفترین آن می باشد ولی در ویژوال فاکس نام این دو متد access که معادل set و assign که معادل متد get می باشد تعریف می شوند و سطح دسترسی این متدها هم به صورت public تعریف می شوند.

نکته برنامه نویسی :
ویژوال فاکس پرو به حروف بزرگ و کوچک حساس نیست ولی از  آنجائیکه می خواهیم ساختارمند کد نویسی کنیم کم کم این قوانین را در نامگذاری ها رعایت خواهیم کرد ومن به فراخور زمان این قوانین را خواهم گفت.
پس از این به بعد نام گذاری کلاسها را به روش Camel Case وبا یک حروف بزرگ در ابتدا خواهیم نوشت(Camel Case: یعنی نام ها را مانند کوهان شتر با یک حرف بزرگ و در ادامه کلمات با معنی را هم با حروف بزرگ شروع خواهیم کرد.)
ونام گذاری آبجکتها را با حرف کوچک تعریف خواهیم کرد.



2- تعریف متدها :
در ویژوال فاکس پرو متد با استفاده از کلمه کلیدی Procedure تعریف میشود و به صورت پیش فرض هم دسترسی Public برای متد ها در نظر گرفته می شود و امکان تعیین سطح دسترسی برای متد ها نیز دقیقا مشابه تعریف خاصیت ها می توان هم Protected تعریف کرد وهم به صورت Hidden که البته واضح می باشد که تعریف یک متد با دسترسی Protected به معنای خصوصی (Private) کردن متد و تعریف و تغییر هم فقط در سطح کلاس می باشد پس بنابراین اگر متدی را به صورت محافظت شده تعریف نمایید در آبجکتهایی که می خواهید از این متد استفاده نمایید فقط دسترسی خواندن خواهید داشت و نمی توانید آن متد را تحریف نمایید و پیاده سازی تابع را تغییر دهید دقیقا مانند متدهایی که در برنامه نویسی #c آنها را اقیم کنیم (Sealed method) و یا در جاوا (Final Method).
 و تعریف به صورت Hidden نیز یعنی سطح دسترسی در کلاس می باشد و آبجکتهای دیگر نه دسترسی خواندن دارند و نه دسترسی نوشتن در این متدها را دارند.
بنابراین اگر متدی را Public تعریف کنیم می توانیم هم در کلاس خود متد وهم در سایر کلاسها و آبجکتها این متد را هم دوباره نویسی کنیم که یعنی Overriding اتفاق افتاده است و هم می توانیم به ارث ببریم که Inheritance  اتفاق افتاده است.
و اگر متد را با دسترسی Protected تعریف نماییم یعنی فقط این متد در کلاس صاحب متد پیاده سازی می شود ولی در آبجکتها و کلاسهای دیگر فقط امکان ارث بری از آن وجود خواهد داشت.
اکنون با این مقدمه چند متد به شکل زیر در کلاس مان تعریف خواهیم کرد.
PUBLIC PROCEDURE sqlservercheck
    PARAMETERS otherdatabasevisible AS boolean
    #DEFINE mb_okbutton 0
    #DEFINE mb_stopsign 16
   
Protected SuccRet=.T.
    WITH THIS
        IF TYPE('oEconect')!='U'
            =SQLIDLEDISCONNECT(oeconect)
        ENDIF
        RELEASE oeconect
        PUBLIC oeconect
        IF .not. PEMSTATUS(_SCREEN,[lCconstr],5)
            IF FILE([CSQLMNGT.SSL])
                SET CLASSLIB TO _encdeccryptor.vcx ADDITIVE
                _decryptor=CREATEOBJECT([_encdecryptor])
                _ls=_decryptor.decryptor()
                IF FILE([CSQLMNGT.SSL]) AND _ls
                    RESTORE FROM csqlmngt.ssl ADDITIVE
                    _ls=_decryptor.encryptor()
                    RELEASE _decryptor
                    IF !otherdatabasevisible
                        IF type([m.ChangedDB])<>[L]
                            MainDataServer  =iif(m.activedataformCheked,MainDataSource,alltrim(csetdatabasestr))
                        ENDIF
                    ENDIF
                    .lcconstr=csetconnectstr
                    _SCREEN.ADDPROPERTY([lCconstr],.lcconstr)
                    _screen.AddProperty([LCDataRep],alltrim(csetdatabasestr))
                ELSE
                    MESSAGEBOX([CS is not Work!]+CHR(13)+[1-Copy File 'csqlmngt.ssl' from Servername\Hoa\inv-win\update-exe Folder]+CHR(13);
                    +[2-if not found file 'csqlmngt.ssl' Run Setting.exe]+CHR(13);
                    +[3-Please Contact by System Administrator],0+16+0,'System Error')
                    CLEAR EVENTS
                    CLOSE ALL
                    CLEAR ALL
                    QUIT
                ENDIF
            ELSE
                    MESSAGEBOX([CS is not Work!]+CHR(13)+[1-Copy File 'csqlmngt.ssl' from Servername\Hoa\inv-win\update-exe Folder]+CHR(13);
                    +[2-if not found file 'csqlmngt.ssl' Run Setting.exe]+CHR(13);
                    +[3-Please Contact by System Administrator],0+16+0,'System Error')
                CLEAR EVENTS
                CLOSE ALL
                CLEAR ALL
                QUIT
            ENDIF
        ELSE
            IF !otherdatabasevisible
                IF type([m.ChangedDB])<>[L]
                    maindataserver  =iif(m.activedataformCheked,MainDataSource,iif(type([csetdatabasestr])=[U],_screen.LCDataRep,csetdatabasestr))
                ENDIF
            ENDIF
            .lcconstr=_SCREEN.lCconstr
        ENDIF
        oeconect = SQLSTRINGCONNECT(.lcconstr)
        IF oeconect <= 0
            LOCAL ARRAY laerror[1]
            AERROR(laerror)
            MESSAGEBOX(laerror[2],mb_okbutton+mb_stopsign,[SQL Server Error:]+TRANSFORM(laerror[5]))
            SuccRet=.F.
        ENDIF
        .evaloeconect = oeconect
        SuccRet=.sqlsetpropvalue(oeconect)
    ENDWITH
    RETURN SuccRet
ENDPROC



PUBLIC PROCEDURE sqlsetpropvalue
    PARAMETERS conhandle
    #define _Idletime 0
    #define _QueryTimeout 0
    #define _Dispwar .T.
    #define _Conectimeout 15
    #define _Displog 3

   
Protected RetSet=.T.
       RetSet=IIF(SQLSETPROP(conhandle, [IdleTimeout], _Idletime)>0,RetSet,.F.)
       RetSet=IIF(SQLSETPROP(conhandle, [QueryTimeOut], _QueryTimeout)>0,RetSet,.F.)
       RetSet=IIF(SQLSETPROP(conhandle, [DispWarnings], _Dispwar)>0,RetSet,.F.)
       RetSet=IIF(SQLSETPROP(conhandle, [ConnectTimeOut], _Conectimeout)>0,RetSet,.F.)
       RetSet=IIF(SQLSETPROP(conhandle, [DispLogin], _Displog)>0,RetSet,.F.)
       RetSet=IIF(SQLSETPROP(conhandle, [Asynchronous], .F.)>0,RetSet,.F.)
       RetSet=IIF(SQLSETPROP(conhandle, [BatchMode], .T.)>0,RetSet,.F.)
     
    RETURN
RetSet 
ENDPROC



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

*!* Define a method Call By Value
PUBLIC PROCEDURE CallByValue
Parameters primitiveType  AS integer
 
primitiveType = primitiveType + 1

return primitiveType

و در مثال بعدی یک متد با ورودی یک آبجکت از نوع تکست باکس تعریف کرده ایم در این مثال از ارسال با ارجاع شی استفاده کرده ایم بنابراین می توانیم از همان شی در همان کلاس استفاده نماییم و هر تغییر در شی مذکور در شی اصلی در جایی که به متد ارسال شده است نیز ثبت خواهد شد

*!* Define a method Call By reference.!
DEFINE CLASS myClass AS Custom
   PROCEDURE test2
        PARAMETERS objTextBox AS TextBox , p as Object
        objTextBox .Value = "this refrence.!" && call by refernce
    ENDPROCEDURE
  ENDDEFINE

  DEFINE CLASS sample1 AS Form
  hidden myTxtBox = .f.  && Define a property and determine its type by the compiler 
 
   PROCEDURE init
        *!* initialize property and Objects
        myClass = createobject("myClass.vcx")
        myTxtBox = createobject("TextBox")
   ENDPROCEDURE

   PROCEDURE Click_TextBox  
        myClass.test2(this.myTxtBox)
   ENDPROCEDURE

   ENDDEFINE
       در برنامه نویسی با ویژوال فاکس پرو برای دسترسی به متدها و خصوصیت های یک آبجکت می توانید از عملگر .(نقطه) ویا از علامت <- نیز برای دسترسی استفاده نمایید دقیقا مشابه به والد خود زبان سی پس توجه داشته باشید علامت (<-) فوق هیچ ربطی به عبارت های پیشرفته تعریف عبارتهای بی نام در زبانهای ساختار یافته شی گرا ندارد بنابراین
objTextBox .Value = "this refrence.!" && call by refernce
و دستور زیر دقیقا یکسان می باشند
objTextBox -> Value = "this refrence.!" && call by refernce

: نکته برنامه نویسی
در ویژوال فاکس پرو در زمان ایجاد یک شی جدید و یا تعریف یک نوع داده اولیه امکان تعریف نوع آن امکانپذیر نمی باشد بنابراین در زمان اجرای برنامه نوع ها را کامپایلر تعیین میکند


برای متدها همچنین امکان تعریف مقدار بازگشتی به محل ارجاع متد نیز وجود دارد با استفاده از دستور

Return مقدار برگشتی
و همچنین توجه نمایید که نوع مقدار خروجی متد چون تعریف نمی شود پس باید برنامه نویس توجه داشته باشد که چه نوعی را به عنوان بازگشت متد در حال دریافت می باشد تا از نوع درست آن استفاده نماید و همچنین در زمان طراحی فرم و کلاس دیزاین مد هم نمی توانید از نوع بازگشتی متد اطلاع داشته باشید
البته با دستور بازگشت امکان بازگشت مقادیر در زمان تعریف متدهای بازگشتی و یا ارسال یک مقدار به یک متد با استفاده ازنام آن متد امکانپذیر می باشد که در جای مناسب تر و در زمان نیاز به آنها اشاره خواهم کرد