«Это 28-й день моего участия в ноябрьском испытании обновлений. Подробную информацию об этом событии см.:Вызов последнего обновления 2021 г."
Я уже составлял статью об отражении оптимизации производительности:Не манипулируйте БД в цикле for, отзыв не плохой, продолжайте пользоваться性能优化
В качестве темы поделитесь недавними краткими мыслями:Уменьшите количество запросов к БД и разумно используйте переменные-члены.
高内聚,低耦合
Это очень популярная дизайнерская идея.Достигая высокой сплоченности и низкой связанности, мы должны также учитывать проблему передачи значений: мы должны избегать необоснованной передачи значений при извлечении функций и инкапсуляции кода, а также избегать нескольких функций.Неоднократно запрашивать одну и ту же базу данных.
взять каштан
Описание требования
-
Наш проект представляет собой приложение для знакомств. В нем есть такие действия, как смахивание карточек «Нравится», «Дизлайк» и «Суперлайк», а также такие действия, как дарение подарков и приглашение на свидание.
-
Существуют различные суждения для вышеуказанных действий, такие как верхний предел лайков каждый день, и является ли он участником или нет; при дарении подарков необходимо судить, активирован ли участник, и использовать ли цену членства при вычете гонораров, при приглашении на свидание необходимо судить, друг ли это и т. д. И т. д. Различные, казалось бы, обыденные сценарии объединяются, чтобы сделать структуру кода невероятно сложной. Программирование стало чрезвычайно важным.
-
Если вам не нужно беспокоиться о том, чтобы смотреть вниз, вы можете сначала подумать о том, как бы вы это реализовали, если бы вас попросили заняться программированием.
...
Подумайте об этом, чтобы лучше понять следующие дизайнерские идеи, или введите свое решение в поле для комментариев.
...
анализ спроса
-
Исходя из вышеперечисленных требований, определим несколько понятий: действие, потребление, запись;
-
Сплит-действия: основные действия, платежные действия, глобальные действия, сплит-потребление: пополнение, потребление, купоны и т. д.;
-
Реализовать логический код в соответствии с концепцией разделения, например, базовое действие абстрагируется в класс, а платежное действие и глобальное действие наследуют этот класс: платежное действие абстрагируется в один класс, а связанное с оплатой действие действия размещаются здесь; глобальное действие относится к независимо от того, является ли оно членом или нет, является ли оно потребителем или нет, действия, которые могут выполняться, также абстрагируются в отдельный класс.
(В первой версии разработки проекта мы не делали такой абстракции. Различные действия, потребление и записи были реализованы в классе. По мере развития проекта он становился очень раздутым и хаотичным.)
Вышеизложенное может быть немного абстрактным, но приведенный ниже пример кода сделает его намного яснее~
пример кода
Чтобы быть компактным и понятным каждому, я не буду вставлять наш логический код напрямую, а вынесу ключевые сегменты кода для анализа.
весь кадр
- Следующий код упоминается выше
全局动作类
, который наследует基础动作类
, все действия в基础动作类
определено в - стандартизированный
输入参数
и输出参数
эти переменные-члены - Метод построения передает текущий идентификатор пользователя и идентификатор контрагента, все действия должны иметь обе стороны
- стандартизированный
setAction()
установить действие,getActionResult()
Получите результат выполнения действия, унифицируйте формат и спецификацию ввода и вывода и следуйте унифицированной спецификации независимо от того, где она вызывается.
class UserUniversalAction extends BaseUserAction
{
//输入参数
protected $_userid; //当前用户ID
protected $_actionId; //动作ID
protected $_extra = []; //动作携带的额外参数
protected $_otherUserid; //对方用户ID
protected $_data = []; //中间存储
protected $_houseOpen = [];
protected $_userConsume = null;
protected $_now;
//输出参数
protected $_pass = true; //财务性约束,有没有消费通过
protected $_rechargeType = null; //消费的类型
protected $_propCount = 0;
protected $_consumeSuccess = false; //消费成功-默认false
protected $_canInvite = false; //
protected $_errorCode = 0; //非财务行约束,动作的关系执行条件
protected $_needAfterAction = true;
//protected $_out = []; //动作执行完成后,输出结果
public $hasRight = false;
public function __construct($userid, $otherUserid = '')
{
parent::__construct($userid, 0);
$this->_otherUserid = $otherUserid;
//初始化参数
$this->_houseOpen = HouseOpen::getCurrentOpen();
//消费初始化
$this->_userConsume = new UserConsume($this->_userid);
$this->_now = time();
}
//设置执行动作
public function setAction($actionId, $extra = [])
{
//设置动作参数
$this->_actionId = $actionId;
$this->_extra = $extra;
//前置动作,执行权限校验等
$this->_beforeAction();
//只有非财务性约束和财务性约束通过后,才能继续执行
if ($this->_errorCode == 0 && $this->_pass) {
//执行动作
$this->_actionExecute();
if ($this->_errorCode == 0) {
//后置动作
$this->_afterAction();
}
}
}
//获取动作执行结果
public function getActionResult()
{
return [
//财务性限制
'pass' => $this->_pass,
'rechargeType' => $this->_rechargeType,
'propCount' => $this->_propCount,
'canInvite' => $this->_canInvite,
//业务性限制
'errorCode' => $this->_errorCode,
'out' => $this->_data
];
}
Подробное объяснение настройки действий выполнения
Внимательные одноклассники, возможно, обнаружили: мы снова правыsetAction()
После дальнейшей разборки он делится на:
_beforeAction
: предварительное действие, проверка разрешения на выполнение и т. д. Например, только когда участник открыт, разрешено суперлайк, и только когда вы становитесь другом, вам разрешено пригласить свидание.
_actionExecute
: выполнить действие, например поставить суперлайк, например отправить собеседнику приглашение на свидание.
_afterAction
: Публикация действия, например отправка сообщения панели уведомлений другой стороне при начале встречи; например, отправка push-сообщения, чтобы проинформировать другую сторону об опыте знакомства после завершения встречи.
Преимущество этого в том, чтоисключительно ясно, почти все действия можно понимать как три шага: до действия, во время действия и после действия.
Еще одно хардкорное место — это второй параметр, передаваемый в$extra = []
:
Первый переданный параметр легко понять:$actionId
Это идентификатор действия, который мы определили, и мы судим, какие действия выполнять в соответствии с идентификатором действия.
второй параметр$extra = []
, extra — это концепция расширенных параметров и переменных параметров. как я упоминал в началеУменьшите количество запросов к БД и разумно используйте переменные-членыЭто перекликается:
Параметры, которые необходимо использовать в нескольких местах, передаются, а не получаются каждый раз путем запроса к БД. Данные, которые мы передаем в качестве параметров, могут быть назначены переменным-членам.
//设置执行动作
public function setAction($actionId, $extra = [])
{
//设置动作参数
$this->_actionId = $actionId;
$this->_extra = $extra;
//前置动作,执行权限校验等
$this->_beforeAction();
//只有非财务性约束和财务性约束通过后,才能继续执行
if ($this->_errorCode == 0 && $this->_pass) {
//执行动作
$this->_actionExecute();
if ($this->_errorCode == 0) {
//后置动作
$this->_afterAction();
}
}
}
Хардкорная часть, обратите внимание
Дружеское напоминание Сяо Укуна:文章有点长,硬核部分开始了,请同学们坚持一会,认真看。
Следующий пример кода поможет вам лучше понять如何合理的使用成员变量
Старые правила сначала говорят о спросе: сделайте вывод в конце встречи, если время голосовой онлайн-встречи составляет менее 1 минуты, пользователь получит компенсацию за ваучер на встречу (мы думаем, что время встречи меньше, чем 1 минута). 1 минута, это плохой опыт, и пользователи не могут тратить деньги зря, чтобы дать купонную компенсацию)
Если это обычный дизайн: нам нужно запросить БД не менее 3 раз, а именно:
- Когда инициируется завершение встречи, состояние изменяется, выполняется серия операций чтения и записи, и последнее состояние данных возвращается клиенту.
- существует
_afterAppointmentFinish
Запросите, открыта ли голосовая комната (наш продукт имеет бизнес-концепцию, только в бизнесе может выполнять действия по назначению) - существует
_afterAppointmentFinish
В соответствии с идентификатором даты запросите дату и другую информацию обеих сторон.
Передавая параметры через переменные-члены, вам нужно только один раз запросить БД, то есть:
- Когда инициируется завершение встречи, состояние изменяется, выполняется ряд операций, и клиенту возвращается последнее состояние данных.
$this->_data = $appointmentModel->toArray();
присвоить переменной-члену;_afterAppointmentFinish()
прошедший$this->_data
Просто возьмите значение.
protected function _actionExecute()
{
//执行权限校验
switch ($this->_actionId) {
.
.
.
case self::TYPE_ACTION_END:
$this->_doAppointmentEndActionExecute();
break;
}
}
protected function _afterAction()
{
//动作后置操作
switch ($this->_actionId) {
.
.
.
case self::TYPE_ACTION_END:
$this->_afterAppointmentFinish();
break;
default:
}
}
protected function _doAppointmentEndActionExecute()
{
$appointmentModel = AppointmentInfo::query()->selectRaw('id,userid,"inviteeUserid",status,endtime,"callStartTimestamp","callDuration","isConsume","appointmentOpenId"')
->where('id', $this->_extra['appointmentId'])->first();
.
.
.
$appointmentModel->endtime = time();
$appointmentModel->status = AppointmentInfo::TYPE_STATUS_END;
$appointmentModel->save();
$this->_data = $appointmentModel->toArray();
.
.
.
}
protected function _afterAppointmentFinish()
{
$houseOpen = $this->_houseOpen; //减少1次DB查询
if ($houseOpen['status'] != HouseOpen::HOUSE_STATUS_OPEN) {
return false;
}
//减少2次DB查询
if (isset($this->_data)
&& $this->_data['isConsume'] == AppointmentInfo::TYPE_IS_CONSUME
&& $this->_data['appointmentOpenId'] == $houseOpen['currentAppointmentOpenId']
&& $this->_data['callDuration'] < 60) { //约会时长不足1分钟,花了多少补偿多少精酿券
.
.
.
}
}
}
Вышеупомянутое просто каштан.По мере развития проекта количество сценариев применения увеличивается.Разумное использование переменных-членовбудет отражать более высокое значение.
обзор
Давайте рассмотрим входные параметры, которые я упомянул в начале, этоПеременные-члены,в_extra ,_data ,_houseOpen
Все они представляют собой массивы, которые легко расширить.Мы можем разумно использовать переменные-члены, чтобы уменьшить избыточные запросы к БД и повысить эффективность работы программы.
//输入参数
protected $_userid; //当前用户ID
protected $_actionId; //动作ID
protected $_extra = []; //动作携带的额外参数
protected $_otherUserid; //对方用户ID
protected $_data = []; //中间存储
protected $_houseOpen = [];
protected $_userConsume = null;
protected $_now;
Суммировать
Вы должны знать, что каждый запрос к БД занимает много времени в сети; мы храним данные в переменных-членах, а время, затрачиваемое на чтение данных из памяти, незначительно.
Добро пожаловать на взаимодействие
Время летит так быстро, сегодня 29-е, и сегодня я наконец-то завершил 28-дневное испытание обновления этого месяца.
Надеюсь, что в будущем я напишу больше таких статей, как сегодня. Эта заключительная статья относительно хардкорная, по крайней мере, в ней нет воды, и ее можно рассматривать как идеальное завершение задачи ноябрьского обновления.
Спасибо за поддержку! ! ! Добро пожаловать в три волны подряд~
Рекомендация хардкорной статьи
Резюме PHP to Go в середине 2021 года
Отражение оптимизации производительности: не используйте БД в цикле for
Отражение оптимизации производительности: не используйте расширенную версию БД в цикле for
Наконец
👍🏻: Если вы чувствуете, что что-то приобрели, пожалуйста, поставьте лайк, чтобы поощрить это!
🌟: Любимые статьи для удобного просмотра!
💬: Обменивайтесь комментариями и развивайтесь друг с другом!