用OOP PHP编写计算器类的一种更简单的方法


A simpler way to write the calculator class in OOP PHP

我创建了一个名为Calculator的类,具有加、减、乘、除功能。计算器只能将两个数字相加并返回结果。我是相对较新的面向对象,想在类上得到一些输入,我是否采取了漫长的路线,如果我这样做,是否有另一种方法来简化类。

代码如下:

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>";

IMHO,您应该使用多态性。
这个视频可以帮助你理解这个原理

这是我的思考方式。

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

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

然后创建calculator holder

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

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

我不认为一个普通的计算器是一个很好的面向对象的例子。一个对象既需要一组方法,也需要一组变量来表示它的状态,并且可以用来区分对象的实例。我建议尝试制作"喜怒无常"的计算器。心情愉快的计算器会在每个结果上加2,生气的计算器会在每个结果上减2。

我会这样做

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();  

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

像下面这样:

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

因此,Calculator变成了一个工具,我们不需要分配这类对象。这就是为什么Calculators的方法应该是static

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

这样,你只需要调用Calculator::add(1, 2)。这类课程随处可见。比如数学中的矢量、矩阵或3D。或写入输出或类似的内容

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

你最终应该做一些像

$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

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

 <?
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

相关文章: