ZugZwang
ZugZwang

Reputation: 418

Cascade of IF statements - best solution

I have this situation:

enter image description here

The User can choose between 3 products, A, B or C, like showed in the image. After the user clicks one of the products, he is redirected to a register form where he must include some data, including x and y. If the selected product and the value of x and y are not right, an error is launched. If the entered data is correct, then some other actions are done. I've tried to implement this control, but I'm not sure this is the best solution.

if ($product==("A") && x < 10 && y <= 2)
{
     price = 10;                      

}

else if ($product ==("B") && x < 50 && y <= 10 && y >2)
{
      price = 20;                  
}

else if ($product ==("C") && x < 250 && y <=50)
{
       price = 30;                 
}

Upvotes: 2

Views: 1187

Answers (2)

Rotari Radu
Rotari Radu

Reputation: 655

//not a short solution or a fast one but has some advantages:
//1. has some logic shared by GhostCat but in a interative way
//2. takes in consideration of multiple cases of A,B,C... in case you load your data from DB
//3. separates raw data from logic, easy to edit later and expand
$data = array(
  'A' => array(
    'variables' => array(
      'x' => array(
        10 => '<'
      ),
      'y' => array(
        2 => '<='
      ),
    ),
    'function' => 'functionA',
  ),
  'B' => array(
    'variables' => array(
      'x' => array(
        50 => '<'
      ),
      'y' => array(
        2 => '>'
      ),
    ),
    'function' => 'functionB',
  ),
  'C' => array(
    'variables' => array(
      'x' => array(
        250 => '<'
      ),
      'y' => array(
        50 => '<='
      ),
    ),
    'function' => 'functionC',
      ),
    );

//
foreach ($data[$product]['variables'] as $variable => $variable_data) {
  foreach ($variable_data as $number => $operator) {
    switch ($operator) {
      case '<':
        if (!($variable < $number)) {
          myFailFunction();
        }
        break;
      case '<=':
        if (!($variable <= $number)) {
          myFailFunction();
        }
        break;
      case '>':
        if (!($variable < $number)) {
          myFailFunction();
        }
        break;
    }
  }
}
//if no fail was met run attached function
$func_name = $data[$product]['function'];
$func_name();
//it should run like this too
//$data[$product]['function']();

Upvotes: 0

GhostCat
GhostCat

Reputation: 140553

The "object oriented" approach here would be to avoid the "tell don't ask" pattern that you implemented.

Meaning: you are "asking" for certain properties; so that your code can make a decision based on that. The solution to that is: don't do it that way!

Instead: you create a "base" product class which offers methods like isXinRange() and isYinRange(). Then you have different sub classes for each product; and AProduct.isXinRange checks x < 10 ...

Meaning: your range checks go into three different classes!

And instead of putting everything into "one" comparison, you do something like:

  1. You create an object of AProduct for "A", BProduct for "B", ... and so on; like someProduct = generateProductFor(stringFromUser)
  2. Then you simply ask if someProduct.isXinRange() gives you true for the X provided by the user

(I am not too familiar with PHP, so sorry for my half-pseudo-half-java coding style here)

Upvotes: 2

Related Questions