যখন (সত্য) এবং লুপ-ব্রেকিং - অ্যান্টি-প্যাটার্ন?


32

নিম্নলিখিত কোড বিবেচনা করুন:

public void doSomething(int input)
{
   while(true)
   {
      TransformInSomeWay(input);

      if(ProcessingComplete(input))
         break;

      DoSomethingElseTo(input);
   }
}

ধরে নিন যে এই প্রক্রিয়াটি একটি সীমাবদ্ধ তবে ইনপুট-নির্ভর সংখ্যক পদক্ষেপের সাথে জড়িত; লুপটি অ্যালগরিদমের ফলস্বরূপ নিজে থেকে শেষ করতে ডিজাইন করা হয়েছে এবং এটি অনির্দিষ্টকালের জন্য চালানোর জন্য ডিজাইন করা হয়নি (বাইরের কোনও ইভেন্ট দ্বারা বাতিল না হওয়া পর্যন্ত)। কারণ লুপটি শেষ হওয়া উচিত কিনা তা পরীক্ষাটি একটি লজিকাল ধাপের মধ্যবর্তী স্থানে রয়েছে, যদিও লুপটি নিজেই বর্তমানে অর্থবহ কিছু পরীক্ষা করে না; পরিবর্তে ধারণাগত অ্যালগরিদমের মধ্যে "যথাযথ" জায়গায় পরীক্ষা করা হয়।

আমাকে বলা হয়েছিল যে এটি একটি খারাপ কোড, কারণ লুপ কাঠামোর দ্বারা শেষের শর্তটি পরীক্ষা না করায় এটি আরও বাগ প্রবণ। আপনি কীভাবে লুপটি থেকে বেরিয়ে আসবেন তা নির্ধারণ করা আরও কঠিন, এবং বাগগুলি আমন্ত্রণ জানাতে পারে কারণ ব্রেকিং শর্তটি বাইপাস করা যেতে পারে বা দুর্ঘটনাক্রমে ভবিষ্যতের পরিবর্তনগুলি দেওয়া যেতে পারে।

এখন, কোডটি নিম্নরূপে কাঠামোগত হতে পারে:

public void doSomething(int input)
{
   TransformInSomeWay(input);

   while(!ProcessingComplete(input))
   {
      DoSomethingElseTo(input);
      TransformInSomeWay(input);
   }
}

তবে, এটি ডিআরওয়াই লঙ্ঘন করে কোডের কোনও পদ্ধতিতে কলটিকে নকল করে; TransformInSomeWayপরে যদি অন্য কোনও পদ্ধতির সাথে প্রতিস্থাপন করা হয়, তবে উভয় কলই খুঁজে পেতে হবে এবং পরিবর্তন করতে হবে (এবং কোডের আরও জটিল অংশে দুটি রয়েছে এমনটি হতে পারে)।

আপনি এটি লিখতে পারেন:

public void doSomething(int input)
{
   var complete = false;
   while(!complete)
   {
      TransformInSomeWay(input);

      complete = ProcessingComplete(input);

      if(!complete) 
      {
         DoSomethingElseTo(input);          
      }
   }
}

... তবে আপনার এখন একটি পরিবর্তনশীল রয়েছে যার একমাত্র উদ্দেশ্য কন্ডিশন-চেকিং লুপ স্ট্রাকচারে স্থানান্তর করা এবং মূল যুক্তির মতো একই আচরণ প্রদানের জন্য একাধিকবার পরীক্ষাও করতে হবে।

আমার অংশ হিসাবে, আমি বলছি যে অ্যালগরিদমকে এই কোডটি বাস্তব বিশ্বে প্রয়োগ করে, মূল কোডটি সর্বাধিক পঠনযোগ্য। আপনি যদি নিজেরাই এটির মধ্য দিয়ে যাচ্ছিলেন তবে আপনি এটি সম্পর্কে ভাবতে চাইতেন এবং সুতরাং এটি অ্যালগরিদমের সাথে পরিচিত লোকদের কাছে স্বজ্ঞাত হতে পারে।

সুতরাং, কোনটি "ভাল"? লুপটির চারপাশে যুক্তি কাঠামোয় করে যখন লুপটিকে শর্ত পরীক্ষা করার দায়িত্ব দেওয়া ভাল? অথবা প্রয়োজনীয়তা বা অ্যালগরিদমের ধারণামূলক বিবরণ দ্বারা নির্দেশিত হিসাবে যুক্তিকে "প্রাকৃতিক" উপায়ে কাঠামোগত করা আরও ভাল, যদিও এটি লুপের অন্তর্নির্মিত ক্ষমতাগুলি বাইপাস করার অর্থ হতে পারে?


12
সম্ভবত, তবে কোড নমুনা থাকা সত্ত্বেও প্রশ্নটি জিজ্ঞাসা করা হচ্ছে আইএমও আরও ধারণামূলক, যা এসই এর এই অঞ্চলের সাথে বেশি মিল রয়েছে। প্যাটার্ন বা অ্যান্টি-প্যাটার্ন কী তা এখানে প্রায়শই আলোচিত হয় এবং এটিই আসল প্রশ্ন; অসীমভাবে চালানোর জন্য একটি লুপ গঠন করছে এবং তারপরে এটি কোনও খারাপ জিনিস ভাঙবে?
কিথস

3
do ... untilকনস্ট্রাক্ট যেহেতু তারা করা হবে না এছাড়াও লুপ এই ধরনের জন্য দরকারী "primed।"
ব্লারফ্লার

2
লুপ-এবং-দেড় কেস এখনও সত্যই ভাল উত্তর অভাব আছে।
লরেন পেচটেল

1
"তবে এটি ডিআরওয়াই লঙ্ঘন করে কোডের কোনও পদ্ধতিতে কলটির নকল করে" আমি এই দাবিটির সাথে একমত নই এবং এটি নীতিটির একটি ভুল বোঝাবুঝির মতো বলে মনে হচ্ছে।
অ্যান্ডি

1
আমাকে (;;) এর সি-স্টাইল পছন্দ করা বাদ দিয়ে যার স্পষ্টরূপে অর্থ "আমার একটি লুপ আছে এবং আমি লুপের বিবৃতিতে যাচাই করি না", আপনার প্রথম পদ্ধতিটি একেবারেই সঠিক। আপনার একটি লুপ আছে। আপনি প্রস্থান করবেন কিনা তা স্থির করার আগে কিছু কাজ করতে হবে। কিছু শর্ত পূরণ করা হলে আপনি প্রস্থান করবেন। তারপরে আপনি আসল কাজটি করেন এবং শুরু করে দিন। এটি একেবারে সূক্ষ্ম, বুঝতে সহজ, যৌক্তিক, অপ্রয়োজনীয় এবং সঠিকভাবে পাওয়া সহজ। দ্বিতীয় রূপটি কেবল ভয়ঙ্কর, তৃতীয়টি নিছক অর্থহীন; বাকি লুপটি যদি এর মধ্যে চলে যায় তবে লম্বা হয়ে উঠছে ful
gnasher729

উত্তর:


14

আপনার প্রথম সমাধানটি আটকে দিন। লুপগুলি খুব জড়িত হয়ে উঠতে পারে এবং এক বা একাধিক ক্লিন ব্রেক আপনার পক্ষে আরও সহজ হতে পারে, অন্য কেউ যদি আপনার কোড, অপ্টিমাইজার এবং প্রোগ্রামের পারফরম্যান্সের চেয়ে বিস্তৃত ই-স্টেটমেন্টগুলি এবং যুক্ত ভেরিয়েবলগুলি দেখেন। আমার স্বাভাবিক পদ্ধতিটি হ'ল "যখন (সত্য)" এর মতো কিছু দিয়ে একটি লুপ সেট আপ করুন এবং আমার পক্ষে সেরা কোডিং পাওয়া যায়। প্রায়শই আমি স্ট্যান্ডার্ড লুপ নিয়ন্ত্রণ সহ ব্রেক (গুলি) প্রতিস্থাপন করতে পারি এবং করতে পারি; বেশিরভাগ লুপগুলি সর্বোপরি সহজ। বিভক্তি শর্ত উচিত কারণ আপনি উল্লেখ জন্য লুপ গঠন দ্বারা চেক করা, কিন্তু না যদি-বিবৃতি, এবং পুনরাবৃত্তি কোড, যার সব এমনকি জুড়ে সম্পূর্ণ নতুন ভেরিয়েবলের যোগ করার মূল্যে আরও বাগ প্রবণ।


"যদি-বিবৃতি এবং পুনরাবৃত্তি কোড, এর সবগুলিই আরও বেশি বাগ প্রবণ।" - হ্যাঁ লোকেদের চেষ্টা করার সময় আমি যদি "ভবিষ্যতের বাগগুলি" হিসাবে কল করি
প্যাট

13

লুপের দেহটি যদি তুচ্ছ না হয় তবে এটি কেবল অর্থবহ সমস্যা। যদি শরীরটি খুব ছোট হয়, তবে এটির মতো বিশ্লেষণ করা তুচ্ছ, এবং কোনও সমস্যা নয়।


7

বিরতির সাথে সমাধানের চেয়ে অন্য সমাধানগুলি সমাধান করতে আমি সমস্যায় পড়েছি। ঠিক আছে, আমি অ্যাডা উপায় পছন্দ করি যা করতে দেয়

loop
  TransformInSomeWay(input);
exit when ProcessingComplete(input);
  DoSomethingElseTo(input);
end loop;

তবে ব্রেক সমাধানটি সবচেয়ে পরিষ্কার উপস্থাপনা।

আমার পিওভিটি হ'ল যখন কোনও অনুপস্থিত নিয়ন্ত্রণ কাঠামো থাকে, তখন পরিষ্কার সমাধান হ'ল ডেটা প্রবাহ ব্যবহার না করে অন্যান্য নিয়ন্ত্রণ কাঠামো দিয়ে এটি অনুকরণ করা। (এবং একইভাবে, যখন আমার কাছে নিয়ন্ত্রণ স্ট্রাকচারের সাথে জড়িত একজনের কাছে খাঁটি ডেটা ফ্লো সমাধানগুলি অগ্রাধিকার দিতে ডেটা ফ্লো সমস্যা হয়))।

আপনি কীভাবে লুপটি থেকে বেরিয়ে আসবেন তা নির্ধারণ করা আরও কঠিন,

ভুল করবেন না, সমস্যাটি বেশিরভাগ ক্ষেত্রে একই রকম না হলে আলোচনা হবে না: শর্তটি একই রকম এবং একই জায়গায় উপস্থিত।

কোনটি

while (true) {
   XXXX
if (YYY) break;
   ZZZZ;
}

এবং

while (TTTT) {
    XXXX
    if (YYYY) {
        ZZZZ
    }
}

ভাল কাঠামো রেন্ডার করতে চান? আমি প্রথম ভোট দিচ্ছি, আপনার শর্তগুলি মেলে তা পরীক্ষা করে দেখার দরকার নেই। (তবে আমার ইন্ডেন্টেশন দেখুন)


1
ওহ, দেখুন, এমন একটি ভাষা যা সরাসরি মধ্য-প্রস্থান লুপগুলিকে সমর্থন করে ! :)
mjfgates

আমি নিয়ন্ত্রণ কাঠামো সহ হারিয়ে যাওয়া নিয়ন্ত্রণ কাঠামো অনুকরণ সম্পর্কে আপনার বক্তব্য পছন্দ করি। এটি সম্ভবত গোটো সম্পর্কিত প্রশ্নগুলির একটি ভাল উত্তর যে কোনও একটি ভাষার নিয়ন্ত্রণ কাঠামো ব্যবহার করা উচিত যখনই সে শব্দার্থক প্রয়োজনীয়তাগুলি মাপসই করে, তবে যদি একটি অ্যালগরিদমকে অন্য কিছু প্রয়োজন হয় তবে আলগোরিদমের জন্য প্রয়োজনীয় নিয়ন্ত্রণ কাঠামোটি ব্যবহার করা উচিত।
সুপারক্যাট 20'15

3

যদিও (সত্য) এবং বিরতি একটি সাধারণ প্রবাদ। এটি সি-জাতীয় ভাষায় মধ্য-প্রস্থান লুপগুলি প্রয়োগ করার মূল উপায়। প্রস্থান শর্তটি সংরক্ষণ করতে একটি ভেরিয়েবল যুক্ত করা এবং লুপের দ্বিতীয়ার্ধের চারপাশে যদি একটি (যদি) যুক্ত করা হয় তবে যুক্তিসঙ্গত বিকল্প। কিছু দোকান সরকারীভাবে এক বা অন্যটির উপর প্রমিতকরণ করতে পারে, তবে একটিও উচ্চতর নয়; তারা সমতুল্য।

এই ভাষাগুলিতে কাজ করা কোনও ভাল প্রোগ্রামার যদি জানতে চান যে সে এক নজরে কী চলছে তবে সে যদি সে বা কোনও একজনকে দেখতে পায় তবে। এটি একটি ভাল সামান্য সাক্ষাত্কার প্রশ্ন করতে পারে; কারও কাছে দুটি লুপের হাত দিন, একটি করে প্রতিটি প্রতিমা ব্যবহার করুন এবং তাদের পার্থক্যটি জিজ্ঞাসা করুন (যথাযথ উত্তর: "কিছুই নয়", সম্ভবত একটি সংযোজন সহ "তবে আমি অভ্যাসটি সেটিকে ব্যবহার করি" ")


2

আপনার বিকল্পগুলি যেমন ভাবেন তত খারাপ নয়। ভাল কোড করা উচিত:

  1. লুপটি কীভাবে বন্ধ করা উচিত সেগুলির অধীনে ভাল পরিবর্তনশীল নাম / মন্তব্য দিয়ে স্পষ্টভাবে ইঙ্গিত করুন। (ব্রেকিং শর্তটি লুকানো উচিত নয়)

  2. অপারেশন করার আদেশ কী তা স্পষ্টভাবে নির্দেশ করুন। এটি যেখানে DoSomethingElseTo(input)inside চ্ছিক তৃতীয় অপারেশন ( ) এর ভিতরে রাখা ভাল ধারণা।

এটি বলেছে যে পারফেকশনিস্ট, ব্রাস-পলিশিং প্রবৃত্তিগুলি প্রচুর সময় গ্রহন করতে দেওয়া সহজ। আমি কেবল উপরের উল্লিখিত হিসাবে যদি টুইট করতে চাই; কোড মন্তব্য করুন এবং এগিয়ে যান।


আমি মনে করি পারফেকশনিস্ট, ব্রাস-পলিশিং প্রবৃত্তি দীর্ঘমেয়াদে সময় সাশ্রয় করে। আশা করা যায়, অনুশীলনের মাধ্যমে আপনি এ জাতীয় অভ্যাসগুলি বিকাশ করতে পারেন যাতে আপনার কোডটি নিখুঁত হয় এবং এর ব্রাস অনেক বেশি সময় ব্যয় না করে পালিশ করা হয় । তবে শারীরিক নির্মাণের বিপরীতে, সফ্টওয়্যার চিরকালের জন্য স্থায়ী হতে পারে এবং অসীম স্থানে ব্যবহার করা যেতে পারে। কোড থেকে প্রাপ্ত সঞ্চয়গুলি এমনকি 0.00000001% দ্রুত, আরও নির্ভরযোগ্য, ব্যবহারযোগ্য এবং রক্ষণাবেক্ষণযোগ্য হতে পারে। (অবশ্যই, আমার অনেক-পালিশ কোডের বেশির ভাগ ভাষায় দীর্ঘ অপ্রচলিত বা অন্য কারোর জন্য অর্থ উপার্জন এই দিন, কিন্তু এটা হয়নি সাহায্যের আমাকে ভাল অভ্যাস বিকাশ।)
RalphChapin

ওয়েল আমি তোমাদের কল করতে পারবেন না ভুল :-) এই হল একটি মতামত প্রশ্ন ও ভাল দক্ষতা পিতল-মসৃণতা বেরিয়ে আসেন যদি: মহান।
প্যাট

আমি মনে করি এটি যেভাবেই হোক বিবেচনা করার সম্ভাবনা। আমি অবশ্যই কোনও গ্যারান্টি দিতে চাই না। আমার ব্রাস-পলিশিংয়ের ফলে আমার দক্ষতা উন্নত হয়েছে তা ভাবতে আমার পক্ষে আরও ভাল লাগা যায়, সুতরাং আমি এই বিষয়টিকে নিয়ে কুসংস্কারযুক্ত হতে পারি।
রাল্ফচাপিন

2

লোকেরা বলে যে এটি ব্যবহার করা খারাপ অভ্যাস while (true)এবং অনেক সময় তারা সঠিক। যদি আপনার whileবিবৃতিতে প্রচুর জটিল কোড থাকে এবং আপনি যদি তা সরিয়ে ফেলেন তখন এটি অস্পষ্ট থাকে, তবে আপনার কোড বজায় রাখা কঠিন হয়ে পড়ে এবং একটি সরল বাগ অসীম লুপের কারণ হতে পারে।

আপনার উদাহরণে আপনি ব্যবহার করা সঠিক while(true)কারণ আপনার কোডটি পরিষ্কার এবং বুঝতে সহজ। কোড পড়ার পক্ষে অদক্ষ এবং শক্ততর করার কোনও বিন্দু নেই, কারণ কিছু লোকেরা এটি সর্বদা ব্যবহার করা খারাপ অভ্যাস হিসাবে বিবেচনা করে while(true)

আমি একই ধরণের সমস্যার মুখোমুখি হয়েছিলাম:

$i = 0
$key = $str.'0';
$key1 = $str1.'0';
while (isset($array][$key] || isset($array][$key1])
{
    if (isset($array][$key]))
    {
        // Code
    }
    else
    {
        // Code
    }
    $key = $str.++$i;
    $key1 = $str1.$i;
}

অযথা দু'বার কল করা do ... while(true)এড়ানো ব্যবহার করা এড়ানো isset($array][$key], কোডটি এটি সংক্ষিপ্ত, পরিষ্কার এবং সহজভাবে পড়া সহজ। else break;শেষে অসীম লুপ বাগটি চালু হওয়ার কোনও ঝুঁকি নেই ।

$i = -1;
do
{
    $key = $str.++$i;
    $key1 = $str1.$i;
    if (isset($array[$key]))
    {
        // Code
    }
    elseif (isset($array[$key1]))
    {
        // Code
    }
    else
        break;
} while (true);

ভাল অভ্যাসগুলি অনুসরণ করা এবং খারাপ অভ্যাসগুলি এড়িয়ে চলা ভাল তবে সর্বদা ব্যতিক্রম থাকে এবং মুক্ত ব্যপারটি রাখা এবং এই ব্যতিক্রমগুলি উপলব্ধি করা গুরুত্বপূর্ণ।


0

যদি নিয়ন্ত্রণের কোনও নির্দিষ্ট প্রবাহ স্বাভাবিকভাবেই একটি বিরতি বিবৃতি হিসাবে প্রকাশ করা হয়, তবে ব্রেক স্টেটমেন্ট অনুকরণ করতে অন্য প্রবাহ নিয়ন্ত্রণ ব্যবস্থাগুলি ব্যবহার করা মূলত কখনই ভাল পছন্দ নয়।

(দ্রষ্টব্য যে এতে আংশিকভাবে লুপটি আনলোলিং করা এবং লুপের বডিটি নীচে সরিয়ে দেওয়া যাতে লুপটি শর্তাধীন পরীক্ষার সাথে মিলে যায়)

যদি আপনি নিজের লুপটি পুনর্গঠন করতে পারেন তবে নিয়ন্ত্রণের প্রবাহটি স্বাভাবিকভাবে লুপের শুরুতে শর্তাধীন চেক করে প্রকাশ করা হয়, দুর্দান্ত। এটি সম্ভব কিনা তা ভেবে কিছুটা সময় ব্যয় করাও উপযুক্ত হতে পারে। তবে এটি নয়, একটি বৃত্তাকার ছিদ্রটি একটি বৃত্তাকার গর্তের সাথে ফিট করার চেষ্টা করবেন না।


0

আপনি এই সঙ্গে যেতে পারে:

public void doSomething(int input)
{
   while(TransformInSomeWay(input), !ProcessingComplete(input))
   {
      DoSomethingElseTo(input);
   }
}

বা কম বিভ্রান্তিকরভাবে:

bool TransformAndCheckCompletion(int &input)
{
   TransformInSomeWay(input);
   return ProcessingComplete(input))
}

public void doSomething(int input)
{
   while(TransformAndCheckCompletion(input))
   {
      DoSomethingElseTo(input);
   }
}

1
কিছু লোক এটি পছন্দ করলেও আমি দৃ that়ভাবে বলছি যে লুপ শর্তটি সাধারণত স্টাফ করে এমন বিবৃতি না দিয়ে শর্তাধীন পরীক্ষার জন্য সংরক্ষণ করা উচিত।

5
একটি লুপ অবস্থায় কমা অভিব্যক্তি ... এটি দুর্দান্ত। তুমি খুব চালাক এবং এটি কেবলমাত্র এই তুচ্ছ মামলায় কাজ করে যেখানে ট্রান্সফর্মআইনসোমে ওয়েকে প্রকাশ হিসাবে প্রকাশ করা যায়।
gnasher729

0

যুক্তির জটিলতা যখন অযৌক্তিক হয়ে যায় তখন ফ্লো কন্ট্রোলের জন্য মিড-লুপ ব্রেক সহ আনবাউন্ডেড লুপ ব্যবহার করা আসলে সবচেয়ে বেশি অর্থবোধ করে। আমার কাছে এমন কিছু কোড সহ একটি প্রকল্প রয়েছে যা নীচের মত দেখাচ্ছে। (লুপের শেষে ব্যতিক্রমটি লক্ষ্য করুন))

L: for (;;) {
    if (someBool) {
        someOtherBool = doSomeWork();
        if (someOtherBool) {
            doFinalWork();
            break L;
        }
        someOtherBool2 = doSomeWork2();
        if (someOtherBool2) {
            doFinalWork2();
            break L;
        }
        someOtherBool3 = doSomeWork3();
        if (someOtherBool3) {
            doFinalWork3();
            break L;
        }
    }
    bitOfData = getTheData();
    throw new SomeException("Unable to do something for some reason.", bitOfData);
}
progressOntoOtherThings();

আনবাউন্ডেড লুপ ব্রেকিং ছাড়াই এই যুক্তিটি করতে, আমি নিম্নলিখিতগুলির মতো কিছু শেষ করব:

void method() {
    if (!someBool) {
        throwingMethod();
    }
    someOtherBool = doSomeWork();
    if (someOtherBool) {
        doFinalWork();
    } else {
        someOtherBool2 = doSomeWork2();
        if (someOtherBool2) {
            doFinalWork2();
        } else {
            someOtherBool3 = doSomeWork3();
            if (someOtherBool3) {
                doFinalWork3();
            } else {
                throwingMethod();
            }
        }
    }
    progressOntoOtherThings();
}
void throwingMethod() throws SomeException {
        bitOfData = getTheData();
        throw new SomeException("Unable to do something for some reason.", bitOfData);
}

সুতরাং ব্যতিক্রম এখন একটি সহায়ক পদ্ধতিতে ফেলে দেওয়া হয়েছে। এছাড়াও এটি বেশ if ... elseবাসা বাঁধে। আমি এই পদ্ধতির সাথে সন্তুষ্ট নই। তাই আমি মনে করি প্রথম প্যাটার্নটি সবচেয়ে ভাল।


প্রকৃতপক্ষে, আমি এই প্রশ্নটি এসওতে জিজ্ঞাসা করেছি এবং শিখায় গুলি চালিয়েছি
ইন্ট্রিপিডিস
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.