美文网首页
结合享元模式架构service层(PHP)

结合享元模式架构service层(PHP)

作者: 半打真心 | 来源:发表于2019-12-13 12:07 被阅读0次
    公祭日

        service层的调用方式一般就是实例化引用或者直接使用静态类。后者似乎实现了绝对分离,前者又有过度耦合的嫌疑。

        从语义上来说service层之间是有关联的,比如一般的serivce只关注数据库数据的处理,因此这类service应该继承同一个基类。但在调用方式上要低耦合,应该要怎么做,我们先来讨论一下方案

    1、使用依赖注入。这在类如laravel框架上很好实施,但其实有进一步解耦的空间,而且如果一个方法依赖很多的服务,就要注入很多的实例,这看起来很丑陋。
    2、直接使用静态类。但是这有一个致命缺陷,因为我们已经把service层继承了同一个基类,这时候使用多个service时就会失效。
    3、结合以上两种方案我想到的模式就是“享元模式”。这也是我们选择的方案具体操作将在下文给出。

        确定了方案后就开始实施。

    1、建立基类

    <?php
    namespace App\Http\Controllers;
    
    class Service{
        public static $instance   = [];   # 实例享元池
        public static $reflection = []; # 反射信息
    
        /**
         * 构造查询数组
         * @param array $need_map
         * @param array $init_condition
         * @param $condition
         * @return array
         */
        public static function condition(array $need_map, array $init_condition, &$condition){
            if(!is_array($condition)) $condition = [];
    
            // construct
            foreach($need_map as $need){
                if(isset($init_condition[ $need[0] ])){
                    if(isset($need[2]) && is_callable($need[2]))
                        $init_condition[ $need[0] ] = $need[2]($init_condition[ $need[0] ]);
                    $condition[] = [$need[0], $need[1], $init_condition[ $need[0] ]];
                }
            }
    
            return $condition;
        }
    
        /**
         * 支持静态访问
         * @param $name
         * @param $arguments
         * @return mixed
         * @throws \Exception
         */
        public static function __callStatic($name, $arguments){
            // judge pass
            self::judgePrivate($name);
    
            // judge reply controller
    //        self::judgeReplyController();
    
            // action
            $key = get_called_class();
            if(!isset(self::$instance[$key])) self::$instance[$key] = new static();
            return call_user_func([self::$instance[$key], $name], ...$arguments);
        }
    
        /**
         * 通过反射截止私有方法访问
         * @param $name
         * @throws \Exception
         */
        private static function judgePrivate($name){
            // judge pass
            try{
                $key = get_called_class();
                if(!isset(self::$reflection[$key])) self::$reflection[$key] = new \ReflectionClass($key);
                $method = self::$reflection[$key]->getMethod($name);
                if($method->isPrivate())
                    throw new \Exception('Method cannot be accessed!');
            }catch (\ReflectionException $e){
                throw new \Exception($e->getMessage());
            }
        }
    
        /**
         * service 与 controller 匹配判断
         * @throws \Exception
         */
        private static function judgeReplyController(){
            $reply_list = debug_backtrace();
            $service    = explode('\\', get_called_class());
            $service    = rtrim(end($service), 'Service');
            $class      = '';
            foreach($reply_list as $reply){
                $class_unit = explode('\\', $reply['class']);
                $class_unit = end($class_unit);
                if(preg_match('/^[A-Za-z]+Controller$/', $class_unit)){
                    $class = rtrim($class_unit, 'Controller');
                    break;
                }
            }
    
            if($service != $class)
                throw new \Exception('Service does not match controller!');
        }
    }
    

    基类实现了享元模式,通过get_called_class()获取具体要调用的service类名,以类名为健名储存一个单例数组也就是享元池。使用__callStatic统一调度实例方法,使用反射获取类信息。

    2、service类

    我们在建立具体的服务类的时候只使用两种访问级别private和protected。protected是提供控制器使用的方法,private是私有使用。

    <?php
    namespace App\Http\Controllers\Services;
    
    use App\Http\Controllers\Service;
    use Illuminate\Support\Facades\DB;
    
    class TypeOrderService extends Service{
        /**
         * 统计房间列表所有费用
         * @param $id_list
         * @return array
         */
        protected function countList(array $id_list){
            //
        }
    }
    

    这套方案已在实际项目中实施,可以保证其稳定性,调用也很方便,跟使用静态类的方式是一样的。

    相关文章

      网友评论

          本文标题:结合享元模式架构service层(PHP)

          本文链接:https://www.haomeiwen.com/subject/nykfnctx.html