কীভাবে "যদি" শৃঙ্খলা এড়ানো যায়?


266

ধরে নিচ্ছি আমার এই ছদ্ম-কোডটি রয়েছে:

bool conditionA = executeStepA();
if (conditionA){
    bool conditionB = executeStepB();
    if (conditionB){
        bool conditionC = executeStepC();
        if (conditionC){
            ...
        }
    }
}

executeThisFunctionInAnyCase();

কার্যাবলী executeStepXযদি এবং কেবল যদি পূর্ববর্তী সফল চালানো উচিত। যে কোনও ক্ষেত্রে, executeThisFunctionInAnyCaseফাংশনটি শেষে ডাকা উচিত। আমি প্রোগ্রামিংয়ে একজন নবাগত, তাই খুব বেসিক প্রশ্নের জন্য দুঃখিত: ifকোড সুগমতার ব্যয়ে এই ধরণের "কোডের পিরামিড" উত্পাদন করে যে দীর্ঘ শৃঙ্খলা এড়ানোর কোনও উপায় আছে (উদাহরণস্বরূপ সি / সি ++ এ)? ?

আমি জানি যে আমরা যদি executeThisFunctionInAnyCaseফাংশন কলটি এড়িয়ে যেতে পারি তবে কোডটি সরলীকৃত হতে পারে:

bool conditionA = executeStepA();
if (!conditionA) return;
bool conditionB = executeStepB();
if (!conditionB) return;
bool conditionC = executeStepC();
if (!conditionC) return;

তবে সীমাবদ্ধতা হ'ল executeThisFunctionInAnyCaseফাংশন কল। গেল breakবিবৃতি কিছু উপায় ব্যবহার করা যেতে?


254
@ ফ্রিডরিক হামিদি ভুল ভুল ভুল! কখনও বলবেন না যে ব্যতিক্রমগুলি সহ আপনার প্রোগ্রামের প্রবাহ চালানো ভাল! ব্যতিক্রমগুলি অবশ্যই অনেক কারণে এই উদ্দেশ্যে উপযুক্ত নয়।
পাইটর জিয়ারহফার

26
@ পাইওটার, আমি পাইথন দ্বারা ক্ষতিগ্রস্থ হয়েছিল (যা আসলে এটি উত্সাহ দেয়)। আমি জানি যে ব্যতিক্রমগুলি সি ++ তে প্রবাহ নিয়ন্ত্রণের জন্য ব্যবহার করার কথা নয়, তবে এটি কি এখানে সত্যই প্রবাহ নিয়ন্ত্রণ রয়েছে? কোনও ফাংশন ফিরে আসা falseকি ব্যতিক্রমী পরিস্থিতির সদৃশ হিসাবে বিবেচিত হতে পারে না ?
ফ্রেডেরিক হামিদী

13
এটি কোনও প্রোগ্রামের শব্দার্থবিজ্ঞানের উপর নির্ভর করে। একটি falseফিরতি চমত্কার স্বাভাবিক হতে পারে।
12:30 এ dornhege

28
আমি আপনার প্রশ্নটি এর প্রথম সংশোধনীতে ফিরিয়ে দিয়েছি। আপনি নির্দিষ্ট সংখ্যক প্রশ্ন (> 0) পাওয়ার পরে আপনার প্রশ্নকে আমূল পরিবর্তন করা উচিত নয়, কারণ এটি সেই মুহুর্ত পর্যন্ত দেওয়া সমস্ত উত্তরকে বাতিল করে দেবে এবং বিভ্রান্তি সৃষ্টি করবে। পরিবর্তে একটি নতুন প্রশ্ন খুলুন।
জুতো

13
আমি আশা করি সমস্ত "নবাগত প্রোগ্রামাররা" এভাবে নকশার প্রশ্ন জিজ্ঞাসা করবেন।
জেজেন টমাস

উত্তর:


486

আপনি একটি &&(লজিক এবং) ব্যবহার করতে পারেন :

if (executeStepA() && executeStepB() && executeStepC()){
    ...
}
executeThisFunctionInAnyCase();

এটি আপনার উভয় প্রয়োজনীয়তা পূরণ করবে:

  • executeStep<X>()পূর্ববর্তীটি সফল হলেই মূল্যায়ন করা উচিত (এটিকে শর্ট সার্কিট মূল্যায়ন বলা হয় )
  • executeThisFunctionInAnyCase() যে কোন ক্ষেত্রে মৃত্যুদন্ড কার্যকর করা হবে

29
এটি উভয়ই শব্দার্থগতভাবে সঠিক (সত্যই, আমরা চাই সমস্ত শর্ত সত্য হোক) পাশাপাশি একটি খুব ভাল প্রোগ্রামিং কৌশল (শর্ট সার্কিট মূল্যায়ন)। তদ্ব্যতীত, এটি যে কোনও জটিল পরিস্থিতিতে ব্যবহার করা যেতে পারে যেখানে ফাংশন তৈরির ফলে কোডটি গোলমেলে।
সানচিইস

58
@ রবাউ: তারপরে জুনিয়র প্রোগ্রামারদের পক্ষে শেষ পর্যন্ত সংক্ষিপ্ত-মূল্যায়নের উপর নির্ভর করে এমন কোডটি দেখতে পারা ভাল হবে এবং তাদের এই বিষয়টিকে পুনরায় অনুসন্ধানের জন্য অনুরোধ জানাতে পারে যা পরিণামে সিনিয়র প্রোগ্রামার হওয়ার পথে তাদের সহায়তা করবে। সুতরাং স্পষ্টভাবে একটি জয়-জয়: শালীন কোড এবং কেউ এটি পড়ে কিছু শিখেছে।
x4u

24
এটি শীর্ষের উত্তর হওয়া উচিত
নাম প্রদর্শন করুন

61
@ রবআউ: এটি কোনও অস্পষ্ট সিনট্যাক্স ট্রিক্সের সুবিধা গ্রহণ করা কোনও হ্যাক নয়, এটি প্রায় প্রতিটি প্রোগ্রামিং ভাষায় অবিস্মরণীয়ভাবে স্ট্যান্ডার্ড অনুশীলন হওয়ার দিক থেকে অত্যন্ত বুদ্ধিমান।
ব্লুরাজা - ড্যানি প্লেফুঘুফুট

38
এই সমাধানটি কেবল তখনই প্রয়োগ হয় যদি শর্তগুলি আসলে সাধারণ ফাংশন কল হয়। বাস্তব কোডে, ঐ অবস্থার 2-5 লাইন দীর্ঘ হতে পারে (এবং নিজেদের অনেক অন্যান্য সমন্বয় হতে &&এবং ||) যাতে কোন উপায় আপনি তাদের একক মধ্যে যোগদান করতে চান হবে ifপাঠযোগ্যতা screwing ছাড়া বিবৃতি। এবং এই শর্তগুলি বহিরাগত ফাংশনে সরানো সর্বদা সহজ নয়, কারণ তারা পূর্বে গণনা করা স্থানীয় ভেরিয়েবলগুলির অনেকের উপর নির্ভরশীল হতে পারে, যদি আপনি প্রত্যেকে পৃথক যুক্তি হিসাবে পাস করার চেষ্টা করেন তবে এটি একটি ভয়াবহ গণ্ডগোল সৃষ্টি করে।
হ্যামস্টারজিন

358

আপনার দ্বিতীয় সংস্করণটি কাজ করতে কেবল একটি অতিরিক্ত ফাংশন ব্যবহার করুন:

void foo()
{
  bool conditionA = executeStepA();
  if (!conditionA) return;

  bool conditionB = executeStepB();
  if (!conditionB) return;

  bool conditionC = executeStepC();
  if (!conditionC) return;
}

void bar()
{
  foo();
  executeThisFunctionInAnyCase();
}

হয় গভীরভাবে নেস্টেড ifs (আপনার প্রথম বৈকল্পিক) বা "কোনও ক্রিয়াকলাপের অংশ" থেকে বেরিয়ে আসার ইচ্ছাটি ব্যবহার করার অর্থ সাধারণত আপনার অতিরিক্ত ফাংশন প্রয়োজন need


51
+1 অবশেষে কেউ একটি বুদ্ধিমান উত্তর পোস্ট করেছে। এটি আমার মতে এটি সবচেয়ে সঠিক, নিরাপদ এবং পঠনযোগ্য উপায়।
লন্ডিন

31
+1 এটি "একক দায়িত্বের নীতিমালা" এর একটি ভাল চিত্র। fooসম্পর্কিত শর্ত এবং ক্রিয়াকলাপগুলির ক্রম ধরে ফাংশন তার পথে কাজ করে। ফাংশন barপরিষ্কারভাবে সিদ্ধান্ত থেকে পৃথক করা হয়। যদি আমরা শর্ত এবং ক্রিয়াকলাপের বিশদটি দেখতে পাই তবে এটি fooএখনও সক্রিয় হতে পারে যা এখনও অনেক বেশি করছে, তবে আপাতত এটি একটি ভাল সমাধান।
গ্রানাইটরোবার্ট

13
নেতিবাচক দিকটি হ'ল সি এর নেস্টেড ফাংশন নেই তাই যদি barআপনার থেকে ভেরিয়েবলগুলি ব্যবহার করার জন্য প্রয়োজনীয় 3 টি পদক্ষেপগুলি ম্যানুয়ালি fooপ্যারামিটার হিসাবে তাদেরকে পাস করতে হয় । যদি এটি হয় এবং যদি fooকেবল একবার ফোন করা হয় তবে আমি দুটি শক্তভাবে মিলিত ফাংশন সংজ্ঞায়িত করতে এড়াতে গোটো সংস্করণটি ব্যবহার করতে ভুল করব যেটি খুব পুনরায় ব্যবহারযোগ্য হবে না being
hugomg

7
সি এর জন্য সংক্ষিপ্ত-প্রচারের বাক্য গঠন সম্পর্কে নিশ্চিত নয়, তবে সি # foo () তে লেখা যেতে পারেif (!executeStepA() || !executeStepB() || !executeStepC()) return
ট্র্যাভিস

6
@ ব্যবহারকারী1598390 গোটোগুলি সর্বদা ব্যবহৃত হয়, বিশেষত সিস্টেম প্রোগ্রামিংয়ে যখন আপনার প্রচুর সেট আপ কোডটি আনওয়াইন্ড করা দরকার।
স্কটি বাউয়ার

166

ওল্ড স্কুল সি প্রোগ্রামাররা এক্ষেত্রে ব্যবহার gotoকরে। এটি gotoলিনাক্স স্টাইলগাইড দ্বারা প্রকৃতপক্ষে উত্সাহিত করা হ'ল এর এক ব্যবহার যা একে সেন্ট্রালাইজড ফাংশন প্রস্থান বলে:

int foo() {
    int result = /*some error code*/;
    if(!executeStepA()) goto cleanup;
    if(!executeStepB()) goto cleanup;
    if(!executeStepC()) goto cleanup;

    result = 0;
cleanup:
    executeThisFunctionInAnyCase();
    return result;
}

কিছু লোক gotoশরীরকে একটি লুপে আবৃত করে এবং এটি থেকে ভেঙে চারপাশে কাজ করে তবে কার্যকরভাবে উভয় পন্থা একই কাজ করে। gotoযদি আপনি কিছু অন্যান্য পরিষ্করণ শুধুমাত্র যদি প্রয়োজন পদ্ধতির উত্তম executeStepA()successfull ছিল:

int foo() {
    int result = /*some error code*/;
    if(!executeStepA()) goto cleanupPart;
    if(!executeStepB()) goto cleanup;
    if(!executeStepC()) goto cleanup;

    result = 0;
cleanup:
    innerCleanup();
cleanupPart:
    executeThisFunctionInAnyCase();
    return result;
}

লুপ পদ্ধতির সাহায্যে আপনি সেই ক্ষেত্রে দুটি স্তরের লুপগুলি শেষ করতে পারেন।


108
+1 টি। অনেক লোক gotoএটিকে দেখে এবং তত্ক্ষণাত্ "এটি ভয়ঙ্কর কোড" মনে করে তবে এর এর কার্যকর ব্যবহার রয়েছে have
গ্রিম পেরো

46
এটি ব্যতীত রক্ষণাবেক্ষণ পয়েন্ট-অফ-ভিউ থেকে, আসলেই বেশ জঞ্জাল কোড। বিশেষত যখন একাধিক লেবেল থাকে, যেখানে কোডটি পড়াও শক্ত হয়। এটি অর্জনের জন্য আরও মার্জিত উপায় রয়েছে: ফাংশনগুলি ব্যবহার করুন।
লন্ডিন

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

56
এই সীমিত, স্বতঃস্ফূর্ত गोোটোর ব্যবহারের সাথে কোনও ভুল নেই। কিন্তু হুঁশিয়ার, এতে যান হয় একটি গেটওয়ে ড্রাগ এবং যদি আপনি সাবধান হবে একদিন বুঝতে পারি যে কেউ তাদের পা দিয়ে অন্য eats স্প্যাঘেটি এবং আপনি এটি পরে আপনি চিন্তা "আমি শুধু এই ঠিক করতে পারবো 15 বছর শুরু করার জন্য কাজ করছি না হন অন্যথায় একটি লেবেল সহ রাতের বাচ্চা বাগ ... "
টিম পোস্ট

66
আমি এই শৈলীতে সম্ভবত এক লক্ষ লক্ষ লাইন অত্যন্ত স্বচ্ছ, সহজেই বজায় রাখা কোডটি লিখেছি। দুটি মূল বিষয় বুঝতে হবে (1) শৃঙ্খলা! প্রতিটি ক্রিয়াকলাপের বিন্যাসের জন্য একটি সুস্পষ্ট গাইডলাইন স্থাপন করুন এবং কেবল চরম প্রয়োজনে এটি লঙ্ঘন করুন এবং (২) বুঝতে পারেন যে আমরা এখানে যা করছি তা কোনও ভাষায় ব্যতিক্রম অনুকরণ করছে যা তাদের নেইthrowএটি অনেক দিক থেকে খারাপ gotoকারণ throwএটি আপনার স্থানীয় প্রেক্ষাপট থেকে পরিষ্কার নয় যেখানে আপনি শেষ করতে যাচ্ছেন! আপনি ব্যতিক্রমগুলির মতো গোটো-স্টাইল নিয়ন্ত্রণ প্রবাহের জন্য একই নকশার বিবেচনাগুলি ব্যবহার করুন।
এরিক লিপার্ট

131

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

এটি একটি তীর

আপনি যা আলোচনা করছেন তা তীর বিরোধী-প্যাটার্ন হিসাবে পরিচিত । এটিকে তীর বলা হয় কারণ নেস্টেড আইএফএসের চেইন কোড ব্লকগুলি গঠন করে যা আরও দূরে এবং ডানদিকে প্রসারিত হয় এবং তারপরে বাম দিকে ফিরে যায় এবং একটি ভিজ্যুয়াল তীর গঠন করে যা কোড সম্পাদক পেনের ডানদিকে "পয়েন্ট" করে।

গার্ড দিয়ে তীর সমতল করুন

তীর এড়ানোর কয়েকটি সাধারণ উপায় এখানে আলোচনা করা হয়েছে । সর্বাধিক সাধারণ পদ্ধতি হ'ল গার্ড প্যাটার্ন ব্যবহার করা , যাতে কোডটি প্রথমে ব্যতিক্রম প্রবাহকে পরিচালনা করে এবং তারপরে মূল প্রবাহকে পরিচালনা করে, যেমন পরিবর্তে

if (ok)
{
    DoSomething();
}
else
{
    _log.Error("oops");
    return;
}

... তুমি ব্যবহার কর ...

if (!ok)
{
    _log.Error("oops");
    return;
} 
DoSomething(); //notice how this is already farther to the left than the example above

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

তীর:

ok = DoSomething1();
if (ok)
{
    ok = DoSomething2();
    if (ok)
    {
        ok = DoSomething3();
        if (!ok)
        {
            _log.Error("oops");  //Tip of the Arrow
            return;
        }
    }
    else
    {
       _log.Error("oops");
       return;
    }
}
else
{
    _log.Error("oops");
    return;
}

গার্ড:

ok = DoSomething1();
if (!ok)
{
    _log.Error("oops");
    return;
} 
ok = DoSomething2();
if (!ok)
{
    _log.Error("oops");
    return;
} 
ok = DoSomething3();
if (!ok)
{
    _log.Error("oops");
    return;
} 
ok = DoSomething4();
if (!ok)
{
    _log.Error("oops");
    return;
} 

এটি পড়ার জন্য অবজেক্টিভ এবং কোয়ান্টেফাইয়েলি সহজ কারণ কারণ

  1. প্রদত্ত লজিক ব্লকের জন্য {এবং} অক্ষর একত্রে আরও কাছাকাছি রয়েছে
  2. একটি নির্দিষ্ট লাইন বুঝতে মানসিক প্রসঙ্গে প্রয়োজনীয় পরিমাণ কম is
  3. শর্তের সাথে যুক্ত যুক্তির সম্পূর্ণতা এক পৃষ্ঠায় থাকার সম্ভাবনা বেশি
  4. পৃষ্ঠা / চোখের ট্র্যাকটি স্ক্রোল করার কোডারটির প্রয়োজনীয়তা হ্রাস করা হয়

কীভাবে শেষে সাধারণ কোড যুক্ত করা যায়

প্রহরী রীতির সমস্যাটি হ'ল এটি "সুবিধাবাদী প্রত্যাবর্তন" বা "সুবিধাবাদী প্রস্থান" বলে যাকে বলে তার উপর নির্ভর করে। অন্য কথায়, এটি প্রতিটি এবং প্রতিটি ক্রিয়াকলাপের প্রস্থানের ঠিক এক পয়েন্ট থাকা উচিত এমন প্যাটার্নটি ভেঙে দেয়। এটি দুটি কারণে সমস্যা:

  1. এটি কিছু লোককে ভুল উপায়ে ঘষে, উদাহরণস্বরূপ যে ব্যক্তিরা পাস্কেলে কোড শিখেছে তারা শিখেছে যে একটি ফাংশন = একটি প্রস্থানস্থান।
  2. এটি কোডের এমন একটি বিভাগ সরবরাহ করে না যা প্রস্থান করার পরে কার্যকর হয় তা যাই হোক না কেন , হাতে থাকা বিষয়।

নীচে আমি ভাষা বৈশিষ্ট্য ব্যবহার করে বা সমস্যাটি পুরোপুরি এড়িয়ে এই সীমাবদ্ধতাটি ঘিরে কাজ করার জন্য কিছু বিকল্প সরবরাহ করেছি।

বিকল্প 1. আপনি এটি করতে পারবেন না: ব্যবহার করুন finally

দুর্ভাগ্যক্রমে, সি ++ বিকাশকারী হিসাবে আপনি এটি করতে পারবেন না। তবে শেষ পর্যন্ত কীওয়ার্ড ধারণ করে এমন ভাষার জন্য এটি প্রথম নম্বর।

try
{
    if (!ok)
    {
        _log.Error("oops");
        return;
    } 
    DoSomething(); //notice how this is already farther to the left than the example above
}
finally
{
    DoSomethingNoMatterWhat();
}

বিকল্প 2. সমস্যাটি এড়ান: আপনার কার্যগুলি পুনর্গঠন করুন

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

এখানে একটি উদাহরণ:

void OuterFunction()
{
    DoSomethingIfPossible();
    DoSomethingNoMatterWhat();
}

void DoSomethingIfPossible()
{
    if (!ok)
    {
        _log.Error("Oops");
        return;
    }
    DoSomething();
}

বিকল্প 3. ভাষা কৌশল: একটি নকল লুপ ব্যবহার করুন

অন্য একটি সাধারণ কৌতুক আমি দেখতে পাচ্ছি যখন ব্যবহার করা হচ্ছে (সত্য) এবং বিরতি, অন্য উত্তরগুলিতে দেখানো হয়েছে।

while(true)
{
     if (!ok) break;
     DoSomething();
     break;  //important
}
DoSomethingNoMatterWhat();

যদিও gotoএটি ব্যবহারের চেয়ে কম "সৎ" , এটি রিফ্যাক্টর করার সময় গণ্ডগোল হওয়ার ঝুঁকি কম, কারণ এটি স্পষ্টত যুক্তির ক্ষেত্রের সীমানা চিহ্নিত করে। আপনার লেবেলগুলি কে বা আপনার gotoবিবৃতি কেটে পেস্ট করে এমন একটি নিষ্পাপ কোডার বড় সমস্যার কারণ হতে পারে! (এবং প্রকৃতপক্ষে প্যাটার্নটি এখন এত সাধারণ যে আমি মনে করি এটি স্পষ্টভাবে অভিপ্রায়টি যোগাযোগ করে, এবং তাই এটি মোটেই "বে "মান" নয়)।

এই বিকল্পগুলির অন্যান্য রূপ রয়েছে। উদাহরণস্বরূপ, এক switchপরিবর্তে ব্যবহার করতে পারে while। কোনও breakকীওয়ার্ড সহ যে কোনও ভাষা নির্মাণ সম্ভবত কাজ করবে।

বিকল্প 4. অবজেক্ট লাইফ চক্রটি উত্সাহিত করুন

অন্য একটি পদ্ধতির অবজেক্ট লাইফ চক্রটি লাভ করে। আপনার প্যারামিটারগুলি ধরে রাখার জন্য একটি প্রসঙ্গ অবজেক্ট ব্যবহার করুন (যা আমাদের নিষ্পাপ উদাহরণটিতে সন্দেহজনকভাবে অভাব রয়েছে) এবং আপনার কাজ শেষ হয়ে গেলে তা নিষ্পত্তি করে দিন।

class MyContext
{
   ~MyContext()
   {
        DoSomethingNoMatterWhat();
   }
}

void MainMethod()
{
    MyContext myContext;
    ok = DoSomething(myContext);
    if (!ok)
    {
        _log.Error("Oops");
        return;
    }
    ok = DoSomethingElse(myContext);
    if (!ok)
    {
        _log.Error("Oops");
        return;
    }
    ok = DoSomethingMore(myContext);
    if (!ok)
    {
        _log.Error("Oops");
    }

    //DoSomethingNoMatterWhat will be called when myContext goes out of scope
}

দ্রষ্টব্য: আপনার পছন্দের ভাষার অবজেক্ট লাইফ চক্রটি আপনি বুঝতে পেরেছেন তা নিশ্চিত হন। এটি কাজ করার জন্য আপনার কিছু প্রকারের ডিটারমিনিস্টিক আবর্জনা সংগ্রহের প্রয়োজন, অর্থাৎ আপনাকে জানতে হবে কখন ধ্বংসকারীকে ডাকা হবে। কিছু ভাষায় আপনাকে Disposeডেস্ট্রাক্টরের পরিবর্তে ব্যবহার করতে হবে ।

বিকল্প 4.1। অবজেক্ট লাইফ চক্রটি উত্সাহিত করুন (মোড়কের ধরণ)

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

class MyWrapper 
{
   bool DoSomething() {...};
   bool DoSomethingElse() {...}


   void ~MyWapper()
   {
        DoSomethingNoMatterWhat();
   }
}

void MainMethod()
{
    bool ok = myWrapper.DoSomething();
    if (!ok)
        _log.Error("Oops");
        return;
    }
    ok = myWrapper.DoSomethingElse();
    if (!ok)
       _log.Error("Oops");
        return;
    }
}
//DoSomethingNoMatterWhat will be called when myWrapper is destroyed

আবার, নিশ্চিত হয়ে নিন যে আপনি নিজের অবজেক্টের জীবনচক্রটি বুঝতে পেরেছেন।

বিকল্প 5. ভাষার কৌশল: শর্ট সার্কিট মূল্যায়ন ব্যবহার করুন

আরেকটি কৌশল হ'ল শর্ট সার্কিট মূল্যায়নের সুবিধা নেওয়া ।

if (DoSomething1() && DoSomething2() && DoSomething3())
{
    DoSomething4();
}
DoSomethingNoMatterWhat();

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

কমপ্যাক্ট কোডের প্রয়োজন হয় এবং যখন কোডটি খুব বেশি রক্ষণাবেক্ষণের সম্ভাবনা না দেখায় এই কৌশলটি সবচেয়ে কার্যকর তখন উদাহরণস্বরূপ আপনি একটি সুপরিচিত অ্যালগরিদম প্রয়োগ করছেন। আরও সাধারণ কোডিংয়ের জন্য এই কোডটির কাঠামো খুব ভঙ্গুর; এমনকি যুক্তিতে সামান্য পরিবর্তনও মোট পুনরায় লেখার সূত্রপাত করতে পারে।


12
অবশেষে? সি ++ এর শেষ অবধি নেই। ডেস্ট্রাক্টর সহ একটি অবজেক্ট এমন পরিস্থিতিতে ব্যবহৃত হয় যেখানে আপনি মনে করেন আপনার শেষ অবধি প্রয়োজন।
বিল ডোর

1
উপরের দুটি মতামত সামঞ্জস্য করার জন্য সম্পাদিত।
জন উ

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

1
আমি নেস্টেড প্যাটার্ন দেখেছি যেখানে কোডটি এখন 1920 x 1080 স্ক্রিনে দৃশ্যমান ছিল না ... তৃতীয় ক্রিয়া ব্যর্থ হলে কী ত্রুটি পরিচালনা করার কোডটি সম্পাদন করা হবে তা অনুসন্ধান করার চেষ্টা করুন ... আমি {...} ব্যবহার করেছি (0) পরিবর্তে যাতে আপনি যখন (সত্য) {...} "continue" অনুমতি দেয় সব আবার শুরু করার জন্য, (ফাইনাল ব্রেক প্রয়োজন হবে না অন্যদিকে।
gnasher729

2
আপনার বিকল্প 4টি আসলে সি ++ এ মেমোরি ফুটো (ছোট ছোট সিনট্যাক্স ত্রুটি উপেক্ষা করে)। এই ধরণের ক্ষেত্রে কেউ "নতুন" ব্যবহার করে না, কেবল "MyContext myContext;" বলুন।
সুমুডু ফার্নান্দো

60

শুধু কর

if( executeStepA() && executeStepB() && executeStepC() )
{
    // ...
}
executeThisFunctionInAnyCase();

এটা খুব সহজ।


তিনটি সম্পাদনার কারণে যে প্রত্যেকে মৌলিকভাবে প্রশ্নটি পরিবর্তিত করেছে (যদি কেউ যদি সংস্করণ # 1 এ পুনর্বিবেচনা গণনা করে তবে চারটি), আমি কোড কোডটি অন্তর্ভুক্ত করছি যার আমি উত্তর দিচ্ছি:

bool conditionA = executeStepA();
if (conditionA){
    bool conditionB = executeStepB();
    if (conditionB){
        bool conditionC = executeStepC();
        if (conditionC){
            ...
        }
    }
}

executeThisFunctionInAnyCase();

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

1
@ চিয়ারসান্থ-আলফ: আমি বিশ্বাস করতে পারি না এটি মোড-মোছা হয়েছিল। এটা ঠিক খুব খারাপ। (+1)
প্যারাম্যাগনেটিক ক্রোস্যান্ট

2
আপনার সাহস আমার +1! (3 বার ব্যপার হয়: ডি)।
হ্যাক 15

নবাগত প্রোগ্রামাররা একাধিক বুলিয়ান "অ্যান্ডস" দিয়ে অর্ডার-এক্সিকিউশন, বিভিন্ন ভাষায় কীভাবে এটি আলাদা হয় ইত্যাদি সম্পর্কে শিখতে হবে এটি সম্পূর্ণ গুরুত্বপূর্ণ And এবং এই উত্তরটি তার পক্ষে দুর্দান্ত পয়েন্টার। তবে এটি সাধারণ বাণিজ্যিক প্রোগ্রামিংয়ে কেবল "অ-স্টার্টার"। এটি সহজ নয়, এটি রক্ষণাবেক্ষণযোগ্য নয়, এটি পরিবর্তনযোগ্য নয়। অবশ্যই, আপনি যদি নিজের জন্য কেবল কিছু দ্রুত "কাউবয় কোড" লিখছেন তবে এটি করুন। তবে এটির মধ্যে রয়েছে "আজকের রীতি অনুযায়ী সফটওয়্যার ইঞ্জিনিয়ারিংয়ের সাথে কোনও সংযোগ নেই।" হাস্যকর "সম্পাদনা-বিভ্রান্তির" জন্য BTW দুঃখিত আপনি এখানে সহ্য করা, @cheers ছিল :)
Fattie

1
@ জো ব্লো: আমি এতে আলফের সাথে রয়েছি - আমি &&তালিকাটি আরও পরিষ্কারভাবে দেখতে পাচ্ছি । আমি সাধারণত পৃথক রেখাগুলিতে শর্তগুলি ভেঙে // explanationপ্রত্যেকটির জন্য একটি পিছনে যুক্ত করি .... শেষ পর্যন্ত, এটি দেখার পক্ষে কম পরিমাণে কোড রয়েছে এবং একবার আপনি বুঝতে পারছেন যে কীভাবে &&চলমান মানসিক প্রচেষ্টা নেই। আমার ধারণাটি হল যে বেশিরভাগ পেশাদার সি ++ প্রোগ্রামাররা এটির সাথে পরিচিত হবে তবে আপনি বিভিন্ন শিল্প / প্রকল্পগুলিতে যেমন বলেছিলেন ফোকাস এবং অভিজ্ঞতা পৃথক।
টনি ডেলরয়

35

কার্যত সি ++ এ স্থগিত করার একটি উপায় রয়েছে: কোনও অবজেক্টের ডেস্ট্রাক্টর ব্যবহার করে।

ধরে নিই যে আপনার সি ++ 11 এ অ্যাক্সেস রয়েছে:

class Defer {
public:
    Defer(std::function<void()> f): f_(std::move(f)) {}
    ~Defer() { if (f_) { f_(); } }

    void cancel() { f_ = std::function<void()>(); }

private:
    Defer(Defer const&) = delete;
    Defer& operator=(Defer const&) = delete;

    std::function<void()> f_;
}; // class Defer

এবং তারপরে সেই ইউটিলিটিটি ব্যবহার করে:

int foo() {
    Defer const defer{&executeThisFunctionInAnyCase}; // or a lambda

    // ...

    if (!executeA()) { return 1; }

    // ...

    if (!executeB()) { return 2; }

    // ...

    if (!executeC()) { return 3; }

    // ...

    return 4;
} // foo

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

24
@ লন্ডিন: আচ্ছা, আমি বুঝতে পারি না যে কেউ কীভাবে ভঙ্গুর কোড দিয়ে সন্তুষ্ট হতে পারে যা তাড়াতাড়ি চালিয়ে যাওয়া / ব্রেক / রিটার্ন চালু হওয়ার সাথে সাথে একটি ব্যতিক্রম ছুঁড়ে দেওয়ার সাথে সাথে ভেঙে যায়। অন্যদিকে, ভবিষ্যতে রক্ষণাবেক্ষণের ক্ষেত্রে এই সমাধানটি স্থিতিস্থাপক, এবং কেবলমাত্র এই সত্যটির উপর নির্ভর করে যে উইন্ডোজদের সময় ধ্বংসকারীদের মৃত্যুদন্ড কার্যকর করা হয় যা সি ++ এর অন্যতম গুরুত্বপূর্ণ বৈশিষ্ট্য। এই যোগ্য বহিরাগত , যখন তা অন্তর্নিহিত ঠিক যে ক্ষমতা সমস্ত মানক পাত্রে ক্রীড়া-কৌতুক হয় অন্তত বলতে।
ম্যাথিউ এম।

7
@ লন্ডিন: ম্যাথিউয়ের কোডের সুবিধাটি হ'ল ব্যতিক্রম ছুঁড়ে ফেলা executeThisFunctionInAnyCase();হলেও কার্যকর করা হবে foo();। ব্যতিক্রম-নিরাপদ কোড লেখার সময়, এই ধরণের সমস্ত ক্লিনআপ ফাংশনকে একজন ডেস্ট্রাক্টরের মধ্যে রাখা ভাল অনুশীলন।
ব্রায়ান

6
@ ব্রায়ান তারপর কোনও ব্যতিক্রম throwোকাবেন না foo()। এবং যদি তা করেন তবে এটি ধরুন। সমস্যা সমাধান. বাগ ফিক্স করে ফিক্স করুন, ওয়ার্ক-এপাশে লিখে না।
লন্ডিন

18
@ লন্ডিন: Deferক্লাসটি কোডের একটি পুনরায় ব্যবহারযোগ্য ছোট্ট টুকরো যা আপনাকে ব্যতিক্রম নিরাপদ উপায়ে কোনও প্রকারের অবরুদ্ধ ক্লিনআপ করতে দেয়। এটি স্কোপ গার্ড হিসাবে বেশি পরিচিত । হ্যাঁ স্কোপ গার্ডের যেকোন ব্যবহারকে অন্য ম্যানুয়াল উপায়ে forপ্রকাশ করা যেতে পারে , যেমন কোনও লুপ যেমন একটি ব্লক এবং whileলুপ হিসাবে প্রকাশ করা যেতে পারে , যা ঘুরেফিরে প্রকাশ করা যায় ifএবং gotoযা আপনি চাইলে সমাবেশ ভাষায় প্রকাশ করা যায়, বা যারা সত্য মাস্টার, তাদের জন্য কাস্টমিক রশ্মির মাধ্যমে স্মৃতিতে বিটগুলি পরিবর্তন করে বিশেষ শর্ট গ্রান্টস এবং মন্ত্রগুলির প্রজাপতি প্রভাব দ্বারা পরিচালিত। কিন্তু, কেন যে।
চিয়ার্স এবং এইচটিএইচ - আলফ

34

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

void foo()
{
  // ...
  do {
      if (!executeStepA())
          break;
      if (!executeStepB())
          break;
      if (!executeStepC())
          break;
  }
  while (0);
  // ...
}

11
একাধিক রিটার্ন সহ একটি ফাংশন ব্যবহার করা আমার মতে একই, তবে আরও পঠনযোগ্য।
লন্ডিন

4
হ্যাঁ, অবশ্যই এটি আরও পঠনযোগ্য ... তবে দক্ষতার দিক থেকে অতিরিক্ত ফাংশন কল (প্যারামিটার পাসিং এবং রিটার্ন) ওভারহেড ডু-{করার সময় (0) নির্মাণের মাধ্যমে এড়ানো যেতে পারে।
দেবাসিস

5
আপনি এখনও ফাংশনটি করতে মুক্ত inline। যাইহোক, এটি একটি দুর্দান্ত কৌশল, কারণ এটি এই সমস্যার চেয়ে বেশি সহায়তা করে।
Ruslan

2
@ লন্ডিন আপনাকে কোডের স্থানীয়ত্বটি বিবেচনায় নিতে হবে, অনেক জায়গাতেই কোড ছড়িয়ে দেওয়াও সমস্যা রয়েছে।
এপিআই-বিস্ট

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

19

আপনি এটি করতে পারেন:

bool isOk = true;
std::vector<bool (*)(void)> funcs; //vector of function ptr

funcs.push_back(&executeStepA);
funcs.push_back(&executeStepB);
funcs.push_back(&executeStepC);
//...

//this will stop at the first false return
for (auto it = funcs.begin(); it != funcs.end() && isOk; ++it) 
    isOk = (*it)();
if (isOk)
 //doSomeStuff
executeThisFunctionInAnyCase();

এইভাবে আপনার প্রতি ন্যূনতম রৈখিক বৃদ্ধির আকার, প্রতি কল +1 লাইন এবং এটি সহজেই বিন্যস্ত।


সম্পাদনা করুন : (ধন্যবাদ @ উন্ডা) কোনও বড় পাখা নন কারণ আপনি দৃশ্যমানতা হারাচ্ছেন আইএমও:

bool isOk = true;
auto funcs { //using c++11 initializer_list
    &executeStepA,
    &executeStepB,
    &executeStepC
};

for (auto it = funcs.begin(); it != funcs.end() && isOk; ++it) 
    isOk = (*it)();
if (isOk)
 //doSomeStuff
executeThisFunctionInAnyCase();

1
এটি পুশ_ব্যাকের ভিতরে দুর্ঘটনাজনিত ফাংশন কল সম্পর্কে ছিল (), তবে আপনি এটি যাইহোক ঠিক করেছেন :)
কোয়ান্টিন

4
আমি কেন এটি ডাউনটা পেয়েছিলাম তা জানতে আগ্রহী। ধরা যাক, কার্যকর করা পদক্ষেপগুলি প্রকৃতই প্রতিসাম্য, যেমনগুলি তারা উপস্থিত বলে মনে হয়, ততক্ষণে এটি পরিষ্কার এবং রক্ষণাবেক্ষণযোগ্য।
ClickRick

1
যদিও এটি বিতর্কিতভাবে আরও পরিচ্ছন্ন দেখাচ্ছে। এটি মানুষের পক্ষে বুঝতে অসুবিধা হতে পারে এবং সংকলকটির জন্য এটি বোঝা অবশ্যই শক্ত!
রায় টি।

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

3
তুচ্ছ মামলার জন্য সামান্য পরিমাণে ইঞ্জিনিয়ারড, তবে এই কৌশলটিতে অবশ্যই একটি দুর্দান্ত বৈশিষ্ট্য রয়েছে যা অন্যরা করেন না: আপনি মৃত্যুর সময় এবং [সংখ্যায়] রানটাইমের সময় ডাকা ফাংশনগুলি পরিবর্তন করতে পারেন, এবং এটি দুর্দান্ত :)
জোকোয়াটজিন

18

এই কাজ করবে? আমি মনে করি এটি আপনার কোডের সাথে সমান।

bool condition = true; // using only one boolean variable
if (condition) condition = executeStepA();
if (condition) condition = executeStepB();
if (condition) condition = executeStepC();
...
executeThisFunctionInAnyCase();

3
আমি সাধারণত ভেরিয়েবলটি কল করি okযখন এই জাতীয় ভেরিয়েবলটি ব্যবহার করি।
মাকেকে

1
ডাউনভোটস কেন তা জানতে আমি খুব আগ্রহী হব। এখানে কি ভুল হচ্ছে?
এবিসিপ্লাস

1
আপনার উত্তরটি সাইক্লোমেটিক জটিলতার জন্য শর্ট সার্কিট পদ্ধতির সাথে তুলনা করুন।
আলফাগোকু

14

পছন্দসই কোডটি বর্তমানে দেখছি হিসাবে ধরে নেওয়া হচ্ছে:

bool conditionA = executeStepA();
if (conditionA){
    bool conditionB = executeStepB();
    if (conditionB){
        bool conditionC = executeStepC();
        if (conditionC){
            ...
        }
    }
}    
executeThisFunctionInAnyCase();

আমি বলব যে সঠিক পদ্ধতির মধ্যে এটি পড়া সহজ এবং বজায় রাখা সবচেয়ে সহজ, ইন্ডেন্টেশন কম মাত্রা থাকবে, যা (বর্তমানে) প্রশ্নের উত্সাহিত উদ্দেশ্য।

// Pre-declare the variables for the conditions
bool conditionA = false;
bool conditionB = false;
bool conditionC = false;

// Execute each step only if the pre-conditions are met
conditionA = executeStepA();
if (conditionA)
    conditionB = executeStepB();
if (conditionB)
    conditionC = executeStepC();
if (conditionC) {
    ...
}

// Unconditionally execute the 'cleanup' part.
executeThisFunctionInAnyCase();

এটি গুলি, ব্যতিক্রম, ডামি লুপস বা অন্যান্য কঠিন নির্মাণের কোনও প্রয়োজন এড়ানো যায় এবং সহজ সরল কাজটি হাতে পায়।gotowhile


লুপগুলি ব্যবহার করার সময়, অতিরিক্ত "পতাকা" ভেরিয়েবলগুলি প্রবর্তন করার প্রয়োজন ছাড়াই এটি সাধারণত গ্রহণযোগ্য returnএবং breakলুপের বাইরে লাফিয়ে। এই ক্ষেত্রে, একটি গোটো ব্যবহার করা একইভাবে ইনোকুউউ হবে - মনে রাখবেন যে আপনি অতিরিক্ত পরিবর্তনশীল ভেরিয়েবল জটিলতার জন্য অতিরিক্ত গোটো জটিলতার বাণিজ্য করছেন।
হুগমগ

2
@ হুগমগ ভেরিয়েবলগুলি মূল প্রশ্নে ছিল। এখানে কোনও অতিরিক্ত জটিলতা নেই। প্রশ্নটি সম্পর্কে অনুমান করা হয়েছিল (যেমন ভেরিয়েবলগুলি redacted কোডে প্রয়োজন) তাই সেগুলি বজায় রাখা হয়েছিল। যদি তাদের প্রয়োজন না হয় তবে কোডটি সরল করা যেতে পারে, তবে প্রশ্নের অসম্পূর্ণ প্রকৃতি প্রদত্ত অন্য কোনও অনুমান নেই যা বৈধভাবে তৈরি করা যেতে পারে।
ClickRick

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

12

কোনওভাবে ব্রেক স্টেটমেন্ট ব্যবহার করা যাবে?

সেরা সমাধান নাও হতে পারে তবে আপনি আপনার বক্তব্যগুলিকে একটি do .. while (0)লুপে রাখতে পারেন এবং breakপরিবর্তে বিবৃতি ব্যবহার করতে পারেন return


2
আমি এটিকেই হ্রাসকারী নই, তবে এটি এমন কোনও জিনিসের জন্য একটি লুপিং কন্সট্রাক্টের অপব্যবহার হবে যেখানে বর্তমানে এটি যা চেয়েছিল তার প্রভাব কিন্তু অনিবার্যভাবে ব্যথার কারণ হয়ে দাঁড়াবে। সম্ভবত পরবর্তী বিকাশকারীর জন্য যাকে আপনি অন্য প্রকল্পে যাওয়ার পরে 2 বছরের সময় এটি বজায় রাখতে হবে।
ClickRick

3
@ do .. while (0)ম্যাক্রো সংজ্ঞাগুলির জন্য ক্লিকরিক ব্যবহার করা লুপগুলিও অপব্যবহার করছে তবে এটি ঠিক আছে বলে মনে করা হচ্ছে।
ওহাহ

1
সম্ভবত, তবে এটি অর্জনের আরও পরিষ্কার উপায় রয়েছে।
ClickRick

4
@ ক্লিকেরিক আমার উত্তরের একমাত্র উদ্দেশ্য উত্তর দেওয়া কোনওভাবে ব্রেক স্টেটমেন্টটি ব্যবহার করা যেতে পারে এবং উত্তর হ্যাঁ, আমার উত্তরের প্রথম শব্দগুলি বোঝায় যে এটি ব্যবহারের সমাধান নয়।
ওয়াহ

2
এই উত্তরটি কেবল একটি মন্তব্য হওয়া উচিত
msmucker0527

12

আপনি সমস্ত ifশর্তগুলি নিজের মতো করে কোনও ফাংশনে চান হিসাবে ফর্ম্যাটে রাখতে পারেন, অন রিটার্নটি executeThisFunctionInAnyCase()ফাংশনটি কার্যকর করে ute

ওপিতে বেস উদাহরণ থেকে শর্ত পরীক্ষা ও সম্পাদনকে বিভক্ত করা যায়;

void InitialSteps()
{
  bool conditionA = executeStepA();
  if (!conditionA)
    return;
  bool conditionB = executeStepB();
  if (!conditionB)
    return;
  bool conditionC = executeStepC();
  if (!conditionC)
    return;
}

এবং তারপরে যেমন বলা হয়;

InitialSteps();
executeThisFunctionInAnyCase();

যদি সি ++ ১১ টি ল্যাম্বডাস উপলভ্য থাকে (ওপিতে কোনও সি ++ 11 ট্যাগ ছিল না তবে তারা এখনও বিকল্প হতে পারে), তবে আমরা পৃথক ফাংশনটি ছেড়ে দিয়ে এটিকে একটি ল্যাম্বডায় গুটিয়ে রাখতে পারি।

// Capture by reference (variable access may be required)
auto initialSteps = [&]() {
  // any additional code
  bool conditionA = executeStepA();
  if (!conditionA)
    return;
  // any additional code
  bool conditionB = executeStepB();
  if (!conditionB)
    return;
  // any additional code
  bool conditionC = executeStepC();
  if (!conditionC)
    return;
};

initialSteps();
executeThisFunctionInAnyCase();

10

আপনি যদি লুপগুলি অপছন্দ gotoও অপছন্দ করেন do { } while (0);এবং সি ++ ব্যবহার করতে পছন্দ করেন তবে একই প্রভাব পেতে আপনি একটি অস্থায়ী ল্যাম্বদাও ব্যবহার করতে পারেন।

[&]() { // create a capture all lambda
  if (!executeStepA()) { return; }
  if (!executeStepB()) { return; }
  if (!executeStepC()) { return; }
}(); // and immediately call it

executeThisFunctionInAnyCase();

1
if আপনি অপছন্দ করেছেন you && do করতে অপছন্দ করেছেন, যখন (0) && আপনি সি ++ পছন্দ করেন ... দুঃখিত, প্রতিরোধ করতে পারেনি, তবে সেই শেষ শর্তটি ব্যর্থ হয়েছে কারণ প্রশ্নটি সি হিসাবে + সি ++ রয়েছে
ক্লিকরিক

@ ক্লিকারিক সবাইকে খুশি করা সবসময়ই কঠিন। ইন আমার মতামত সি / সি ++ আপনি সাধারণত করেন, এগুলি এক এবং অন্যান্য ব্যবহার কোড নাটের গুরু হয় যেমন জিনিস আছে।
অ্যালেক্স

9

আপনার কোডে আইএফ / ইএলএসইয়ের চেইনগুলি ভাষা ইস্যু নয়, তবে আপনার প্রোগ্রামটির নকশা। আপনি যদি আপনার প্রোগ্রামটি পুনরায় ফ্যাক্টর করতে বা পুনরায় লিখতে সক্ষম হন তবে আমি আরও প্রস্তাব দিতে চাই যে আপনি আরও ভাল সমাধানের জন্য ডিজাইন প্যাটার্নগুলি ( http://sourcemaking.com/design_ Patterns ) সন্ধান করুন।

সাধারণত, আপনি যখন আপনার কোডটিতে অনেকগুলি আইএফ এর দেখতে পাচ্ছেন, তখন কৌশল নকশা প্যাটার্ন ( http://sourcemaking.com/design_patterns/strategy/c-sharp-dot-net ) বা সম্ভবত একটি সংমিশ্রণ কার্যকর করার সুযোগ হয় অন্যান্য নিদর্শন।

আমি নিশ্চিত যে / অন্যথায় একটি দীর্ঘ তালিকা লেখার বিকল্প রয়েছে, তবে আমি সন্দেহ করি যে তারা চেইনটি আপনার দেখতে সুন্দর দেখাচ্ছে ব্যতীত তারা কিছু পরিবর্তন করবে (তবে, সৌন্দর্যটি দর্শকের চোখে রয়েছে এখনও কোডটিতে প্রযোজ্য খুব :-))। আপনার মতো বিষয়গুলি সম্পর্কে উদ্বিগ্ন হওয়া উচিত (6 মাসের মধ্যে যখন আমার একটি নতুন শর্ত রয়েছে এবং আমি এই কোড সম্পর্কে কিছুই মনে রাখিনা, আমি কী সহজেই এটি যুক্ত করতে সক্ষম হব? বা চেইনের পরিবর্তন হলে কী কী দ্রুত এবং ত্রুটি-মুক্ত হয়? আমি কি এটি বাস্তবায়ন করব)


9

আপনি শুধু এই ..

coverConditions();
executeThisFunctionInAnyCase();

function coverConditions()
 {
 bool conditionA = executeStepA();
 if (!conditionA) return;
 bool conditionB = executeStepB();
 if (!conditionB) return;
 bool conditionC = executeStepC();
 if (!conditionC) return;
 }

100 এর 99 বার, এটি করার একমাত্র উপায়।

কখনও কখনও, কম্পিউটার কোডে "কৌশল" কিছু করার চেষ্টা করবেন না।


যাইহোক, আমি নিশ্চিত যে নিম্নলিখিতটি আপনার মনে রাখা আসল সমাধান ...

অবিরত বিবৃতি আলগোরিদিমিক প্রোগ্রামিং গুরুত্বপূর্ণ। (বেশিরভাগ ক্ষেত্রেই, অ্যালগরিদমিক প্রোগ্রামিংয়ে গোটো স্টেটমেন্টটি সমালোচিত))

অনেক প্রোগ্রামিং ভাষায় আপনি এটি করতে পারেন:

-(void)_testKode
    {
    NSLog(@"code a");
    NSLog(@"code b");
    NSLog(@"code c\n");
    
    int x = 69;
    
    {
    
    if ( x == 13 )
        {
        NSLog(@"code d---\n");
        continue;
        }
    
    if ( x == 69 )
        {
        NSLog(@"code e---\n");
        continue;
        }
    
    if ( x == 13 )
        {
        NSLog(@"code f---\n");
        continue;
        }
    
    }
    
    NSLog(@"code g");
    }

(সবার আগে দ্রষ্টব্য: উদাহরণের মতো নগ্ন ব্লকগুলি সুন্দর কোড লেখার একটি গুরুত্বপূর্ণ এবং গুরুত্বপূর্ণ অঙ্গ, বিশেষত যদি আপনি "অ্যালগরিদমিক" প্রোগ্রামিংয়ের সাথে ডিল করছেন are)

আবার, আপনার মাথায় ঠিক তাই ছিল, তাই না? এবং এটি এটি লেখার সুন্দর উপায়, তাই আপনার ভাল প্রবৃত্তি আছে।

তবে, দুঃখজনকভাবে, অবজেক্টিভি-সি-বর্তমান সংস্করণে (পাশাপাশি - আমি সুইফ্ট সম্পর্কে জানি না, দুঃখিত) একটি ঝুঁকিপূর্ণ বৈশিষ্ট্য রয়েছে যেখানে এটি পরীক্ষা করে এনক্লোজিং ব্লকটি লুপ কিনা।

এখানে চিত্র বর্ণনা লিখুন

আপনি কিভাবে এটি কাছাকাছি পাবেন তা এখানে ...

-(void)_testKode
    {
    NSLog(@"code a");
    NSLog(@"code b");
    NSLog(@"code c\n");
    
    int x = 69;
    
    do{
    
    if ( x == 13 )
        {
        NSLog(@"code d---\n");
        continue;
        }
    
    if ( x == 69 )
        {
        NSLog(@"code e---\n");
        continue;
        }
    
    if ( x == 13 )
        {
        NSLog(@"code f---\n");
        continue;
        }
    
    }while(false);
    
    NSLog(@"code g");
    }

তাই ভুলে যাবেন না ..

(false) করার সময় (মিথ্যা);

এর অর্থ "একবার এই ব্লকটি করুন"

অর্থাত্ লেখালেখি do{}while(false);এবং কেবল লেখার মধ্যে সম্পূর্ণ পার্থক্য নেই {}

এটি এখন আপনার ইচ্ছা মতো পুরোপুরি কাজ করে ... এখানে আউটপুট ...

এখানে চিত্র বর্ণনা লিখুন

সুতরাং, এটি সম্ভব যে আপনি নিজের মাথায় অ্যালগরিদমটি দেখেন। আপনার মাথায় যা আছে তা লেখার চেষ্টা করা উচিত always (বিশেষত আপনি যদি বিবেকবান না হন, কারণ সুন্দর যখন প্রকাশিত হয়! :))

"অ্যালগরিদমিক" প্রকল্পগুলিতে যেখানে এটি অনেক কিছু ঘটে থাকে, উদ্দেশ্য-সিতে আমাদের সর্বদা একটি ম্যাক্রো থাকে ...

#define RUNONCE while(false)

... তাহলে আপনি এটি করতে পারেন ...

-(void)_testKode
    {
    NSLog(@"code a");
    int x = 69;
    
    do{
    if ( x == 13 )
        {
        NSLog(@"code d---\n");
        continue;
        }
    if ( x == 69 )
        {
        NSLog(@"code e---\n");
        continue;
        }
    if ( x == 13 )
        {
        NSLog(@"code f---\n");
        continue;
        }
    }RUNONCE
    
    NSLog(@"code g");
    }

দুটি পয়েন্ট রয়েছে:

ক, যদিও এটি নির্বোধ যে অবজেক্টি-সি একটি অবিরত বিবৃতি রয়েছে তা যে ধরণের ব্লক পরীক্ষা করে তা "এটির সাথে লড়াই" করতে কষ্ট পাচ্ছে। সুতরাং এটি একটি কঠিন সিদ্ধান্ত।

বি, উদাহরণস্বরূপ, যে ব্লক আপনার ইন্ডেন্ট করা উচিত প্রশ্ন আছে? আমি এই জাতীয় প্রশ্নের উপর ঘুম হারিয়েছি, তাই আমি পরামর্শ দিতে পারে না।

আশা করি এটা সাহায্য করবে.



আপনি আরও খ্যাতি পেতে অনুগ্রহ রেখেছিলেন? :)
টিএমএস

এই সমস্ত মন্তব্যগুলিতে রাখার পরিবর্তে if, আপনি আরও বর্ণনামূলক ফাংশন নাম ব্যবহার করতে পারেন এবং মন্তব্যগুলিকে ফাংশনে রেখে দিতে পারেন।
টমাস আহলে

ইশ। আমি এই 1 টি লাইন সমাধান গ্রহণ করব যা সংক্ষিপ্তভাবে শর্ট সার্কিট মূল্যায়ন (যা 20 বছরেরও বেশি সময় ধরে ভাষায় রয়েছে এবং সুপরিচিত) এর সাথে এই গণ্ডগোলের উপরে পড়ছে reads আমি মনে করি আমরা উভয়ই একমত হতে পারি আমরা একে অপরের সাথে কাজ না করে খুশি।
এম

8

আপনার মৃত্যুদন্ড কার্যকর করা ফাংশনগুলিকে একটি ব্যতিক্রম ছুঁড়ে ফেলুন যদি তারা মিথ্যা প্রত্যাবর্তনের পরিবর্তে ব্যর্থ হয়। তারপরে আপনার কলিং কোডটি দেখতে দেখতে এটির মতো হতে পারে:

try {
    executeStepA();
    executeStepB();
    executeStepC();
}
catch (...)

অবশ্যই আমি ধরে নিচ্ছি যে আপনার আসল উদাহরণে ফাঁসির পদক্ষেপটি কেবল ধাপের অভ্যন্তরে কোনও ত্রুটি ঘটলে মিথ্যা ফিরে আসবে?


3
প্রবাহ নিয়ন্ত্রণ করতে ব্যতিক্রম ব্যবহার করা প্রায়শই খারাপ অনুশীলন এবং দুর্গন্ধযুক্ত কোড হিসাবে বিবেচনা করা হয়
user902383

8

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

bool ok = true;
bool conditionA = executeStepA();
// ... possibly edit conditionA, or just ok &= executeStepA();
ok &= conditionA;

if (ok) {
    bool conditionB = executeStepB();
    // ... possibly do more stuff
    ok &= conditionB;
}
if (ok) {
    bool conditionC = executeStepC();
    ok &= conditionC;
}
if (ok && additionalCondition) {
    // ...
}

executeThisFunctionInAnyCase();
// can now also:
return ok;

কেন ok &= conditionX;এবং সহজভাবে না ok = conditionX;?
এবিসিপ্লাস

@ user3253359 অনেক ক্ষেত্রে, হ্যাঁ, আপনি এটি করতে পারেন। এটি একটি ধারণাগত ডেমো; ওয়ার্কিং কোডে আমরা এটি যথাসম্ভব সহজ করার চেষ্টা করব
blgt

+1 কয়েকটি পরিষ্কার এবং রক্ষণাবেক্ষণযোগ্য উত্তরগুলির মধ্যে একটি যা প্রশ্নে বর্ণিত হিসাবে সি তে কাজ করে।
ClickRick

6

সি ++ এ (প্রশ্নটি সি এবং সি ++ উভয়ই ট্যাগ করা হয়), আপনি যদি ব্যতিক্রমগুলি ব্যবহার করতে ফাংশনগুলি পরিবর্তন করতে না পারেন তবে আপনি কিছুটা সহায়ক ফাংশন লিখলে আপনি এখনও ব্যতিক্রম প্রক্রিয়াটি ব্যবহার করতে পারেন

struct function_failed {};
void attempt(bool retval)
{
  if (!retval)
    throw function_failed(); // or a more specific exception class
}

তারপরে আপনার কোডটি নীচে পড়তে পারে:

try
{
  attempt(executeStepA());
  attempt(executeStepB());
  attempt(executeStepC());
}
catch (function_failed)
{
  // -- this block intentionally left empty --
}

executeThisFunctionInAnyCase();

যদি আপনি অভিনব বাক্য গঠনতে থাকেন তবে আপনি পরিবর্তে এটিকে স্পষ্ট কাস্টের মাধ্যমে কাজ করতে পারেন:

struct function_failed {};
struct attempt
{
  attempt(bool retval)
  {
    if (!retval)
      throw function_failed();
  }
};

তারপরে আপনি আপনার কোডটি লিখতে পারেন

try
{
  (attempt) executeStepA();
  (attempt) executeStepB();
  (attempt) executeStepC();
}
catch (function_failed)
{
  // -- this block intentionally left empty --
}

executeThisFunctionInAnyCase();

ব্যতিক্রমগুলিতে মান চেকগুলি রিফ্যাক্টরিং করা ভালভাবে যাওয়া উচিত নয়, যথেষ্ট ওভারহেড আনওয়াইন্ডিং ব্যতিক্রম রয়েছে।
জন উ

4
-1 এর মতো সি ++ তে স্বাভাবিক প্রবাহের জন্য ব্যতিক্রমগুলি ব্যবহার করা দুর্বল প্রোগ্রামিং অনুশীলন। সি ++ এ ব্যতিক্রম ব্যতিক্রমী পরিস্থিতিতে সংরক্ষণ করা উচিত।
জ্যাক এইডলি

1
প্রশ্নের পাঠ্য (আমার দ্বারা জোর দেওয়া) থেকে: "ফাংশনগুলি এক্সিকিউটেস্টপেক্স এক্সিকিউট করা উচিত যদি এবং কেবল পূর্ববর্তী সফল হয় তবেই " অন্য কথায়, ফিরতি মান ব্যর্থতা নির্দেশ করতে ব্যবহৃত হয়। অর্থাৎ এ ত্রুটি পরিচালনা আছে (এবং এক আশা করব যে ব্যর্থতা হয় ব্যতিক্রমী)। ত্রুটি পরিচালনা হয় ঠিক কি ব্যতিক্রম জন্য উদ্ভাবিত হয়েছে।
celtschk

1
নাঃ। প্রথমত, ত্রুটি পরিচালনার জন্য নয়, ত্রুটি প্রচারের জন্য ব্যতিক্রমগুলি তৈরি করা হয়েছিল ; দ্বিতীয়ত, "ফাংশনগুলি এক্সিকিউটস্টেপেক্স এক্সিকিউট করা উচিত যদি এবং শুধুমাত্র পূর্ববর্তী সফল হয়।" পূর্ববর্তী ফাংশন দ্বারা ফিরিয়ে দেওয়া বুলিয়ান মিথ্যাটি স্পষ্টতই ব্যতিক্রমী / ভ্রান্ত মামলার ইঙ্গিত দেয় না। আপনার বিবৃতিটি এইভাবে নন সিকুইটার । ত্রুটি পরিচালনা ও প্রবাহ স্যানিটাইজেশন অনেকগুলি বিভিন্ন উপায়ে প্রয়োগ করা যেতে পারে, ব্যতিক্রমগুলি এমন একটি সরঞ্জাম যা ত্রুটি প্রচার এবং স্থানের বাইরে ত্রুটি পরিচালনার মঞ্জুরি দেয় এবং এতে এক্সেল হয়।

6

যদি আপনার কোডটি উদাহরণ হিসাবে সহজ হয় এবং আপনার ভাষা শর্ট সার্কিট মূল্যায়ন সমর্থন করে, আপনি এটি চেষ্টা করতে পারেন:

StepA() && StepB() && StepC() && StepD();
DoAlways();

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


আসলে আমি বিষয়টিকে আরও ভালভাবে ব্যাখ্যা করার জন্য আমার প্রশ্নটি সম্পাদনা করেছি, তবে বেশিরভাগ উত্তর অকার্যকর করতে অস্বীকৃত হয়েছিল। : \
এবিসিপ্লাস

আমি এসও-তে একটি নতুন ব্যবহারকারী এবং একজন নবাগত প্রোগ্রামার। 2 টি প্রশ্ন তখন: আপনার যে প্রশ্নটির মতো অন্য একটি প্রশ্ন এই প্রশ্নের কারণে সদৃশ হিসাবে চিহ্নিত হবে এমন ঝুঁকি রয়েছে? আর একটি বিষয় হ'ল: কোনও নবাগত এসও ব্যবহারকারী / প্রোগ্রামার কীভাবে সেখানে সবার মধ্যে সেরা উত্তরটি বেছে নিতে পারে (প্রায় ভাল আমি মনে করি ..)?
এবিসিপ্লাস

6

সি ++ 11 এবং এর বাইরে, ডি এর স্কোপ (প্রস্থান) ব্যবস্থার অনুরূপ স্কোপ প্রস্থান ব্যবস্থা বাস্তবায়নের জন্য একটি দুর্দান্ত পদ্ধতির হতে পারে ।

এটি প্রয়োগের একটি সম্ভাব্য উপায় হ'ল সি ++ 11 ল্যাম্বডাস এবং কিছু সহায়ক ম্যাক্রোগুলি:

template<typename F> struct ScopeExit 
{
    ScopeExit(F f) : fn(f) { }
    ~ScopeExit() 
    { 
         fn();
    }

    F fn;
};

template<typename F> ScopeExit<F> MakeScopeExit(F f) { return ScopeExit<F>(f); };

#define STR_APPEND2_HELPER(x, y) x##y
#define STR_APPEND2(x, y) STR_APPEND2_HELPER(x, y)

#define SCOPE_EXIT(code)\
    auto STR_APPEND2(scope_exit_, __LINE__) = MakeScopeExit([&](){ code })

এটি আপনাকে ফাংশন থেকে তাড়াতাড়ি ফিরে আসার অনুমতি দেয় এবং আপনার নির্ধারিত যে কোনও ক্লিনআপ কোড সর্বদা সুযোগ ছাড়ার পরে কার্যকর করা হবে তা নিশ্চিত করবে:

SCOPE_EXIT(
    delete pointerA;
    delete pointerB;
    close(fileC); );

if (!executeStepA())
    return;

if (!executeStepB())
    return;

if (!executeStepC())
    return;

ম্যাক্রোগুলি সত্যই সজ্জা। MakeScopeExit()সরাসরি ব্যবহার করা যেতে পারে।


এই কাজটি করার জন্য ম্যাক্রোগুলির কোনও প্রয়োজন নেই। এবং [=]সাধারণত একটি স্কোপড ল্যাম্বডায় ভুল।
ইয়াক্ক - অ্যাডাম নেভ্রামামন্ট

হ্যাঁ, ম্যাক্রোগুলি কেবল সাজসজ্জার জন্য এবং এটিকে ফেলে দেওয়া যায়। তবে আপনি কি বলবেন না যে মান অনুসারে ক্যাপচার করা সবচেয়ে নিরাপদ "জেনেরিক" পদ্ধতির?
গ্ল্যাম্পার্ট

1
না: যদি আপনার ল্যাম্বদা ল্যাম্বডা তৈরি করা বর্তমান সুযোগের বাইরে না থেকে থাকে তবে ব্যবহার করুন [&]: এটি নিরাপদ এবং সামান্যতম আশ্চর্যের। ঘোষণার পর্যায়ে ল্যাম্বডা (বা অনুলিপিগুলি) সুযোগের চেয়ে বেশি সময় বেঁচে থাকতে পারে তখনই মূল্য দ্বারা ক্যাপচার করুন ...
ইয়াক্ক - অ্যাডাম নেভ্রামামন্ট

হ্যাঁ, এটা বোঝা যায়। আমি এটা পরিবর্তন করব। ধন্যবাদ!
গ্ল্যাম্পার্ট

6

কেউ কেন সহজ সমাধান দিচ্ছেন না? : ডি

আপনার সমস্ত ফাংশনের যদি একই স্বাক্ষর থাকে তবে আপনি এটি এইভাবে (সি ভাষার জন্য) করতে পারেন:

bool (*step[])() = {
    &executeStepA,
    &executeStepB,
    &executeStepC,
    ... 
};

for (int i = 0; i < numberOfSteps; i++) {
    bool condition = step[i]();

    if (!condition) {
        break;
    }
}

executeThisFunctionInAnyCase();

একটি পরিষ্কার সি ++ সমাধানের জন্য আপনার এমন একটি ইন্টারফেস ক্লাস তৈরি করা উচিত যা এক্সিকিউট পদ্ধতি এবং আপনার পদক্ষেপগুলিকে বস্তুগুলিতে মোড়ক করে wra
তারপরে, উপরের সমাধানটি এর মতো দেখাবে:

Step *steps[] = {
    stepA,
    stepB,
    stepC,
    ... 
};

for (int i = 0; i < numberOfSteps; i++) {
    Step *step = steps[i];

    if (!step->execute()) {
        break;
    }
}

executeThisFunctionInAnyCase();

5

ধরে নিই যে আপনার স্বতন্ত্র অবস্থার পরিবর্তনশীলগুলির দরকার নেই, পরীক্ষাগুলি উল্টিয়ে দেওয়া এবং "ঠিক আছে" পথ হিসাবে অন্যটি-ফ্যালথ্রো ব্যবহার করা যদি আপনাকে / অন্য বিবৃতিগুলির আরও উল্লম্ব সেট পেতে দেয়:

bool failed = false;

// keep going if we don't fail
if (failed = !executeStepA())      {}
else if (failed = !executeStepB()) {}
else if (failed = !executeStepC()) {}
else if (failed = !executeStepD()) {}

runThisFunctionInAnyCase();

ব্যর্থ ভেরিয়েবল ছাড়াই কোডটি কিছুটা অস্পষ্ট IMO করে তোলে।

ভিতরে ভেরিয়েবলগুলি ঘোষণা করা ঠিক আছে, = বনাম == সম্পর্কে কোনও চিন্তা নেই।

// keep going if we don't fail
if (bool failA = !executeStepA())      {}
else if (bool failB = !executeStepB()) {}
else if (bool failC = !executeStepC()) {}
else if (bool failD = !executeStepD()) {}
else {
     // success !
}

runThisFunctionInAnyCase();

এটি অস্পষ্ট, তবে কমপ্যাক্ট:

// keep going if we don't fail
if (!executeStepA())      {}
else if (!executeStepB()) {}
else if (!executeStepC()) {}
else if (!executeStepD()) {}
else { /* success */ }

runThisFunctionInAnyCase();

5

এই রাষ্ট্র মেশিন, যা সুবিধাজনক কারণ আপনি সহজেই একটি সঙ্গে এটি বাস্তবায়ন করতে পারে মত দেখায় রাষ্ট্রীয় প্যাটার্ন

জাভাতে এটি দেখতে এরকম কিছু দেখাবে:

interface StepState{
public StepState performStep();
}

একটি বাস্তবায়ন নিম্নলিখিত হিসাবে কাজ করবে:

class StepA implements StepState{ 
    public StepState performStep()
     {
         performAction();
         if(condition) return new StepB()
         else return null;
     }
}

ইত্যাদি। তারপরে আপনি যদি বড়টি শর্তযুক্ত করে থাকেন তবে:

Step toDo = new StepA();
while(toDo != null)
      toDo = toDo.performStep();
executeThisFunctionInAnyCase();

5

রোমিক যেমন উল্লেখ করেছেন, আপনি এটির জন্য একটি নকশার প্যাটার্ন প্রয়োগ করতে পারেন, তবে আমি স্ট্র্যাটেজির পরিবর্তে ডেকোরেটর প্যাটার্নটি ব্যবহার করব যেহেতু আপনি চেইন কল করতে চান। কোডটি যদি সহজ হয় তবে আমি বাসা বাঁধতে রোধ করার জন্য সুন্দর কাঠামোগত উত্তরগুলির সাথে একটিতে যাব। তবে, যদি এটি জটিল হয় বা গতিশীল শৃঙ্খলার প্রয়োজন হয়, তবে ডেকোরেটর প্যাটার্নটি একটি ভাল পছন্দ। এখানে একটি YUML শ্রেণীর চিত্র রয়েছে :

YUML বর্গ ডায়াগ্রাম

এখানে একটি নমুনা লিনকপ্যাড সি # প্রোগ্রাম রয়েছে:

void Main()
{
    IOperation step = new StepC();
    step = new StepB(step);
    step = new StepA(step);
    step.Next();
}

public interface IOperation 
{
    bool Next();
}

public class StepA : IOperation
{
    private IOperation _chain;
    public StepA(IOperation chain=null)
    {
        _chain = chain;
    }

    public bool Next() 
    {
        bool localResult = false;
        //do work
        //...
        // set localResult to success of this work
        // just for this example, hard coding to true
        localResult = true;
        Console.WriteLine("Step A success={0}", localResult);

        //then call next in chain and return
        return (localResult && _chain != null) 
            ? _chain.Next() 
            : true;
    }
}

public class StepB : IOperation
{
    private IOperation _chain;
    public StepB(IOperation chain=null)
    {
        _chain = chain;
    }

    public bool Next() 
    {   
        bool localResult = false;

        //do work
        //...
        // set localResult to success of this work
        // just for this example, hard coding to false, 
            // to show breaking out of the chain
        localResult = false;
        Console.WriteLine("Step B success={0}", localResult);

        //then call next in chain and return
        return (localResult && _chain != null) 
            ? _chain.Next() 
            : true;
    }
}

public class StepC : IOperation
{
    private IOperation _chain;
    public StepC(IOperation chain=null)
    {
        _chain = chain;
    }

    public bool Next() 
    {
        bool localResult = false;
        //do work
        //...
        // set localResult to success of this work
        // just for this example, hard coding to true
        localResult = true;
        Console.WriteLine("Step C success={0}", localResult);
        //then call next in chain and return
        return (localResult && _chain != null) 
            ? _chain.Next() 
            : true;
    }
}

আইএমএইচও, ডিজাইনের ধরণগুলিতে পড়ার সেরা বইটি হুড ফার্স্ট ডিজাইন প্যাটার্নস


জেফফ্রির উত্তরের মতো কিছু দিয়ে এর কী লাভ?
ডিসেম্বর

অনেক বেশি পরিবর্তনশীল স্থিতিস্থাপক, যখন প্রয়োজনীয়তাগুলি পরিবর্তন হয় যখন ডোমেনের অনেক জ্ঞান ছাড়াই এই পদ্ধতির পরিচালনা করা সহজ হয়। বিশেষত যখন আপনি বিবেচনা করেন তবে নেস্টেড আইএফএসের কিছু অংশ কত গভীর এবং দীর্ঘস্থায়ী হতে পারে। এটি সমস্ত খুব ভঙ্গুর পেতে পারে এবং এইভাবে কাজ করার জন্য উচ্চ ঝুঁকিপূর্ণ হতে পারে। আমাকে ভুল করবেন না কিছু অপ্টিমাইজেশনের পরিস্থিতি আপনাকে এটিকে ছিঁড়ে ফেলা এবং যদি ফিরে আসতে পারে তবে এই সময়টি 99% হয় this তবে মুল বক্তব্যটি আপনি যখন সেই স্তরে পৌঁছান তখন আপনাকে রক্ষণাবেক্ষণের যত্ন নিতে হবে না কারণ আপনার কর্মক্ষমতা প্রয়োজন need
জন নিকোলাস

4

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

সাধারণ প্যাটার্নটি ব্যবহার করা ছিল do { } while (false);

while(false)এটি তৈরি করতে আমি একটি ম্যাক্রো ব্যবহার করেছি do { } once;সাধারণ প্যাটার্নটি ছিল:

do
{
    bool conditionA = executeStepA();
    if (! conditionA) break;
    bool conditionB = executeStepB();
    if (! conditionB) break;
    // etc.
} while (false);

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


4

ম্যাথিউয়ের সি ++ 11 উত্তরের উন্নতি করতে এবং ব্যবহারের মাধ্যমে ব্যয় করা রানটাইম ব্যয়টি এড়াতে std::function, আমি নিম্নলিখিতটি ব্যবহার করার পরামর্শ দেব

template<typename functor>
class deferred final
{
public:
    template<typename functor2>
    explicit deferred(functor2&& f) : f(std::forward<functor2>(f)) {}
    ~deferred() { this->f(); }

private:
    functor f;
};

template<typename functor>
auto defer(functor&& f) -> deferred<typename std::decay<functor>::type>
{
    return deferred<typename std::decay<functor>::type>(std::forward<functor>(f));
}

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

ব্যবহারের উদাহরণ:

auto guard = defer(executeThisFunctionInAnyCase);
bool conditionA = executeStepA();
if (!conditionA) return;
bool conditionB = executeStepB();
if (!conditionB) return;
bool conditionC = executeStepC();
if (!conditionC) return;

যেমন ম্যাথিউয়ের উত্তর এই সমাধানটি সম্পূর্ণ ব্যতিক্রম নিরাপদ executeThisFunctionInAnyCaseএবং সব ক্ষেত্রেই ডাকা হবে। করা উচিত executeThisFunctionInAnyCaseনিজেই নিক্ষেপ, destructors পরোক্ষভাবে চিহ্নিত করা হয়েছে noexceptএবং এর ফলে একটি কল std::terminateপরিবর্তে জারি ঘটাচ্ছে হবে একটি ব্যতিক্রম স্ট্যাক unwinding সময় নিক্ষিপ্ত হবে।


+1 আমি এই উত্তরটি খুঁজছিলাম তাই আমাকে এটি পোস্ট করতে হবে না। আপনি নিখুঁত এগিয়ে উচিত functorমধ্যে deferred; 'd কন্সট্রাকটর, কোন প্রয়োজন একটি বলপূর্বক move
ইয়াক্ক - অ্যাডাম নেভ্রামামন্ট

@ ইয়াক কন্সট্রাক্টরকে ফরওয়ার্ডিং কনস্ট্রাক্টর হিসাবে পরিবর্তন করেছেন
জো

3

দেখে মনে হচ্ছে আপনি একক ব্লক থেকে আপনার সমস্ত কল করতে চান। অন্যরা যেমন প্রস্তাব করেছে, আপনার উচিত একটি whileলুপ ব্যবহার করে ছেড়ে যাওয়া উচিত breakবা কোনও নতুন ফাংশন যা আপনি রেখে দিতে পারেন return(পরিষ্কার হতে পারে)।

gotoএমনকি আমি ফাংশন থেকে বেরিয়ে আসার জন্য ব্যক্তিগতভাবে নিষেধ করি । ডিবাগ করার সময় এগুলি খুঁজে পাওয়া শক্ত।

আপনার কর্মপ্রবাহের জন্য কাজ করা উচিত একটি মার্জিত বিকল্প হ'ল এটিতে একটি ফাংশন অ্যারে তৈরি করা এবং পুনরাবৃত্তি করা।

const int STEP_ARRAY_COUNT = 3;
bool (*stepsArray[])() = {
   executeStepA, executeStepB, executeStepC
};

for (int i=0; i<STEP_ARRAY_COUNT; ++i) {
    if (!stepsArray[i]()) {
        break;
    }
}

executeThisFunctionInAnyCase();

ভাগ্যক্রমে, ডিবাগারটি আপনার জন্য এটি স্পট করে। আপনি যদি ডিবাগ করছেন এবং কোডের মাধ্যমে একক পদক্ষেপ না নিচ্ছেন, তবে আপনি এটি ভুল করছেন।
কোডি গ্রে

আপনি কী বলতে চাইছেন তা আমি বুঝতে পারছি না, কেন আমি একক পদক্ষেপ ব্যবহার করতে পারি না?
অ্যাক্সফ্যাব

3

কারণ আপনারও আছে মৃত্যুদন্ড কার্যকর করার মধ্যে [... কোড অবরুদ্ধ ...] থাকার কারণে, আমার ধারণা আপনার মেমরি বরাদ্দ বা অবজেক্টের সূচনা রয়েছে। এইভাবে আপনাকে প্রস্থান করার সময় ইতিমধ্যে শুরু করা সমস্ত পরিষ্কার করার বিষয়ে যত্ন নিতে হবে এবং আপনার সমস্যা দেখা দিলে এবং কোনও ফাংশন মিথ্যা ফিরে আসবে তা পরিষ্কার করে ফেলতে হবে।

এই ক্ষেত্রে, আমি আমার অভিজ্ঞতায় সবচেয়ে ভাল যা ছিল (যখন আমি ক্রিপ্টোএপিআইয়ের সাথে কাজ করেছি) ছোট ক্লাস তৈরি করছিল, নির্মাত্রে আপনি আপনার ডেটা প্রবর্তন করবেন, ডেস্ট্রাক্টরে আপনি এটি অবিচ্ছিন্ন করতে পারেন। প্রতিটি পরবর্তী ফাংশন ক্লাস পূর্ববর্তী ফাংশন ক্লাসের শিশু হতে হবে। যদি কিছু ভুল হয়ে যায় - ব্যতিক্রম ছুঁড়ে দিন।

class CondA
{
public:
    CondA() { 
        if (!executeStepA()) 
            throw int(1);
        [Initialize data]
    }
    ~CondA() {        
        [Clean data]
    }
    A* _a;
};

class CondB : public CondA
{
public:
    CondB() { 
        if (!executeStepB()) 
            throw int(2);
        [Initialize data]
    }
    ~CondB() {        
        [Clean data]
    }
    B* _b;
};

class CondC : public CondB
{
public:
    CondC() { 
        if (!executeStepC()) 
            throw int(3);
        [Initialize data]
    }
    ~CondC() {        
        [Clean data]
    }
    C* _c;
};

এবং তারপরে আপনার কোডে আপনাকে কেবল কল করতে হবে:

shared_ptr<CondC> C(nullptr);
try{
    C = make_shared<CondC>();
}
catch(int& e)
{
    //do something
}
if (C != nullptr)
{
   C->a;//work with
   C->b;//work with
   C->c;//work with
}
executeThisFunctionInAnyCase();

আমার ধারণা, কন্ডিশনএক্সের প্রতিটি কল যদি কিছু শুরু করে, মেমরি বরাদ্দ করে এবং ইত্যাদি সবকিছু পরিষ্কার হয়ে যায় তা নিশ্চিত হওয়ার পক্ষে সেরা solution


3

একটি আকর্ষণীয় উপায় ব্যতিক্রমগুলি নিয়ে কাজ করা।

try
{
    executeStepA();//function throws an exception on error
    ......
}
catch(...)
{
    //some error handling
}
finally
{
    executeThisFunctionInAnyCase();
}

আপনি যদি এই জাতীয় কোড লিখেন তবে আপনি কোনওভাবে ভুল দিকে যাচ্ছেন। এ জাতীয় কোড থাকতে আমি এটিকে "সমস্যা" হিসাবে দেখব না, তবে এইরকম অগোছালো "আর্কিটেকচার" রাখি।

টিপ: আপনি বিশ্বাস করেন এমন একটি পাকা বিকাশকারীদের সাথে সেগুলি নিয়ে আলোচনা করুন ;-)


আমি মনে করি এই ধারণাটি প্রতিটি আইফ-চেইন প্রতিস্থাপন করতে পারে না। যাইহোক, অনেক ক্ষেত্রে, এটি একটি খুব ভাল পদ্ধতির!
হোয়াই

3

আরেকটি পদ্ধতির - do - whileলুপ, যদিও এটির আগে যেমন এটির উদাহরণ দেখা যায় নি তার আগে এটি উল্লেখ করা হয়েছিল যা এটি দেখতে কেমন দেখাচ্ছে:

do
{
    if (!executeStepA()) break;
    if (!executeStepB()) break;
    if (!executeStepC()) break;
    ...

    break; // skip the do-while condition :)
}
while (0);

executeThisFunctionInAnyCase();

(আচ্ছা whileলুপের সাথে ইতিমধ্যে একটি উত্তর রয়েছে তবে do - whileলুপটি পুনরুতরূপে সত্যের জন্য পরীক্ষা শুরু করে না (শুরুতে) তবে পরিবর্তে শেষের দিকে xD (যদিও এটি এড়িয়ে যেতে পারে))।


আরে জাফি - এই উত্তরটি করার ক্ষেত্রে (মিথ্যা) পদ্ধতির ব্যাপক ব্যাখ্যা রয়েছে। stackoverflow.com/a/24588605/294884 অন্য দুটি উত্তরও এর উল্লেখ করেছে।
ফ্যাটি

এটি একটি আকর্ষণীয় প্রশ্ন যা এই পরিস্থিতিতে CONTINUE ব্যবহার করা আরও মার্জিত বা BREAK!
ফ্যাটি

আরে @ জো ব্লো আমি সমস্ত উত্তর দেখেছি ... কেবল এটি সম্পর্কে কথা বলার পরিবর্তে দেখাতে চেয়েছিলাম :)
জাফি

আমার প্রথম উত্তরটি আমি এখানে বলেছি "" এটির কথা কেউ উল্লেখ করেনি ... "এবং তাত্ক্ষণিকভাবে কেউ কেউ আন্তরিকতার সাথে উল্লেখ করেছিলেন যে এটি দ্বিতীয় শীর্ষ উত্তর ছিল :)
ফ্যাটি

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