প্রতিক্রিয়া পরিচালনা করার জন্য নকশার প্যাটার্ন


10

বেশিরভাগ সময় যখন আমি এমন কিছু কোড লিখি যা নির্দিষ্ট ফাংশন কলটির প্রতিক্রিয়া পরিচালনা করে আমি নিম্নলিখিত কোড কাঠামোটি পাই:

উদাহরণ: এটি এমন একটি ফাংশন যা লগইন সিস্টেমের জন্য প্রমাণীকরণটি পরিচালনা করবে

class Authentication{

function login(){ //This function is called from my Controller
$result=$this->authenticate($username,$password);

if($result=='wrong password'){
   //increase the login trials counter
   //send mail to admin
   //store visitor ip    
}else if($result=='wrong username'){
   //increase the login trials counter
   //do other stuff
}else if($result=='login trials exceeded')
   //do some stuff
}else if($result=='banned ip'){
   //do some stuff
}else if...

function authenticate($username,$password){
   //authenticate the user locally or remotely and return an error code in case a login in fails.
}    
}

সমস্যা

  1. যেহেতু আপনি দেখতে পারেন কোড একটি মধ্যে build হয় if/elseকাঠামো একটি নতুন ব্যর্থতা অবস্থা মানে হবে এই যে আমি একজন যোগ করতে হবে যার মানে else ifমন্তব্যটির জন্য লঙ্ঘন খুলুন বন্ধ পুঁজি
  2. আমি একটি অনুভূতি পেয়েছি যে ফাংশনটির বিমূর্ততার বিভিন্ন স্তর রয়েছে কারণ আমি কেবলমাত্র একটি হ্যান্ডলারে লগইন ট্রায়ালগুলির কাউন্টারকে বাড়িয়ে তুলতে পারি, তবে অন্যটিতে আরও গুরুতর স্টাফ করি।
  3. কিছু ফাংশন increase the login trialsউদাহরণস্বরূপ পুনরাবৃত্তি হয় ।

আমি একাধিককে if/elseকারখানার ধরণে রূপান্তর করার বিষয়ে চিন্তাভাবনা করেছি , তবে আমি কেবলমাত্র কারখানাটি ব্যবহার করে এমন আচরণ তৈরি না করে অবজেক্ট তৈরি করতে ব্যবহার করেছি। কারও কি এর জন্য আরও ভাল সমাধান আছে?

বিঃদ্রঃ:

এটি লগইন সিস্টেমটি ব্যবহার করে কেবল উদাহরণ। আমি ভালভাবে নির্মিত ও ও প্যাটার্ন ব্যবহার করে এই আচরণের একটি সাধারণ সমাধান চাইছি। এই ধরণের if/elseহ্যান্ডলারগুলি আমার কোডে অনেক জায়গায় উপস্থিত হয় এবং আমি উদাহরণটি ব্যাখ্যা করার জন্য একটি সহজ সহজ হিসাবে লগইন সিস্টেমটি ব্যবহার করি। আমার আসল ব্যবহারের কেসগুলি এখানে পোস্ট করা অনেক জটিল। : ডি

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


হালনাগাদ

আমার প্রশ্নটি পরিষ্কার করার জন্য আরও একটি জটিল কোড উদাহরণ:

  public function refundAcceptedDisputes() {            
        $this->getRequestedEbayOrdersFromDB(); //get all disputes requested on ebay
        foreach ($this->orders as $order) { /* $order is a Doctrine Entity */
            try {
                if ($this->isDisputeAccepted($order)) { //returns true if dispute was accepted
                    $order->setStatus('accepted');
                    $order->refund(); //refunds the order on ebay and internally in my system
                    $this->insertRecordInOrderHistoryTable($order,'refunded');                        
                } else if ($this->isDisputeCancelled($order)) { //returns true if dispute was cancelled
                    $order->setStatus('cancelled');
                    $this->insertRecordInOrderHistory($order,'cancelled');
                    $order->rollBackRefund(); //cancels the refund on ebay and internally in my system
                } else if ($this->isDisputeOlderThan7Days($order)) { //returns true if 7 days elapsed since the dispute was opened
                    $order->closeDispute(); //closes the dispute on ebay
                    $this->insertRecordInOrderHistoryTable($order,'refunded');
                    $order->refund(); //refunds the order on ebay and internally in my system
                }
            } catch (Exception $e) {
                $order->setStatus('failed');
                $order->setErrorMessage($e->getMessage());
                $this->addLog();//log error
            }
            $order->setUpdatedAt(time());
            $order->save();
        }
    }

ফাংশন উদ্দেশ্য:

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

উত্তর:


15

কৌশল কৌশল অনুসারে এটি একজন প্রধান প্রার্থী ।

উদাহরণস্বরূপ, এই কোড:

if ($this->isDisputeAccepted($order)) { //returns true if dispute was accepted
    $order->setStatus('accepted');
    $order->refund(); //refunds the order on ebay and internally in my system
    $this->insertRecordInOrderHistoryTable($order,'refunded');                        
} else if ($this->isDisputeCancelled($order)) { //returns true if dispute was cancelled
    $order->setStatus('cancelled');
    $this->insertRecordInOrderHistory($order,'cancelled');
    $order->rollBackRefund(); //cancels the refund on ebay and internally in my system
} else if ($this->isDisputeOlderThan7Days($order)) { //returns true if 7 days elapsed since the dispute was opened
    $order->closeDispute(); //closes the dispute on ebay
    $this->insertRecordInOrderHistoryTable($order,'refunded');
    $order->refund(); //refunds the order on ebay and internally in my system
}

কমে যেতে পারে

var $strategy = $this.getOrderStrategy($order);
$strategy->preProcess();
$strategy->updateOrderHistory($this);
$strategy->postProcess();

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

মন্তব্যগুলিতে প্রশ্নের উত্তর দিতে সম্পাদনা করুন।

আপনি কি দয়া করে আপনার কোডটি আরও বিস্তারিত বলতে পারেন আমি যা বুঝতে পেরেছি তা হল getOrderStrategy একটি ফ্যাক্টরি পদ্ধতি যা আদেশের স্থিতির উপর নির্ভর করে একটি কৌশল অবজেক্ট দেয়, তবে প্রাকপ্রসেস () এবং প্রাকপ্রসেস () ফাংশনগুলি কী। এছাড়াও আপনি কেন ওর্ডার হিস্টোরি ($ এটি) আপডেট করতে পাস করেছেন?

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

আপনার কোডের একটি সাধারণ টুকরা হ'ল ইনসার্টরেকর্ডইনঅর্ডারহিসটরি টেবিল, সুতরাং আমি কৌশলটির কেন্দ্রীয় পয়েন্ট হিসাবে এটি (কিছুটা জেনেরিক নাম সহ) ব্যবহার করতে বেছে নিয়েছি। আমি এটিতে এটি পাস করি, কারণ এটি a ক্রম এবং কৌশল অনুসারে আলাদা স্ট্রিং সহ এটিতে একটি পদ্ধতি কল করে।

সুতরাং, মূলত, আমি যারা দেখতে তাদের প্রত্যেকের কল্পনা করি:

public function updateOrderHistory($auth) {
    $auth.insertRecordInOrderHistoryTable($order, 'cancelled');
}

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

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

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

var $strategy = $this.getOrderStrategy($order);
$strategy->setStatus();
$strategy->closeDisputeIfNecessary();
$strategy->refundIfNecessary();
$strategy->insertRecordInOrderHistoryTable($this);                        
$strategy->rollBackRefundIfNecessary();

এবং আপনার কয়েকটি কৌশল "ifNecessary" পদ্ধতির জন্য খালি পদ্ধতিগুলি প্রয়োগ করে।

যা কিছু কলিং কোডটিকে আরও পঠনযোগ্য করে তোলে।


আপনার উত্তরের জন্য ধন্যবাদ, তবে আপনি দয়া করে আপনার কোডটি আরও বিস্তারিতভাবে বর্ণনা করতে পারেন। আমি যা বুঝতে পেরেছি তা হ'ল এটি getOrderStrategyএকটি ফ্যাক্টরি পদ্ধতি যা strategyক্রম স্থিতির উপর নির্ভর করে কোনও বস্তু ফেরত দেয় তবে কী preProcess()এবং কী কী তা হয় preProcess()। এছাড়াও আপনি কেন পাস $thisকরেছেন updateOrderHistory($this)?
স্যাঙ্গো

1
@ সাঙ্গো: আশা করি উপরের সম্পাদনাটি সহায়তা করবে।
পিডিআর

আহা! আমি এখন এটি পেয়েছি বলে মনে করি। অবশ্যই আমার কাছ থেকে একটি আপ-ভোট :)
সানগো

+1, আপনি বিস্তারিতভাবে বলতে পারেন, লাইন কিনা, var $ কৌশল = $ this.getOrderStrategy ($ অর্ডার); কৌশলটি সনাক্ত করার জন্য একটি স্যুইচ কেস থাকবে।
নবীন কুমার

2

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

if($result=='wrong password')
   wrongPassword();
else if($result=='wrong username')
   wrongUsername();
else if($result=='login trials exceeded')
   excessiveTries();
else if($result=='banned ip')
   bannedIp();

1

আপনি যখন কোনও স্ট্যাটাস পরিচালনা করতে / তারপর / অন্য বিবৃতিগুলির একটি গোছা শুরু করেন, তখন স্টেট প্যাটার্নটি বিবেচনা করুন ।

এটি ব্যবহারের একটি বিশেষ পদ্ধতিতে একটি প্রশ্ন ছিল: রাষ্ট্রীয় প্যাটার্নটির এই প্রয়োগটি কি কোনও অর্থবোধ করে?

আমি এই প্যাটারে নতুন, তবে আমি কখন এটি ব্যবহার করব তা নিশ্চিত হওয়ার জন্য আমি উত্তরটি রেখেছি ("সমস্ত সমস্যা একটি হাতুড়ির কাছে নখের মতো দেখায়" "এড়িয়ে চলুন)।


0

আমি আমার মন্তব্যে যেমন বলেছি, জটিল যুক্তিগুলি আসলে কিছুই পরিবর্তন করে না।

আপনি একটি বিতর্কিত আদেশ প্রক্রিয়া করতে চান। এটি করার একাধিক উপায় রয়েছে। বিতর্কিত আদেশের प्रकार হতে পারে Enum:

public void ProcessDisputedOrder(DisputedOrder order)
{
   switch (order.Type)
   {
       case DisputedOrderType.Canceled:
          var strategy = new StrategyForDisputedCanceledOrder();
          strategy.Process(order);  
          break;

       case DisputedOrderType.LessThan7Days:
          var strategy = new DifferentStrategy();
          strategy.Process(order);
          break;

       default: 
          throw new NotImplementedException();
   }
}

এই কাজ করার অনেক উপায় আছে। আপনি এর উত্তরাধিকার অনুক্রমের থাকতে পারে Order, DisputedOrder, DisputedOrderLessThan7Days, DisputedOrderCanceled, ইত্যাদি এই চমৎকার নয়, কিন্তু এটি কাজ করবে।

উপরের আমার উদাহরণে আমি অর্ডার প্রকারের দিকে তাকান এবং এর জন্য প্রাসঙ্গিক কৌশল পাই। আপনি এই প্রক্রিয়াটিকে একটি কারখানায় আবদ্ধ করতে পারেন:

var strategy = DisputedOrderStrategyFactory.Instance.Build(order.Type);

এটি অর্ডার প্রকারের দিকে নজর দেবে এবং আপনাকে সেই ধরণের অর্ডারের জন্য একটি সঠিক কৌশল দেয়।

আপনি এর লাইনে কিছু দিয়ে শেষ করতে পারেন:

public void ProcessDisputedOrder(DisputedOrder order)
{
   var strategy = DisputedOrderStrategyFactory.Instance.Build(order.Type);   
   strategy.Process(order);
}

আসল উত্তর, আপনি যেহেতু সহজ কিছু করার পরে ভেবেছিলেন তেমন প্রাসঙ্গিক নয়:

আমি এখানে নিম্নলিখিত উদ্বেগগুলি দেখতে পাচ্ছি:

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

আমি নিম্নলিখিত করতে হবে:

CheckBannedIP(login.IP);
CheckLoginTrial(login);

Authenticate(login.Username, login.Password);

public void CheckBannedIP(string ip)
{
    // If banned then re-direct, else do nothing.
}

public void CheckLoginTrial(LoginAttempt login)
{
    // If exceeded trials, then inform user, else do nothing
}

public void Authenticate(string username, string password)
{
     // Attempt to authenticate. On success redirect, else catch any errors and inform the user. 
}

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

কারখানা বস্তুর নির্মাণকে encapsulates। আপনার উদাহরণে কোনও কিছুর নির্মাণের প্রয়োজন নেই, আপনাকে যা করতে হবে তা হ'ল আপনার উদ্বেগগুলি আলাদা করা।


আপনার জবাবের জন্য ধন্যবাদ, তবে প্রতিটি প্রতিক্রিয়ার স্থিতির জন্য আমার হ্যান্ডলারগুলি সত্যিই জটিল হতে পারে। প্রশ্নের আপডেট দেখুন।
সোনগো

এটি কিছুই পরিবর্তন করে না। কিছু কৌশল ব্যবহার করে বিতর্কিত আদেশ প্রক্রিয়া করা দায়বদ্ধতা। কৌশল বিভিন্ন ধরণের বিবাদের সাথে পরিবর্তিত হতে পারে।
কোডার্ট

দয়া করে একটি আপডেট দেখুন। আরও জটিল যুক্তির জন্য আপনি আপনার বিতর্কিত আদেশ কৌশল তৈরিতে কারখানাটি ব্যবহার করতে পারেন।
কোডার্ট

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