zoukankan      html  css  js  c++  java
  • 【设计模式】一:简单工厂模式

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

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

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

    <?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;
    
    // 此处主要体现简单工厂模式的思想,此类还有很多地方需要完善,当然这只是简单的加减乘除,不用工厂模式更加简单,但是计算规则复杂后就体现出封装
    // 的优越性,产品经理需求变动频繁,经常加功能,该功能就体现出了继承导致松耦合的优越性
  • 相关阅读:
    NOIP2006代码及简析
    设计模式的原则
    UML应用
    关系
    活动图
    状态图
    UML概序
    UML基本图示
    用例
    介绍一个好的英语学习网站!
  • 原文地址:https://www.cnblogs.com/rcltocode/p/10530443.html
Copyright © 2011-2022 走看看