【问题标题】:A simpler way to write the calculator class in OOP PHP用 OOP PHP 编写计算器类的更简单方法
【发布时间】:2013-04-17 12:21:35
【问题描述】:

我创建了一个名为 Calculator 的类,其中包含加、减、乘和除函数。计算器仅限于将两个数字相加并返回结果。 我对 OOP 比较陌生,想在课堂上获得一些意见,我是否走很长的路,如果我这样做了,是否有另一种简化课堂的方法。

代码如下:

class Calculator {
    private $_val1 , $_val2;

    public function __construct($val1, $val2){
        $this->_val1 = $val1;
        $this->_val2 = $val2;
    }

    public function add(){
        return $this->_val1 + $this->_val2;
    }

    public function subtract(){
        return $this->_val1 - $this->_val2;
    }

    public function multiply (){
        return $this->_val1 * $this->_val2;
    }

    public function divide () {
        return $this->_val1 / $this->_val2;
    }
}

$calc = new Calculator(3,4);
echo "<p>3 + 4 = ".$calc->add(). "</p>";

$calc = new Calculator (15,12);
echo "<p>15 - 12 = ".$calc->subtract(). "</p>";

$calc = new Calculator (20,2);
echo "<p> 20 * 2 = ".$calc->multiply(). "</p>";

$calc = new Calculator (20,2);
echo "<p> 20 / 2 = ".$calc ->divide(). "</p>";

【问题讨论】:

  • 请花一点时间正确对齐代码。乱七八糟的代码几乎看不懂。
  • 为您对齐。 :-)
  • 啊抱歉,我猜我们是并行编辑的 :)

标签: php oop


【解决方案1】:

恕我直言,你应该使用多态性。
This Video 可以帮助你理解这个原理

这是我的想法。

首先,为您需要的任何操作定义一个接口

interface OperationInterface
{
    public function evaluate(array $operands = array());
}

然后,创建计算器支架

class Calculator
{
    protected $operands = array();

    public function setOperands(array $operands = array())
    {
        $this->operands = $operands;
    }

    public function addOperand($operand)
    {
        $this->operands[] = $operand;
    }

    /**
     * You need any operation that implement the given interface
     */
    public function setOperation(OperationInterface $operation)
    {
        $this->operation = $operation;
    }

    public function process()
    {
        return $this->operation->evaluate($this->operands);
    }
}

然后你可以定义一个操作,例如加法

class Addition implements OperationInterface
{
    public function evaluate(array $operands = array())
    {
        return array_sum($operands);
    }
}

你会像这样使用它:

$calculator = new Calculator;
$calculator->setOperands(array(4,2));
$calculator->setOperation(new Addition);

echo $calculator->process(); // 6

至此,如果您想添加任何新行为或修改现有行为,只需创建或编辑一个类。

例如,假设您想要模数运算

class Modulus implements OperationInterface
{
    public function evaluate(array $operands = array())
    {
        $equals = array_shift($operands);

        foreach ($operands as $value) {
            $equals = $equals % $value;
        }

        return $equals;
    }
}

那么,

$calculator = new Calculator;
$calculator->setOperands(array(4,2));
$calculator->setOperation(new Addition); // 4 + 2

echo $calculator->process(); // 6

$calculator->setOperation(new Modulus); // 4 % 2

echo $calculator->process(); // 0

$calculator->setOperands(array(55, 10)); // 55 % 10

echo $calculator->process(); // 5

这个方案可以让你的代码成为第三方库

如果您打算重复使用此代码或将其作为库提供,用户无论如何都不会修改您的源代码
但是如果他想要一个未定义的SubstractionBackwardSubstraction 方法怎么办?

他只需要在他的项目中创建自己的Substraction 类,该类实现OperationInterface 以便与您的库一起使用。

更容易阅读

在查看项目架构时,更容易看到这样的文件夹

- app/
    - lib/
        - Calculator/
            - Operation/
                - Addition.php
                - Modulus.php
                - Substraction.php
            - OperationInterface.php
            - Calculator.php

并立即知道哪个文件包含所需的行为。

【讨论】:

  • 不妨加入一些链接功能,让echo $calculator-&gt;setOperands(array(4,2))-&gt;setOperation(new Addition)-&gt;process(); 成为可能?
  • 只需在 setOperandssetOperation 方法上添加 return $this;
  • 我喜欢 stackoverflow。
【解决方案2】:

我认为普通计算器不是 OOP 的好例子。一个对象需要一组方法和一组表示其状态的变量,并且可以用来区分对象的实例。我建议尝试制作“喜怒无常”的计算器。心情愉快的计算器会为每个结果加 2,而愤怒的计算器会从每个结果中减去 2。

【讨论】:

    【解决方案3】:

    我会做这样的事情

    interface Evaluable {
        public function evaluate();
    }
    
    class Value implements Evaluable {
        private $value;
    
        public function __construct($value) {
            $this->value = $value;
        }
    
        public function evaluate() {
            return $this->value();
        }
    }
    
    class Node implements Evaluable {
        protected $left;
        protected $right;
    
        public function __construct(Evaluable $left, Evaluable $right) {
            $this->left = $left;
            $this->right = $right;
        }
    }
    
    class SumNode extends Node {
        public function evaluate() {
            return $this->left->evaluate() + $this->right->evaluate();
        }
    }
    
    $op = new SumNode(new Value(2), new Value(3));
    $result = $op->evaluate();
    

    这样您可以轻松添加新操作

    class SubNode extends Node {
        public function evaluate() {
            return $this->left->evaluate() - $this->right->evaluate();
        }
    }
    

    还有这样的连锁操作

    $sum1 = new SumNode(new Value(5), new Value(3));
    $sum2 = new SumNode(new Value(1), new Value(2));
    $op = new SubNode($sum1, $sum2);
    $result = $op->evaluate();  
    

    【讨论】:

    • 我的回答和 Touki 的类似。我们都看过 Misko 的精彩视频:p
    • 你真的检查过脚本吗?乍一看,您缺少两个东西:Class Node 没有实现evaluate() 方法,Class Value 没有方法value(),只有一个属性value。但除此之外,获得模式的想法是件好事! (Y)
    • 糟糕,我刚刚想到,在 PHP >=5.4 上,您可以在类扩展中实现“接口”方法...
    【解决方案4】:

    一般来说,我们不会在这类类中固定值。 您的方法应该通过参数获取它们的 2 个值,而不是选择私有成员。

    如下:

    public function add($v1, $v2)
    {
        return $v1 + $v2;
    }
    

    因此,计算器成为一种工具,我们不应该需要分配这种对象。 这就是计算器方法应该是静态的原因。

    public static function add($v1, $v2)
    {
        return $v1 + $v2;
    }
    

    这样,您只需拨打Calculator::add(1, 2)即可。 你可以在任何地方找到这样的课程。像向量、数学或 3D 中的矩阵。或者写入输出或类似的东西。

    请记住,这是一种做到这一点的方法,既不是最好的也不是最差的。

    【讨论】:

    【解决方案5】:

    你可能最终应该做类似的事情

    $calc = new Calculator();
    $calc->sum($x, $y, $z);
    $calc->substract($x, $y);
    ....
    

    看看这个例子。你可以使用 func_num_args() 给出任意数量的参数

    <?php
    function foo()
    {
    $numargs = func_num_args();
    echo "Number of arguments: $numargs\n";
    }
    
    foo(1, 2, 3);   
    ?>
    // output: Number of arguments: 3
    

    【讨论】:

      【解决方案6】:

      这个任务有很多解决方案,这里是其中之一:

       <?
      
      class Calculator
      {
      
          /**
           * @var float
           */
          /**
           * @var float
           */
          private $_val1,
              $_val2;
      
          /**
           * @var int
           */
          private static $_result = 0;
      
          /**
           * @param $val1
           * @param $val2
           */
          public function __construct($val1 = '', $val2 = '')
          {
              if ((!empty($val1) && !empty($val2)) && (!is_numeric($val1) && !is_numeric($val2))) {
                  $this->_val1 = (float)$val1;
                  $this->_val2 = (float)$val2;
              }
          }
      
          /**
           * @param $val1
           */
          public function setVal1($val1)
          {
              $this->_val1 = (float)$val1;
          }
      
          /**
           * @param $val2
           */
          public function setVal2($val2)
          {
              $this->_val2 = (float)$val2;
          }
      
          /**
           * @param string $operator
           *
           * @return float|int|string
           */
          public function getResult($operator = '')
          {
              if (is_numeric($this->_val1) && is_numeric($this->_val2)) {
                  switch ($operator) {
                      case '+':
                          self::$_result = $this->_val1 + $this->_val2;
                          break;
                      case '-':
                          self::$_result = $this->_val1 - $this->_val2;
                          break;
                      case '*':
                          self::$_result = $this->_val1 * $this->_val2;
                          break;
                      case '/':
                          self::$_result = $this->_val1 / $this->_val2;
                          break;
                  }
              } else {
                  echo 'Alert alert alert)) some of operands not set or not number';
              }
              return self::$_result;
          }
      }
      

      这是一个很好的解决方案https://gist.github.com/cangelis/1442951

      【讨论】:

      • 我肯定会在开关中添加一个默认情况(有一个例外),以防止出现拼写错误和未知操作数。此外,您应该抛出异常而不是回显。如果没有例外,代码将返回未定义的结果,从而导致 PHP 错误消息和/或奇怪的行为。除此之外,请参阅我的其他评论以获取有关 chandresh_cool 的建议。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2014-02-22
      • 1970-01-01
      • 2012-10-20
      • 2013-12-16
      • 2017-04-14
      • 1970-01-01
      • 2022-08-23
      相关资源
      最近更新 更多