Skip to content

5. توابع و رویه‌ها

5.1. تابع‌های از پیش تعریف‌شده VBScript

ثروت یک زبان تا حد زیادی از کتابخانه توابع آن ناشی می‌شود که ممکن است به صورت متدها در اشیاء محصور شوند. از این نظر، VBScript را می‌توان نسبتاً محدود دانست.

جدول زیر توابع VBScript را که جزئی از اشیاء نیستند، فهرست می‌کند. در اینجا به جزئیات آن‌ها نمی‌پردازیم. نام آن‌ها عموماً نشان‌دهنده هدفشان است. خوانندگان برای جزئیات مربوط به تابع خاص، باید به مستندات مراجعه کنند.

Abs
آرایه
Asc
Atn
CBool
CByte
CCur
CDate
CDbl
Chr
CInt
CLng
تبدیل‌ها
Cos
CreateObject
CSng
تاریخ
DateAdd
DateDiff
DatePart
DateSerial
DateValue
روز
ریاضیات مشتق‌شده
ارزیابی
Expression
فیلتر
FormatCurrency
FormatDateTime
FormatNumber
FormatPercent
GetLocale
GetObject
GetRef
هگز
ساعت
InputBox
InStr
InStrRev
داخلی، ثابت
IsArray
IsDate
IsEmpty
IsNull
IsNumeric
IsObject
پیوستن
LBound
LCase
چپ
لن
LoadPicture
لاگ
LTrim; RTrim; و Trims
ریاضی
میان
دقیقه
ماه
MonthName
MsgBox
اکنون
اکتبر
جایگزین کنید
RGB
درست
Rnd
گرد
ScriptEngine
ScriptEngineBuildVersion
ScriptEngineMajorVersion
ScriptEngineMinorVersion
دوم
SetLocale
Sgn
گناه
فضا
تک‌تکه
مربع
StrComp
رشته
قهوه‌ای
زمان
تایمر
TimeSerial
TimeValue
TypeName
UBound
UCase
VarType
روز هفته
WeekdayName
سال

5.2. برنامه‌نویسی ماژولار

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

  • خواندن داده‌ها از صفحه‌کلید یا دیسک
  • نوشتن داده‌ها روی صفحه نمایش، چاپگر، دیسک و غیره.
  • محاسبه عبارت‌ها
  • پیمایش در یک فایل
  • ...

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

ما می‌توانیم در ابتدا راه‌حل را به شکل زیر توصیف کنیم:

  début
        lire les valeurs et les mettre dans un tableau T
        trier le tableau T
        écrire les valeurs triées du tableau T à l'écran
  fin

ما مسئله را به سه زیرمسئله تقسیم کرده‌ایم که حل آن‌ها ساده‌تر است. نشانه‌گذاری الگوریتمی اغلب رسمی‌تر از مورد قبلی است و الگوریتم به صورت زیر نوشته می‌شود:

   début
         lire_tableau(T)
         trier_tableau(T)
         écrire_tableau(T)
   fin

که در آن T نشان‌دهنده یک آرایه است. عملیات‌ها

    . lire_tableau(T)
    . trier_tableau(T)
    . écrire_tableau(T)

عملیات غیرابتدایی هستند که به نوبه خود باید توسط عملیات ابتدایی توصیف شوند. این کار در واحدهایی به نام ماژول‌ها انجام می‌شود. داده T پارامتر ماژول نامیده می‌شود. این اطلاعاتی است که برنامه فراخواننده به ماژول فراخوانده شده می‌فرستد (پارامتر ورودی) یا از آن دریافت می‌کند (پارامتر خروجی). بنابراین، پارامترهای یک ماژول، اطلاعات مبادله‌شده بین برنامه فراخواننده و ماژول فراخوانده‌شده هستند.

ماژول lire_tableau(T)
ماژول trier_tableau(T)
ماژول écrire_tableau(T)

ماژول lire_tableau(T) می‌تواند به شرح زیر توصیف شود:


début
    écrire "Tapez la suite de valeurs à trier sous la forme val1 val2 ... : "
    lire valeurs
    construire tableau T à partir de la chaîne valeurs
fin

در اینجا، ما توضیح کافی از ماژول lire_tableau را ارائه کرده‌ایم. در واقع، سه اقدام مورد نیاز معادل مستقیمی در VBScript دارند. اقدام آخر نیازمند استفاده از تابع SPLIT خواهد بود. اگر VBScript این تابع را نداشت، اقدام ۳ نیز به نوبه خود باید به اقدامات پایه‌ای که معادل مستقیم در VBScript دارند، تقسیم می‌شد.

ماژول écrire_tableau(T) می‌تواند به شرح زیر توصیف شود:


début
    construire chaîne texte "valeur1,valeur2,...." à partir du tableau T
    écrire texte
fin

ماژول écrire_tableau(T) می‌تواند به صورت زیر توصیف شود (با فرض اینکه شاخص‌های عناصر در T از 0 شروع می‌شوند):

début
      N<-- indice dernier élément du tableau T
      pour IFIN variant de N à 1
      faire
           //: جستجوی شاخص IMAX بزرگ‌ترین عنصر در T
           //IFIN نمایه آخرین عنصر T است

          chercher_max(T, IFIN, IMAX) 

           // بزرگ‌ترین عنصر T را با آخرین عنصر T جابه‌جا می‌کند

          échanger (T, IMAX, IFIN)

      finfaire
FIN

در اینجا، الگوریتم بار دیگر از عملیات غیرابتدایی استفاده می‌کند:


 . chercher_max(T, IFIN, IMAX)
 . échanger(T, IMAX, IFIN)

chercher_max(T, IFIN, IMAX) شاخص IMAX بزرگ‌ترین عنصر آرایه T را بازمی‌گرداند، جایی که شاخص آخرین عنصر IFIN است.

تابع swap(T, IMAX, IFIN) دو عنصر از آرایه T را که شاخص‌هایشان IMAX و IFIN هستند، با هم جابجا می‌کند.

بنابراین باید عملیات جدید غیرابتدایی را توصیف کنیم.

ماژول chercher_max(A, IFIN, IMAX)
   début
        IMAX<--0

        pour i variant de 1 à IFIN
        faire
           si T[i]>T[IMAX] alors 
             début
                IMAX<--i
             fin
        finfaire
    fin
ماژول تعویض (T IMAX, IFIN)
  début
       temp<----T[IMAX]
       T[IMAX]<---T[IFIN]
       T[IFIN]<---temp
  fin

مسئله اولیه با استفاده از عملیات پایه‌ای VBScript به‌طور کامل توصیف شده و بنابراین اکنون می‌توان آن را به این زبان ترجمه کرد. شایان ذکر است که عملیات پایه‌ای ممکن است از زبانی به زبان دیگر متفاوت باشد و در نتیجه، تحلیل یک مسئله باید در مقطعی زبان برنامه‌نویسی مورد استفاده را در نظر بگیرد. ابجکتی که در یک زبان وجود دارد ممکن است در زبان دیگری وجود نداشته باشد و بدین ترتیب الگوریتم مورد استفاده را تغییر دهد. بنابراین، اگر یک زبان تابع مرتب‌سازی داشت، بی‌معنی است که از آن در اینجا استفاده نکنیم.

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

ما یک ساختار درختی داریم.

5.3. توابع و رویه‌های VBScript

پس از انجام تحلیل مدولار، برنامه‌نویس می‌تواند ماژول‌های الگوریتم خود را به توابع VBScript مانند fonctions یا procédures تبدیل کند. هر دو fonctions و procédures پارامترهای ورودی/خروجی را می‌پذیرند، اما fonction نتیجه‌ای را بازمی‌گرداند که امکان استفاده از آن را در عبارت‌ها فراهم می‌کند، در حالی که procédure چنین امکانی را ندارد.

5.3.1. اعلام توابع و رویه‌های VBScript

یک رویه VBScript به صورت زیر اعلام می‌شود

sub nomProcédure([Byref/Byval] param1, [Byref/Byval] param2, ...)
    instructions
end sub

و تابع به شرح زیر اعلام می‌شود

function nomFonction([Byref/Byval] param1, [Byref/Byval] param2, ...)
    instructions
end sub

برای بازگرداندن نتیجه، تابع باید شامل یک عبارت تخصیص باشد که نتیجه را به متغیری با همان نام تابع تخصیص می‌دهد:

functionName=result

اجرای یک تابع یا رویه به دو صورت پایان می‌یابد:

  1. با برخورد به دستور 'end function' یا 'end sub'
  2. با برخورد با دستور 'exit function' یا 'exit sub'

برای یک تابع، مهم است به خاطر داشته باشید که نتیجه باید قبل از پایان تابع با دستور 'end function' یا 'exit function' به متغیری با همان نام تابع تخصیص داده شده باشد.

5.3.2. روش‌های ارسال پارامترها به یک تابع یا رویه

هنگام اعلام پارامترهای ورودی و خروجی یک تابع یا رویه، مد (byRef, byVal) که پارامتر از برنامه فراخوانی‌کننده به برنامه فراخوانی‌شونده با آن منتقل می‌شود، مشخص می‌گردد:

sub nomProcédure([Byref/Byval] param1, [Byref/Byval] param2, ...)

function nomFonction([Byref/Byval] param1, [Byref/Byval] param2, ...)

در صورتی که حالت انتقال byRef یا byVal مشخص نشده باشد، از حالت byRef استفاده می‌شود.

پارامترهای واقعی، پارامترهای اسمی

بیایید تابع VBScript تعریف‌شده توسط

function nomFonction([Byref/Byval] paramForm1, [Byref/Byval] paramForm2, ...)
...
end function

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

résultat=nomFonction(paramEff1, paramEff2, ...)

پارامترهای parmamEffi که در فراخوانی تابع یا رویه استفاده می‌شوند، پارامترهای حقیقی نامیده می‌شوند. هنگامی که اجرای تابع nomFonction آغاز می‌شود، مقادیر پارامترهای شکلی با مقادیر پارامترهای حقیقی متناظر تخصیص می‌یابد. کلیدواژه‌های byRef و byVal حالت انتقال مقدار را تعیین می‌کنند.

حالت انتقال با مقدار (byVal)

وقتی یک پارامتر صوری این روش گذراندن را مشخص می‌کند، پارامتر صوری و پارامتر حقیقی دو متغیر مجزا هستند. مقدار پارامتر حقیقی قبل از اجرای تابع یا رویه، در پارامتر شکلی کپی می‌شود. اگر تابع یا رویه در حین اجرا مقدار پارامتر شکلی را تغییر دهد، این امر به هیچ وجه بر مقدار پارامتر حقیقی متناظر تأثیر نمی‌گذارد. این حالت ارسال برای پارامترهای ورودی یک تابع یا رویه بسیار مناسب است.

حالت گذراندن به صورت مرجع (byRef)

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

  • پارامترهای خروجی، زیرا مقادیر آن‌ها باید به برنامه فراخواننده بازگردانده شوند
  • پارامترهای ورودی که کپی کردن آنها دشوار است، مانند آرایه‌ها

برنامه زیر نمونه‌هایی از ارسال پارامتر را نشان می‌دهد:

برنامه

Sub proc1(byval i, ByRef j, k)
  ' i توسط مقدار (byval) ارسال می‌شود – پارامتر حقیقی و پارامتر صوری بنابراین متفاوت هستند
  ' j به صورت مقدار (byval) ارسال می‌شود – پارامتر واقعی و پارامتر رسمی بنابراین یکسان هستند
  ' حالت ارسال برای k مشخص نشده است. به‌طور پیش‌فرض، این ارسال به مرجع است
  i=i+1
  j=j+1
  k=k+1
  affiche "dans proc1",i,j,k
End Sub

 Sub affiche(byval msg, ByVal i, ByVal j, ByVal k)
  'مقادیر i، j و k را نمایش می‌دهد
  wscript.echo msg & " i=" & i & " j=" & j & " k=" & k
End Sub


' ------------- فراخوانی توابع و رویه‌ها

' ابتدایی‌سازی i و j
  i=4:j=5 : k=6

'بررسی
  affiche "dans programme principal, avant l'appel à proc1 :",i,j,k

'فراخوانی رویه proc1
  proc1 i,j,k

'بررسی
  affiche "dans programme principal, après l'appel à proc1 :",i,j,k

' پایان
  wscript.quit 0
نتایج
dans programme principal, avant l'appel à proc1 : i=4 j=5 k=6
dans proc1 i=5 j=6 k=7
dans programme principal, après l'appel à proc1 : i=4 j=6 k=7

توضیحات

  • در یک اسکریپت VBScript، جای مشخصی برای توابع و رویه‌ها وجود ندارد. آنها می‌توانند در هر نقطه‌ای از کد منبع ظاهر شوند. به طور کلی، آنها یا در ابتدا یا در انتها گروه‌بندی می‌شوند و دقت می‌شود که برنامه اصلی یک بلوک پیوسته را تشکیل دهد.

5.3.3. نحو فراخوانی توابع و رویه‌ها

فرض کنید p یک رویه است که پارامترهای اسمی pf1، pf2، ... را می‌پذیرد

  • روال p به صورت زیر فراخوانی می‌شود
p pe1, pe2, ...

بدون پرانتز دور پارامترها

  • اگر رویه p هیچ پارامتری نداشته باشد، می‌توان از فراخوانی p یا p() و اعلامیه sub p یا sub p() استفاده کرد

فرض کنید f تابعی است که پارامترهای رسمی pf1، pf2، ... را می‌پذیرد.

  • فراخوانی تابع f به شکل زیر است
résultat=f(pe1, pe2, ...)

کروشه‌ها دور پارامترها ضروری است. اگر تابع f هیچ پارامتری نداشته باشد، می‌توان از فراخوانی f یا f() و اعلامیه‌ی function f یا function f() استفاده کرد.

  • نتیجهٔ تابع f ممکن است توسط برنامهٔ فراخواننده نادیده گرفته شود. در این صورت، تابع f به‌عنوان یک رویه در نظر گرفته شده و از قواعد فراخوانی رویه‌ها پیروی می‌کند. در این حالت، برای فراخوانی تابع f، f pe1, pe2, ... (بدون پرانتز) نوشته می‌شود.

اگر تابع یا رویه یک متد شیء باشد، به نظر می‌رسد که قوانین تا حدی متفاوت و ناسازگار هستند.

  • برای مثال، می‌توان نوشت MyFile.WriteLine "This is a test." یا MyFile.WriteLine("This is a test.")
  • اما در حالی که می‌توانید wscript.echo 4 را بنویسید، نمی‌توانید wscript.echo(4) را بنویسید.

ما از قوانین زیر پیروی خواهیم کرد:

  • بدون پرانتز دور پارامترهای یک رویه یا تابع که به‌عنوان رویه استفاده می‌شود
  • کروشه‌ها دور پارامترهای یک تابع

5.3.4. چند مثال از توابع

در زیر چند مثال از تعریف و کاربرد توابع آورده شده است:

برنامه

 Function plusgrandque(byval i, ByVal j)
  ' اگر i > j باشد مقدار true و در غیر این صورت مقدار false را برمی‌گرداند

  'اعتبارسنجی داده‌ها
  If isnumeric(i) And isnumeric(j) Then
    If i>j Then
      plusgrandque=true
    Else
      plusgrandque=false
    End If
  Else
    wscript.echo "Arguments (" & i & "," & j & ") erronés"
    plusgrandque=false
  End If
  Exit Function
End Function

 Function rendUnTableau(byval n)
  ' یک آرایه با n عنصر را بازمی‌گرداند
  tableau=array()
  ' اعتبار پارامتر n را بررسی می‌کند
  If isnumeric(n) And n>=1 Then
    ReDim Preserve tableau(n)
    For i= 0 To n-1
      tableau(i)=i
    Next
  Else
    wscript.echo "Argument [" & n & "] erroné"
  End If
  'نتیجه را بازمی‌گرداند
  rendUnTableau=tableau
End Function

 Function argumentsVariables(byref arguments)
  ' آرگومان‌ها یک آرایه از اعداد است که جمع آن‌ها بازگردانده می‌شود
  somme=0
  For i=0 To ubound(arguments)
    somme=somme+arguments(i)
  Next
  argumentsVariables=somme
End Function

  ' دو تابع بدون پارامتر که به دو روش متفاوت تعریف شده‌اند
  Function sansParametres1
    sansParametres=4
  End Function

  Function sansParametres2()
    sansParametres=4
  End Function

  
' ------------- فراخوانی توابع و رویه‌ها

' فراخوانی‌های تابع 'greaterThan'
  wscript.echo "plusgrandque(10,6)=" & plusgrandque(10,6)
  wscript.echo "plusgrandque(6,10)=" & plusgrandque(6,10)
  wscript.echo "plusgrandque(6,6)=" & plusgrandque(6,6)
  wscript.echo "plusgrandque(6,'a')=" & plusgrandque(6,"a")

' فراخوانی تابع rendUnTableau
  monTableau=rendUnTableau(10)
  For i=0 To ubound(monTableau)
    wscript.echo monTableau(i)
  Next
  monTableau=rendUnTableau(-6)
  For i=0 To ubound(monTableau)
    wscript.echo monTableau(i)
  Next

' فراخوانی تابع argumentsVariables
  wscript.echo "somme=" & argumentsVariables(array(-1,2,7,8))
  wscript.echo "somme=" & argumentsVariables(array(-1,10,12))

' فراخوانی تابع‌ها بدون پارامتر
  res=sansParametres1
  res=sansParametres1()
  sansParametres1
  sansParametres1()

  res=sansParametres2
  res=sansParametres2()
  sansParametres2
  sansParametres2()

'پایان
  wscript.quit 0
نتایج
plusgrandque(10,6)=Vrai
plusgrandque(6,10)=Faux
plusgrandque(6,6)=Faux
Arguments (6,a) erronés
plusgrandque(6,'a')=Faux
0
1
2
3
4
5
6
7
8
9

Argument [-6] erroné
somme=16
somme=21
somme=10

نظرات

  • تابع rendUnTableau نشان می‌دهد که یک تابع می‌تواند به جای یک نتیجه، چندین نتیجه بازگرداند. تنها کاری که باید انجام دهد این است که آن‌ها را در یک واریانت آرایه قرار دهد و آن واریانت را به عنوان نتیجه بازگرداند.
  • برعکس، تابع argumentsVariables نشان می‌دهد که می‌توان تابعی نوشت که تعداد متغیری آرگومان را بپذیرد. در اینجا نیز، صرفاً کافی است آن‌ها را در یک واریانت آرایه قرار داده و این واریانت را به عنوان پارامتر تابع در نظر بگیریم.

5.3.5. پارامتر خروجی یا نتیجه تابع

فرض کنید تحلیل یک برنامه کاربردی، نیاز به ماژولی به نام M با پارامترهای ورودی Ei و پارامترهای خروجی Sj را نشان داده است. به یاد داشته باشید که پارامترهای ورودی، اطلاعاتی هستند که برنامه فراخواننده در اختیار برنامه فراخوانده‌شده قرار می‌دهد و برعکس، پارامترهای خروجی، اطلاعاتی هستند که برنامه فراخوانده‌شده در اختیار برنامه فراخواننده قرار می‌دهد. در VBScript، چندین راه‌حل برای پارامترهای خروجی وجود دارد:

  • اگر تنها یک پارامتر خروجی وجود داشته باشد، می‌توان آن را به عنوان نتیجه تابع در نظر گرفت. در این حالت، دیگر از پارامتر خروجی صحبت نمی‌شود، بلکه صرفاً از نتیجه تابع صحبت می‌شود.
  • اگر n پارامتر خروجی وجود داشته باشد، یکی از آنها می‌تواند به عنوان نتیجه تابع عمل کند و n-1 پارامتر باقی‌مانده به عنوان پارامترهای خروجی عمل می‌کنند. به عنوان جایگزینی دیگر، به جای یک تابع، می‌توان از یک رویه با n پارامتر خروجی استفاده کرد. همچنین می‌توان از توابعی استفاده کرد که آرایه‌ای حاوی n مقدار را برای بازگشت به برنامه فراخوانی‌کننده برمی‌گردانند. شایان ذکر است که برنامه فراخوانی‌شونده نتایج خود را به برنامه فراخوانی‌کننده به صورت مقدار بازمی‌گرداند. این کپی‌برداری هنگامی که پارامترهای خروجی به صورت ارجاعی ارسال شوند، اجتناب می‌شود. بنابراین، این راه‌حل دوم در زمان صرفه‌جویی می‌کند.

5.4. برنامه VBScript برای مرتب‌سازی مقادیر

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

برنامه
' برنامهٔ اصلی
Option Explicit

Dim T        ' le tableau de valeurs à trier

' خواندن مقادیر
T=lire_tableau

'مرتب‌سازی مقادیر
trier_tableau T

'نمایش مقادیر مرتب‌شده
ecrire_tableau T

' پایان
wscript.quit 0

' ---------- توابع و رویه‌ها

' -------- lire_tableau
Function lire_tableau
    'مقادیر درخواست شده‌اند
    wscript.stdout.write "Tapez les valeurs à trier sous la forme val1 val2  ... valn : "
    ' آنها را می‌خوانیم
    Dim valeurs
    valeurs=wscript.stdin.readLine
    ' آنها را در یک آرایه ذخیره می‌کنیم
    lire_tableau=split(valeurs," ")
End Function

' -------- ecrire_tableau
Sub ecrire_tableau(byref T)
    ' محتویات آرایه T را نمایش می‌دهد
    wscript.echo join(T," ")
End Sub

' -------- trier_tableau
Sub trier_tableau (byref T)
    'آرایه T را به ترتیب صعودی مرتب می‌کند

    ' شاخص imax آرایه T[0..ifin] را پیدا می‌کند
    'برای جابه‌جایی T[imax] با آخرین عنصر آرایه T[0..ifin]
    'سپس دوباره با آرایه‌ای که یک عنصر کمتر دارد شروع می‌کنیم

    Dim ifin, imax, temp
    For ifin=ubound(T) To 1 Step -1
        ' ما شاخص imax آرایه T[0..ifin] را پیدا می‌کنیم
        imax=chercher_max(T,ifin)
        ' ما بیشترین مقدار را با آخرین عنصر آرایه T[0..ifin] جا‌به‌جا می‌کنیم
        temp=T(ifin):T(ifin)=T(imax):T(imax)=temp
    Next
End Sub

' -------- chercher_max
Function chercher_max(byRef T, ByVal ifin)
    ' ما اندیس imax را در آرایه T[0..ifin] جستجو می‌کنیم
    Dim i, imax
    imax=0
    For i=1 To ifin
        If cdbl(T(i))>cdbl(T(imax)) Then imax=i
    Next

    ' نتیجه بازگردانده می‌شود
    chercher_max=imax    
End Function
نتایج
Tapez les valeurs à trier sous la forme val1 val2  ... valn : 10 9 8 7 6 1
1 6 7 8 9 10

توضیحات:

  • ماژول échanger که در الگوریتم اولیه شناسایی شده بود، در اینجا به عنوان یک ماژول VBScript پیاده‌سازی نشد، زیرا بسیار ساده تشخیص داده شد و شایسته یک ماژول جداگانه نبود.

5.5. برنامه IMPOTS به صورت مدولار

ما در حال بازنویسی برنامه محاسبه مالیات هستیم، این بار به صورت مدولار نوشته شده است

برنامه
'محاسبه مالیات یک مؤدی
' برنامه باید با سه پارامتر فراخوانی شود: متأهل، تعداد فرزندان، حقوق
' married: کاراکتر 'O' اگر متأهل، 'N' اگر مجرد
' فرزندان: تعداد فرزندان
' حقوق: حقوق سالانه بدون احتساب پنی

' اعلام متغیر الزامی
Option Explicit
Dim erreur

' آرگومان‌ها با بررسی اعتبارشان بازیابی می‌شوند
Dim marie, enfants, salaire
erreur=getArguments(marie,enfants,salaire)
' خطا؟
If erreur(0)<>0 Then wscript.echo erreur(1) : wscript.quit erreur(0)

' بازیابی داده‌های مورد نیاز برای محاسبه مالیات
Dim limites, coeffR, coeffN
getData limites,coeffR,coeffN

' نمایش نتیجه
wscript.echo "impôt=" & calculerImpot(marie,enfants,salaire,limites,coeffR,coeffN)

'خروج بدون خطا
wscript.quit 0

' ------------ توابع و رویه‌ها

' ----------- getArguments
Function getArguments(byref marie, ByRef enfants, ByRef salaire)
    ' باید سه مقدار را که به‌عنوان آرگومان به برنامهٔ اصلی ارسال شده‌اند، بازیابی کند
    ' یک آرگومان بدون فاصله قبل یا بعد از آن به برنامه ارسال می‌شود
    ' برای بررسی اعتبار داده‌ها از عبارت‌های منظم استفاده خواهد شد

    ' یک نوع آرایه خطا را بازمی‌گرداند که شامل دو مقدار است
    ' error(0): کد خطا، 0 در صورت عدم وجود خطا
    ' error(1): پیام خطا در صورت رخ دادن خطا، در غیر این صورت یک رشته خالی

    Dim syntaxe
    syntaxe= _
    "Syntaxe : pg marié enfants salaire" & vbCRLF & _
    "marié : caractère O si marié, N si non marié" & vbCRLF & _
    "enfants : nombre d'enfants (entier >=0)" & vbCRLF & _
    "salaire : salaire annuel sans les centimes (entier >=0)"

    'بررسی می‌کند که ۳ آرگومان وجود دارد
    Dim nbArguments
    nbArguments=wscript.arguments.count
    If nbArguments<>3 Then
        ' پیام خطا
        getArguments= array(1,syntaxe & vbCRLF & vbCRLF & "erreur : nombre d'arguments incorrect")
        ' پایان
        Exit Function
    End If

    Dim modele, correspondances
    Set modele=new regexp

    'وضعیت تأهل باید شامل حروف oOnN باشد
    modele.pattern="^[oOnN]$"
    Set correspondances=modele.execute(wscript.arguments(0))
    If correspondances.count=0 Then
        ' پیام خطا
        getArguments=array(2,syntaxe & vbCRLF & vbCRLF & "erreur : argument marie incorrect")
        'خروج
        Exit Function
    End If
    ' بازیابی مقدار
    If lcase(wscript.arguments(0)) = "o"Then
        marie=true
    Else
        marie=false
    End If

    ' فرزندان باید یک عدد صحیح ≥ ۰ باشند
    modele.pattern="^\d{1,2}$"
    Set correspondances=modele.execute(wscript.arguments(1))
    If correspondances.count=0 Then
        ' خطا
        getArguments= array(3,syntaxe & vbCRLF & vbCRLF & "erreur : argument enfants incorrect")
        'خروج
        Exit Function
    End If
    ' ارزش را بازیابی کنید
    enfants=cint(wscript.arguments(1))

    ' حقوق باید یک عدد صحیح ≥ ۰ باشد
    modele.pattern="^\d{1,9}$"
    Set correspondances=modele.execute(wscript.arguments(2))
    If correspondances.count=0 Then
        'خطا
        getArguments= array(4,syntaxe & vbCRLF & vbCRLF & "erreur : argument salaire incorrect")
        'خروج
        Exit Function
    End If
    ' بازیابی مقدار
    salaire=clng(wscript.arguments(2))

    ' بدون خطا تکمیل شد
    getArguments=array(0,"")
End Function

' ----------- getData
Sub getData(byref limites, ByRef coeffR, ByRef coeffN)  
    ' ما داده‌های مورد نیاز برای محاسبه مالیات را در ۳ جدول تعریف می‌کنیم
    limites=array(12620,13190,15640,24740,31810,39970,48360, _
    55790,92970,127860,151250,172040,195000,0)
    coeffr=array(0,0.05,0.1,0.15,0.2,0.25,0.3,0.35,0.4,0.45, _
    0.5,0.55,0.6,0.65)
    coeffn=array(0,631,1290.5,2072.5,3309.5,4900,6898.5,9316.5, _
    12106,16754.5,23147.5,30710,39312,49062)
End Sub

' ----------- calculerImpot
Function calculerImpot(byval marie,ByVal enfants,ByVal salaire, ByRef limites, ByRef coeffR, ByRef coeffN)

    ' تعداد سهام محاسبه می‌شود
    Dim nbParts
    If marie=true Then
        nbParts=(enfants/2)+2
    Else
        nbParts=(enfants/2)+1
    End If
    If enfants>=3 Then nbParts=nbParts+0.5

    ' ضریب خانوادگی و درآمد مشمول مالیات محاسبه می‌شوند
    Dim revenu, qf
    revenu=0.72*salaire
    qf=revenu/nbParts

    ' محاسبه مالیات
    Dim i, impot
    i=0
    Do While i<ubound(limites) And qf>limites(i)
        i=i+1
    Loop
    calculerImpot=int(revenu*coeffr(i)-nbParts*coeffn(i))
End Function

نظرات

  • تابع getArguments جزئیات مالیات‌دهنده (همسر، فرزندان، حقوق) را بازیابی می‌کند. در اینجا، این موارد به عنوان آرگومان به برنامه VBScript ارسال می‌شوند. اگر این تغییر کند – برای مثال، اگر این آرگومان‌ها از یک رابط کاربری گرافیکی تأمین شوند – تنها رویه getArguments نیاز به بازنویسی دارد و نه موارد دیگر.
  • تابع getArguments می‌تواند خطاها را در آرگومان‌ها تشخیص دهد. هنگامی که این اتفاق می‌افتد، ممکن است تصمیم گرفته شده باشد که اجرای برنامه را در داخل تابع getArguments با استفاده از یک دستور wscript.quit متوقف کنند. این کار هرگز نباید در داخل یک تابع یا رویه انجام شود. اگر یک تابع یا رویه خطایی را تشخیص دهد، باید به نحوی آن را به برنامه فراخواننده گزارش دهد. تصمیم‌گیری برای متوقف کردن اجرای برنامه یا عدم توقف آن بر عهده خودِ برنامه فراخواننده است، نه رویه. در مثال ما، برنامه فراخواننده ممکن است به جای متوقف کردن اجرا، تصمیم بگیرد از کاربر بخواهد که داده‌های نادرست را مجدداً از طریق صفحه‌کلید وارد کند.
  • در اینجا، تابع getArguments آرایه‌ای از نوع variant را بازمی‌گرداند که عنصر اول آن کد خطا (در صورت عدم وجود خطا برابر با 0) و عنصر دوم آن پیام خطا در صورت وقوع خطا است. با بررسی نتیجه بازگردانده‌شده، برنامه فراخواننده می‌تواند تشخیص دهد که آیا خطایی رخ داده است یا خیر.
  • روال getData داده‌های مورد نیاز برای محاسبه مالیات را بازیابی می‌کند. در اینجا، این داده‌ها مستقیماً در داخل رویه getData تعریف شده‌اند. اگر این داده‌ها از منبع دیگری – برای مثال یک فایل یا پایگاه داده – تأمین می‌شدند، تنها رویه getData نیاز به بازنویسی داشت و نه رویه‌های دیگر.
  • تابع calculerImpot پس از به‌دست آمدن تمام داده‌ها، مالیات را محاسبه می‌کند، صرف‌نظر از نحوهٔ به‌دست آوردن آن‌ها.
  • بنابراین باید توجه داشت که رویکرد مدولار امکان استفاده مجدد از برخی ماژول‌ها در زمینه‌های مختلف را فراهم می‌کند. در طول بیست سال گذشته، این مفهوم در برنامه‌نویسی شیءگرا به طور گسترده‌ای توسعه یافته است.