8

我创建了一个名为 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>";
4

6 回答 6

8

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

这是我的想法。

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

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

此解决方案允许您的代码成为第三方库

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

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

更容易阅读

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

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

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

于 2013-04-17T12:44:17.873 回答
2

I don't think a plain calculator is a good example for OOP. An object needs both a set of methods and a set of variables that represent its state, and can be used to differentiate instances of the object. I would suggest trying to make "moody" calculators. A calculator with a happy mood will add 2 to each result, and an angry calculator will subtract 2 from each result.

于 2013-04-17T12:42:16.523 回答
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();  
于 2013-04-17T13:42:55.593 回答
1

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

如下所示:

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

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

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

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

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

于 2013-04-17T12:32:37.137 回答
0

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

$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
于 2013-04-17T12:32:07.300 回答
0

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

 <?

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

于 2013-04-17T13:04:18.680 回答