h3

【设计模式】一:简单工厂模式

此系列文章为阅读大话设计模式书籍记录的笔记

使用简单工厂模式,利用面向对象的三大特性-【封装】-【继承】-【多态】实现一段计算器代码。下面示例为逐步优化,也可认为是一个初级程序员慢慢优化自己代码的过程。

 

一:面向过程思想的实现形式

<?php
// 按最初的版本写

class jisuanqi
{
    public function jisuan($num1, $num2, $me)
    {
        if (!is_numeric($num1) || !is_numeric($num2)) {
            return 'num must int';
        }

        if (!$me) {
            return 'method must';
        }


        switch ($me) {
            case '+':
                return  $num1 + $num2;
            case '-':
                return $num1 - $num2;
            case '*':
                return $num1 * $num2;
            case '/':
                if ($num2 == 0) {
                    return 'if mentod is / , the num2 must not 0';
                }
                return $num1 / $num2;
            default:
                return 'haha';
        }
    }
}
$j = new jisuanqi();
$res = $j->jisuan(1, 2, '/');
echo $res;

// 此种写法的缺点:不易扩展,没有按业务进行封装,没办法复用

// 改进一步,将两个业务逻辑进行封装,可复用的内容进行提炼, 例如计算器分为输入端和计算端

 

二:使用封装,按照功能模块进行划分,这样较前一种书写形式已经比较好修改代码,寻找功能块了,但是还是很渣

<?php
// 进行方法的封装
class Operation{
    public function getResult(int $num1, int $num2, string $operation)
    {
        $res = 0;
        switch ($operation) {
            case '+':
                $res = $num1 + $num2;
                break;
            case '-':
                $res = $num1 - $num2;
                break;
            case '*':
                $res = $num1 * $num2;
                break;
            case '/':
                if ($num2 == 0) {
                    return 'error';
                }
                $res = $num1 / $num2;
                break;
            default:
                return 'error';
        }
        return $res;
    }

    public function Main($num1, $num2, $operation)
    {
        if (!is_numeric($num1) || !is_numeric($num2)) {
            return 'num must int';
        }

        if (!$operation) {
            return 'method must';
        }
        $res = $this->getResult($num1, $num2, $operation);
        echo $res;
    }
}
$a = new Operation();
$a->Main(1, 2, '/');

// 这仅仅是使用到了面向对象的三个特性,封装,继承,多态中的一个,封装,但是此时耦合度很高,好的程序要做到松耦合,就是修改一个地方,
// 并不会影响到现有的功能,如果此处想增加一个开方根运算,紧耦合中必须得更改源代码,松耦合中,新增新的功能不会影响到旧的,所以使用继承的特性

 

三:上述方法已经使用了封装,但是还是不利于扩展;

  如果产品经理说我需要加计算平法的功能进去,那只能是修改switch的功能块,此处因为逻辑简单,可能认为修改会简单些;

  但是如果每个计算规则中都需要记录用户的输入信息,存入数据库,存入redis, 然后用一次计算器给加个积分,积分到了哪个级别自动发放礼品等等复杂逻辑进去。

  那我心里就会骂这产品瞎改什么需求,当然产品经常改需求很不好,但也有咱们自己的原因,代码写成一大坨,耦合性这么高,找个大牛出来都觉得看的头疼,别说咱们这种渣渣了;

  所以此处我们可以想办法把各个运算规则再拆出来,再封装啊。

  如果使用面向过程的思想,可以将各个规则分别封装成一个方法,然后用的时候调用就可以了,当然这种也能满足上面描述的情况;

  但是如果这些计算规则都具有一定的共性,那么此处使用面向对象的继承更优一些

<?php

// 使用面向对象的继承特性,达到松耦合

// 创建计算器类
class Operation
{
    public $num1 = 0;
    public $num = 0;
    public function __set($name, $value)
    {
        $this->$name = $value;
    }
    public function __get($name)
    {
        return $this->$name;
    }

    public function getResult()
    {
        $res = 0;
        return $res;
    }
}

// 创建加法类
class OperationAdd extends Operation
{
    // 重写getResult方法
    public function getResult()
    {
        $res = 0;
        $res = $this->num1 + $this->num2;
        return $res;
    }
}

// 创建减法类
class OperationSub extends Operation
{
    public function getResult()
    {
        $res = 0;
        $res = $this->num1 - $this->num2;
        return $res;
    }
}

// 创建乘法类
class OperationMul extends Operation
{
    public function getResult()
    {
        $res = 0;
        $res = $this->num1 * $this->num2;
        return $res;
    }
}

// 创建除法类
class OperationDiv extends Operation
{
    public function getResult()
    {
        if ($this->num2 == 0) {
            return 'error';
        }
        $res = 0;
        $res = $this->num1 - $this->num2;
        return $res;
    }
}

$add = new OperationAdd();
$add->num1 = 1;
$add->num2 = 2;
$res = $add->getResult();
echo $res;

// 此时已经利用面向对象的继承特性,将程序的扩展性能体现出来,如果需要新增一个计算平方的方法,只需要再新增一个类,然后继承自基类就好
// 而且并不会影响原有的计算程序, 但是此时存在一个问题,我们需要自己去判断实例化哪个类,那么就需要一个方法去帮我们调度,那此时就可以
// 使用第一个设计模式,简单工厂模式,到时候这个方法负责帮我们调度,我们只需将对应参数给其即可

 

四: 上边使用了,封装,继承,代码已经较为清晰了,如果产品让我加一个计算平方的,那我加上这一个类就好了啊,新加的这个类中只需要写与平方功能有关的代码就行了;

  但是此处是我们手动的去调用计算规则的,这样是具有问题的,那就引申出第一个设计模式,简单工厂模式;

  说白了,就是建一个类,我们只需要按照规则将参数传进去,这个工厂类自动判断实例化哪个类去,我只关心结果。使用简单工厂模式后,封装性更好了,使用者无需关注内部怎么实现的,

  只需要按照指定规则调用就好了,如果想自己扩展,代码结果也很清晰

 

<?php
class Operation
{
    public $num1 = 0;
    public $num = 0;
    public function __set($name, $value)
    {
        $this->$name = $value;
    }
    public function __get($name)
    {
        return $this->$name;
    }

    public function getResult()
    {
        $res = 0;
        return $res;
    }
}

// 创建加法类
class OperationAdd extends Operation
{
    // 重写getResult方法
    public function getResult()
    {
        $res = 0;
        $res = $this->num1 + $this->num2;
        return $res;
    }
}

// 创建减法类
class OperationSub extends Operation
{
    public function getResult()
    {
        $res = 0;
        $res = $this->num1 - $this->num2;
        return $res;
    }
}

// 创建乘法类
class OperationMul extends Operation
{
    public function getResult()
    {
        $res = 0;
        $res = $this->num1 * $this->num2;
        return $res;
    }
}

// 创建除法类
class OperationDiv extends Operation
{
    public function getResult()
    {
        if ($this->num2 == 0) {
            return 'error';
        }
        $res = 0;
        $res = $this->num1 - $this->num2;
        return $res;
    }
}

// 创建一个工厂类,帮助我们调度程序
class OperationFactory
{
    // 参数检测,调度创建工厂
    public function getOperaRes($num1, $num2, $operation)
    {
        if (!is_numeric($num1) || !is_numeric($num2)) {
            return 'num must int';
        }

        if (!$operation) {
            return 'method must';
        }
        // 调用工厂,工厂生成了模型
        $opera = $this->createOperation($operation);
        $opera->num1 = $num1;
        $opera->num2 = $num2;
        $res = $opera->getResult();
        return $res;
    }
    public function createOperation($operation)
    {
        $opera = null;
        // 简单判断参数
        switch ($operation) {
            case '+':
                $opera = new OperationAdd();
                break;
            case '-':
                $opera = new OperationSub();
                break;
            case '*':
                $opera = new OperationMul();
                break;
            case '/':
                $opera = new OperationDiv();
                break;
            default:
                return 'error';
        }
        return $opera;
    }
}

$opera = new OperationFactory();
$res = $opera->getOperaRes(1, 3, '+');
echo $res;

// 此处主要体现简单工厂模式的思想,此类还有很多地方需要完善,当然这只是简单的加减乘除,不用工厂模式更加简单,但是计算规则复杂后就体现出封装
// 的优越性,产品经理需求变动频繁,经常加功能,该功能就体现出了继承导致松耦合的优越性

 

posted @ 2019-03-14 15:13  码上平天下  阅读(183)  评论(0编辑  收藏  举报