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

وقتی که برنامه نویسانِ تازه کار، کدهای خود را محدوده سنجی(range check) می کنند، اغلب در آن، یک سری کدهای اشتباه یا ناکارآمد مشاهده می کنند.  محدوده سنجی(range check) یک سری دستورات است که مشخص می کند یک مقدار(value) در کدام مجموعه از محدوده ها قرار می گیرد.

وضعیتی را در نظر بگیرید که فروشندگان می توانند بسته به فروش خود، یکی از سه نرخ کمیسیون امکان پذیر را دریافت کنند. بعنوان مثال، یک فروش به مبلغ 1000 دلار یا بیشتر، 8% حق کمیسیون به فروشنده می دهد. و یک فروش به مبلغ 500 تا 999 دلار، 6% حق کمیسیون به فروشنده می دهد و هر فروشی که به مبلغ 499.99 دلار یا کمتر باشد، 5% حق کمیسیون به فروشنده می دهد. 

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

(تصویر  5.14  : یک کد اشتباه برای مشخص کردن کمیسیون)

با استفاده از کد نشان داده شده در تصویر 5.14 وقتی که مقدار فروش(saleAmount) برابر با 5000 دلار می شود، بعنوان مثال، اولین دستور if اجرا می شود، و عبارت بولین (saleAmount >= HIGH_LIM) بعنوان true ارزیابی می شود؛ پس HIGH_RATE به درستی به commissionRate (حق کمیسیون) انتساب داده می شود. 

اما وقتی که مقدار فروش(saleAmount) برابر با 5000 دلار باشد، عبارت if بعدی، یعنی (saleAmount >= MED_LIM) نیز به صورت true ارزیابی می شود(چون saleAmount از مقدار MED_LIM یعنی مقدار متوسط، بزرگتر است)؛ بنابراین commissionRate (حق کمیسیون) که فقط روی HIGH_RATE تنظیم شده بود، به صورت نادرست، روی MED_RATE نیز تنظیم می شود. 

یک راه حل جزئی برای حل این مشکل این است که از یک دستور else پس از اولین ارزیابی(evaluation) استفاده کنیم، همان طور که در تصویر 5.15 نشان داده شده است:

(تصویر 5.15 : کدها بهتر شده است اما کد مشخص کردن کمیسیون ناکارآمد است)

آموزش جاوا الگوریتم

با کد جدیدی که در تصویر 5.15 قرار دارد، وقتی که saleAmount (مقدار فروش) برابر با 5000 دلار است، عبارت مورد نظر true است و حق کمیسیون(commissionRate) برابر با HIGH_RATE می شود. سپس (چون saleAmount >= HIGH_LIM) تمام ساختار if به انتها می رسد. 

وقتی که saleAmount (مقدار فروش) بزرگتر یا مساوی با 1000 دلار نباشد(بعنوان مثال 800 دلار باشد) اولین دستور if برابر با false می شود و دستور else اجرا می شود و به درستی commissionRate را برابر با MED_RATE قرار می دهد. 


کدهای نشان داده شده در تصویر 5.15 کار می کند اما تا حدودی ناکارآمد است. 

وقتی که saleAmount (مقدار فروش) هر مقداری بیش از LOW_RATE باشد، آنگاه یا if اول، برای مقادیری که حداقل 1000 دلار هستند، مقدار HIGH_RATE را در commissionRate قرار می دهد، یا دستور else آن، برای مقادیری که حداقل 500 دلار هستند، مقدار MED_RATE رادر commissionRate تنظیم می کند. 

در هر یک از این دو مورد، مقدار بولین در دستور بعدی تست شده است؛ اگر if (saleAmount <= LOW_LIM) همواره false باشد، commissionRate به درستی تنظیم می شود. اما این غیر ضروری بود که سوال LOW_LIM را بپرسیم. 

پس از اینکه بدانیم که saleAmount حداقل برابر با MED_LIM نیست به جای اینکه بپرسیم if(saleAmount <= LOW_LIM) ، ساده تر و کارآمدتر و کم خطاتر است که از یک else استفاده کنیم. 

اگر saleAmount حداقل برابر با HIGH_LIM نباشد، و نیز حداقل برابر با MED_LIM نباشد، به طور پیش فرض باید کوچکتر یا مساوی با LOW_LIM باشد. تصویر 5.16 این منطق بهبود یافته را نشان می دهد:

(تصویر 5.16 : منطق بهبود یافته حق کمیسیون در جاوا)

نکته: در کدهای تصویر 5.16، ثابت LOW_LIM دیگر تعریف نمی شود، زیرا دیگر از آن استفاده نمی شود. 

در داخل یک if....else تو در تو مانند آنچه در تصویر 5.16 نشان داده شد، بهترین کار این است که ابتدا سؤالی را بپرسیم که به احتمال زیاد درست است. به عبارت دیگر، اگر می دانید که بیشتر مقادیرِ saleAmount اعدادی بزرگ(high) هستند، ابتدا saleAmount را با HIGH_LIM مقایسه کنید. به این طریق، اغلب از پرسیدن سوالات گوناگون جلوگیری می شود. 

اما اگر می دانید که بیشتر مقادیر saleAmount اعدادی کوچک هستند، ابتدا باید بپرسید if(saleAmount < LOW_LIM). کدهای نشان داده شده در تصویر 5.17 منجر به همان مقدار کمیسیون برای هر saleAmount داده شده می شود، اما در شرایطی که بیشتر مقادیر saleAmount کوچک هستند. 

(تصویر 5.17 : کد مشخص کردن کمیسیون که اول از کوچکترین مقادیر saleAmount سوال می کند)

استفاده از کوچکترین مقادیر


بررسی شود:

نکته: در تصویر 5.17 توجه کنید که مقایسه ها به جای استفاده از عملگر => از > استفاده می کنند. دلیلش این است که یک saleAmount با مقدار 1000.00 دلار، باید منجر به استفاده از HIGH_RATE شود و یک saleAmount با مقدار 500.00 دلار باید منجر به استفاده از MED_RATE شود. اگر می خواستیم از عملگر مقایسه ی <= استفاده کنیم، آنگاه می توانستیم مقادیر برش MED_LIM و LOW_LIM را به ترتیب برابر با 999.99 و 499.99 قرار دهیم. 


استفاده ی مناسب از && و ||

برنامه نویسان تازه کار، اغلب وقتی منظورشان استفاده از عملگر || است از عملگر && استفاده می کنند و اغلب وقتی از || استفاده می کنند، منظورشان && است. بخشی از این مشکل در نحوه استفاده ما از زبان انگلیسی است.

بعنوان مثال، فرض کنید مدیر شرکت شما می خواهد، وقتی که نرخ حقوق ساعتی یک کارمند کمتر از 5.85 دلار است و(and) وقتی که نرخ حقوق ساعتی او بیش از 60 دلار است، شما باید 5.85 دلار را بعنوان  یک ثابت نام دار(constant) به نام LOW تعریف کنید و 60 دلار را بعنوان یک ثابت نام دار به نام HIGH تعریف کنید. اما چونکه مدیر شما از کلمه ی and در درخواست استفاده کرده است، ممکن است بخواهید از یک دستور مانند زیر استفاده کنید:

if(payRate < LOW && payRate > HIGH)
System.out.println("Error in pay rate");

اما چونکه یک متغیر تکی، مثل payRate هرگز نمی تواند در یک زمان، هم کمتر 5.85 باشد و هم بیش از 60 باشد، پس دستور خروجی در خط شماره 2 در کد بالا، هرگز اجرا نمی شود، بدون توجه به اینکه متغیر payRate چه مقداری داشته باشد. در این مورد، باید کدهای زیر را بنویسیم تا پیغام خطا به درستی نمایش داده شود:

if(payRate < LOW || payRate > HIGH)
  System.out.println("Error in pay rate");

به طور مشابه، ممکن است مدیر شما درخواست کند: "نام های کارمندانی که در دپارتمان 1 و 2 قرار دارند را نمایش بده". چونکه مدیر شما در درخواست خود، از کلمه ی و(and) استفاده کرده است، ممکن است کدهای زیر را بنویسید:

if(department == 1 && department == 2)
System.out.println("Name is: " + name);

اما متغیر department هرگز نمی تواند در یک زمان، حاوی هردوی مقادیر 1 و 2 باشد؛ بنابراین نام هیچ کارمندی در خروجی نشان داده نمی شود؛ بدون توجه به اینکه این کارمند در کدام دپارتمان قرار دارد. 


یک نوع خطای دیگر که ممکن است اتفاق بیفتد این است که اگر بخواهیم از یک علامت AND یا OR منطقی استفاده کنیم، از یک علامت امپرساند& یا پایپ| تکی، استفاده کنیم. هردوی & و | عملگرهای معتبری در جاوا هستند، اما دو عملکرد متفاوت دارند. وقتی که ما یک علامت & یا | تکی را با رشته ها(integers) استفاده می کنیم، روی بیت ها عمل می کنیم. وقتی که ما از یک علامت & یا | تکی با عبارت های بولین استفاده می کنیم، به جای استفاده از اتصال کوتاه(short-circuitry)، هردوی عبارت ها را ارزیابی می کند. 


دو گزینه ی صحیح و یک گزینه ی اشتباه

تصمیم گیری های دقیق و موثر

1. محدوده سنجی(range check) یک سری دستور است که مشخص می کند یک مقدار، در کدام یک از بخش های یک مجموعه قرار می گیرد. 

2. وقتی که ما باید در یک برنامه یک سری تصمیم گیری کنیم، بهتر است که ابتدا سوالی را بپرسیم که به احتمال زیاد، درست تر است. 

3. از دستور if(payRate < 6.00 && payRate > 50.00) می توانیم برای انتخاب مقادیر payRate که بزرگتر یا کوچکتر از حدود مشخص شده هستند، استفاده کنیم. 

پاسخ: گزینه ی شماره 3 اشتباه است. از دستور if(payRate < 6.00 && payRate > 50.00) نمی توانیم بعنوان یک انتخابگر استفاده کنیم؛ زیرا برای payRate نمی توانیم در یک زمان، مقداری داشته باشیم که کمتر از 6.00 و بزرگتر از 50.00 باشد.