因为阅读yii2源码过程中,不理解其设计模式(导致阅读起来比较吃力),介绍其其中用到的一个设计模式:模块方法模式.
模块方法模式概念:
定义一个操作中的算法的骨架,而将一些步骤延迟到子类中。模板方法使得子类可以不改变一个算法的结构即可重定义该算法的某些特定步骤(引用:菜鸟教程)。在学习过程中设计一个业务处理逻辑模块。
目录结构:
/index.php demo文件
/autoload.php 类加载文件
/sour/AbstractService.php 抽象业务逻辑处理类
/sour/ServiceGo.php 具体业务逻辑处理实现类
index.php
<?php
namespace design;
use \design\sour\ServiceGoShop;
require 'autoload.php';
spl_autoload_register('auto_loader');
/**
* 利用模块方法模式,实现一个业务逻辑模块的格式化
*/
$action = new ServiceGo(); //创建一个Go业务服务
//去旅行
$result = $action->run('travel', [
'where' => '蓝天之上',
'money' => 100
]);
echo json_encode($result, JSON_UNESCAPED_UNICODE).'<br>';
//去购物
$result = $action->run('goShop', [
'money' => 100
]);
echo json_encode($result, JSON_UNESCAPED_UNICODE).'<br>';
autoload.php
<?php
defined('PATH') or define('PATH', __DIR__);
function auto_loader($class)
{
$path = str_replace(
'\\',
DIRECTORY_SEPARATOR,
substr($class, strpos($class, '\\', 1)+1)
);
if(file_exists(PATH.DIRECTORY_SEPARATOR.$path.'.php')) {
require PATH.DIRECTORY_SEPARATOR.$path.'.php';
} else {
throw new Exception(sprintf('not found `%s`', $class));
}
return class_exists($class);
}
/sour/AbstractService.php
<?php
namespace design\sour;
use \Exception;
define('RESULT_CODE', 0);
define('RESULT_MSG', 'success');
define('RESULT_DATA', []);
define('PARAMS', []);
abstract class AbstractService
{
protected $code = RESULT_CODE;
protected $msg = RESULT_MSG;
protected $data = RESULT_DATA;
public $params = [];
public abstract function process($method);
public abstract function getPrefix();
/**
* 通过__get方法, 获取具体的服务动作需要的参数
* @param $name
* @return mixed
*/
public function __get($name)
{
if(isset($this->params[$name])) {
return $this->params[$name];
} else {
throw new Exception('not found parameter `%s`', $name);
}
}
/**
* 通过__set方法缓存具体的服务动作访问到的参数
* @param $name
* @param $value
*/
public function __set($name, $value)
{
$this->params[$name] = $value;
}
/**
* 业务开始之前的业务属性初始化
*/
private function init()
{
$this->params = PARAMS;
$this->code = RESULT_CODE;
$this->msg = RESULT_MSG;
$this->data = RESULT_DATA;
}
/**
* 初始化方法传参
* @param $args
*/
private function initParams($args)
{
foreach ($args as $name => $value) {
$this->{$name} = $value;
}
}
/**
* 统一业务返回参数
* @return array
*/
private function ret()
{
return [
'code' => $this->code,
'msg' => $this->msg,
'data' => $this->data
];
}
/**
* 业务逻辑入口,
* @param $method 所调用的业务类方法
* @param $args 业务类所用传参
* @return array
*/
public function run($method, $args)
{
$this->init();
$this->initParams($args);
$this->process($method);
return $this->ret();
}
/**
* 格式化方法名称
* @param $method
* @return string
*/
public function normalizeMethod($method)
{
return $this->getPrefix().ucwords($method);
}
}
/sour/ServiceGo.php
<?php
namespace design\sour;
use \Exception;
class ServiceGo extends AbstractService
{
/**
* 具体的业务代码(去旅行)
*/
public function goTravel()
{
do {
if(bccomp($this->money, '0', 2) <= 0) {
$this->code = 10001;
$this->msg = '没有钱';
break;
}
if(!$this->where) {
$this->code = 10002;
$this->msg = '不知道去哪儿';
break;
}
$this->data = [
'where' => $this->where,
'money' => $this->money
];
} while(false);
}
/**
* 具体的业务代码(购物)
*/
public function goGoShop()
{
do {
if(bccomp($this->money, '0', 2) <= 0) {
$this->code = 10001;
$this->msg = '没有钱';
break;
}
$this->data = [
'buy' => [
'vegetables' => [
'胡罗卜',
'白菜'
],
'fruit' => [
'葡萄',
'香蕉',
'哈密瓜'
]
]
];
} while(false);
}
/**
* 返回方法的前缀
* @return string
*/
public function getPrefix()
{
return 'go';
}
/**
* 服务类过程处理
* @param $method
* @throws Exception
*/
public function process($method)
{
$normalizeMethod = $this->normalizeMethod($method);
if(!method_exists($this, $normalizeMethod)) {
throw new Exception(sprintf('class `%s` not found method `%s`', get_class($this), $method));
}
$this->{$normalizeMethod}();
}
}
呵呵~