大模型量化技术解析和应用

本文涉及的产品
全局流量管理 GTM,标准版 1个月
云解析 DNS,旗舰版 1个月
公共DNS(含HTTPDNS解析),每月1000万次HTTP解析
简介: 眼看人工智能含智能量越来越高含人量越来越低,是否开始担心自己要跟不上这趟高速列车了?内心是否也充满好奇:大模型背后的奥秘是什么?为何如此强大?它能为我所用吗?哪种技术最适合我的需求?

本文为魔搭社区大模型技术理论&实践学习笔记系列,并收录至 modelscope-classroom和魔搭社区研习社,更多LLM学习资料欢迎收藏关注~

modelscope-classroom:

https://github.com/modelscope/modelscope-classroom/blob/main/LLM-tutorial/%E9%87%8F%E5%8C%96%E6%8A%80%E6%9C%AF%E8%A7%A3%E6%9E%90.md

魔搭研习社:

https://www.modelscope.cn/learn/399?pid=339

背景

眼看人工智能含智能量越来越高含人量越来越低,是否开始担心自己要跟不上这趟高速列车了?内心是否也充满好奇:大模型背后的奥秘是什么?为何如此强大?它能为我所用吗?哪种技术最适合我的需求?

同志,找对组织了!小狸愈正联合魔搭社区面向希望入门学习LLM理论和应用的小伙伴们持续输出一些主题性的学习资料,一起day day up!

今天主要讲量化,也就是低显存跑超大大大模型的原理(注意,此处不是股票量化嗷 )。

已有系列教程的

  • 大模型是什么?

https://github.com/modelscope/modelscope-classroom/blob/main/LLM-tutorial/A.%E6%B7%B1%E5%BA%A6%E5%AD%A6%E4%B9%A0%E5%85%A5%E9%97%A8%E4%BB%8B%E7%BB%8D.md

  • transformers结构是什么?

https://github.com/modelscope/modelscope-classroom/blob/main/LLM-tutorial/D.Transformer%E7%BB%93%E6%9E%84.md

  • 什么是模型训练和推理?

https://github.com/modelscope/modelscope-classroom/blob/main/LLM-tutorial/H.%E8%AE%AD%E7%BB%83.md

  • 和本篇关系最大的,模型量化基础:

https://github.com/modelscope/modelscope-classroom/blob/main/LLM-tutorial/G.%E9%87%8F%E5%8C%96.md

  • LISA微调技术解析:

LISA微调技术解析:比LoRA更低的显存更快的速度

量化的定义和基本原理

建议直接查看以上文档中的模型量化基础篇章。不过在这里,先把模型量化的定义重新嚼一遍:

量化是将模型浮点数变为定点数运行的过程

image.png

浮点数计算机存储方式示意图

image.png

量化过程示意图

简单理解,就是将用小数计算结果的模型,转换成用整数计算,中间自然有精度损失(因为小数位没了,而且浮点数翻译成整形再转回来是有损压缩过程)。

使用这个定义,结合以上文档中的模型量化基础,侧重以下几个方面进行技术分析:

  • BnB/HQQ/AWQ/GPTQ等几种量化方法的原理
  • 以上几种量化方法如何使用

原理篇

本篇可能会涉及到较多公式,对理论不感兴趣的小伙伴可以直接跳过看下面的结论以及使用篇章。

BnB量化

BnB全称是BitsAndBytes,是几乎最早集成到transformers框架中的量化算法。

论文地址:

LLM.int8():

https://arxiv.org/pdf/2208.07339

QLoRA:

https://arxiv.org/abs/2305.14314

我们回顾一下量化的基本思路:

  1. 按照整数位数,定义最大值和最小值
  2. 按照浮点数和整数的范围比例,对浮点数进行缩放
  3. 在forward时,将hidden_states按1-2步骤进行缩放,或者将weights反量化为浮点数进行计算

image.png

absmax量化

bitsandbytes.LLM.int8()算法也是基于上面的思路的,特殊之处在于,在分析weights矩阵的稀疏性质后,总结了下面的特性:

  1. 模型weights和hidden_states中存在离群值,比例不到1%
  2. 离群值比例虽然低,但是对量化造成了性能恶化

针对离群值的量化算法其实有很多方式,比如分段量化,BnB采用了针对离群值保持低精度浮点数的做法:

  1. 从输入的隐藏状态中,按列提取离群值
  2. 对离群值以低精度浮点型进行矩阵乘法,对非离群值以int8进行矩阵乘法
  3. 对非离群值的结果反量化,将两部分加起来得到最终结果

image.png

离群值/非离群值量化

在实际实验中,BnB算法发现以6为尺度分割出离群值是最佳的。

在transformers中使用BnB算法比较简单:

from transformers import BitsAndBytesConfig, AutoModelForCausalLM
bnb_config = BitsAndBytesConfig(
   load_in_8bit=True,
)
model = AutoModelForCausalLM.from_pretrained(some-model-id, quantization_config=bnb_config)

由于BnB量化不需要任何校准数据集,因此其量化速度很快,这也是为什么在QLoRA训练时,会直接传入BitsAndBytesConfig直接对原始模型量化后训练。

而在QLoRA论文中,作者介绍了4bit量化、双重量化和分页optimizer的技术方案。

image.png

4bit量化 支持两种数据类型:fp4和nf4。fp4是四bit浮点数,包含一位符号位,两位整数位和一位小数位。nf4全称是4-bit NormalFloat,和fp4类似,但是其数值分布并不均匀,呈现正态分布。这是因为一般LLM的矩阵参数概率密度也是呈现正态分布的。在4bit量化中,也更推荐使用nf4数据类型,因为可以比较好的契合参数特性。

nf4的量化思路可以理解为:一般模型weights是均值为0,标准差为σ的的分布,因此该分布可以转换为标准高斯分布。这样可以从标准高斯分布中取样一定分位数的量化间隔并设定量化值(该值采用两边分位数的均值),并且正则化到[-1, 1]区间中。后续就可以将模型weights通过absmax量化到该区间中。

双重量化 指的是针对量化常数的二次量化。由于BnB的量化是块量化(block-wise),因此块级别的常数存储也会占用GPU memory。对此,在一次量化后针对此类常数进行二次量化,进一步压缩显存空间。

image.png

image.png

optimizer分页 可以同比理解为CPU的分页内存概念,防止在长文本时出现的显存爆炸。

下面我们放一点代码帮助理解。

在transformers.intergrations.bitsandbytes.py中:

image.png

这里是替换Linear和Conv算子为bnb的起始点。

bitsandbytes.nn.modules.py:

image.png

双重量化。可以看到在weights迁移到cuda的时机进行量化。

image.png

继续到C代码bitsandbytes.csrc.kernels.cu:

image.png

可以看到针对离群点进行了阈值判断并有选择地量化。如果大于离群阈值则直接置0。

4bit量化:

image.png

可以看到量化后针对偶数index的参数左移四位,和相邻参数构成了一个完整的byte。

使用QLoRA进行训练请参考下个章节。

GPTQ量化

说到GPTQ,就要说起它的老祖先OBD、OBS、OBC等剪枝算法(否则无法理解GPTQ)。本质上来说,参数剪枝是参数量化的一种特殊情况(把参数直接置为0这个特殊量化值)。

先说OBD

论文:

https://citeseerx.ist.psu.edu/document?repid=rep1&type=pdf&doi=17c0a7de3c17d31f79589d245852b57d083d386e

image.png

loss的泰勒级数展开

假设模型已经在训练集上训练至收敛,则可以假设E在U点处的一阶导为0。在忽略高阶无穷小分量后,上式仅剩余二阶梯度部分。如果对海森矩阵进行对角近似,则上式在优化后仅剩余下面的部分:

image.png

Hessian矩阵部分

由于训练收敛,则海森矩阵是正定的,任何的扰动都会导致loss增加。剪枝的目标就是找到对参数进行重要性评估,将对E影响最小的参数置为0。

再说OBS

论文:https://proceedings.neurips.cc/paper/1992/file/303ed4c69846ab36c2904d3ba8573050-Paper.pdf 

基于OBD的结论,容易看到对角近似的假设是可能存在问题的。OBD主要对这部分进行了改进:

image.png

image.png

image.png

在具有约束条件的情况下,引入松弛变量构建拉格朗日函数:

image.png

image.png

image.png

image.png

然后说OBC

论文:https://openreview.net/pdf?id=ksVGCOlOEba

OBC基于OBS的结论,做了下面的两个假设:

  1. 假设了Loss的形式是:

image.png

即为剪枝后的激活值和剪枝前激活值的MSE loss。

  1. 每个权重的行独立影响激活值的行

image.png

image.png

在整体矩阵尺度上,OBS在分别评估每一行的待剪枝的参数后,整体更新global mask并计算出剪枝后的W:

image.png

其中的重要性估计和参数更新公式原型来自OBS。

由于前提假设是剪枝,如果改为量化只需要修改松弛变量条件:

image.png

可以得到量化版本的OBC(OBQ)的权重更新公式和重要性评估公式为:

image.png

OBQ会按照参数重要性对参数进行逐个量化。

终于到了GPTQ

论文:https://arxiv.org/pdf/2210.17323

基于OBS,GPTQ在实现上进行了优化。

  1. OBQ总是使用贪婪算法来优先量化对E影响最小的参数,而GPTQ通过实验发现,针对不同的行的量化顺序并不会影响最终结果,这使得量化可以按列顺序进行,且行量化可以并行进行,提高量化速度
  2. 按照OBQ的公式,每次量化一个参数后需要更新整体参数矩阵,但是对当前列进行量化时,后面的列参数对当前的量化无影响,而是受到当前列量化的影响(当然这是个近似估计)。因此可以按照B=128进行分块,使得块内部参数立即更新,块外部的后续列只是暂时记录更新的值,等128列整体更新完成,在一起更新后续的列参数。这样可以高效利用GPU的并行计算能力,减小吞吐压力。

image.png

Lazy-Batch Updates

其中的Q代表batch更新的量化索引。

image.png

image.png

在比较BnB和GPTQ后,我们可以看到这样的差异:

  1. BnB量化使用了离群值和非离群值区分处理的策略,因此速度快,不需要数据集。
  2. GPTQ的量化操作基于泰勒级数分解,其评估公式依赖于海森矩阵,并和输入X强相关,因此需要迭代更新,速度慢但更准确。

AWQ量化

论文:https://arxiv.org/pdf/2306.00978

了解了BnB量化后,对AWQ量化的理解会更简单一些。BnB量化的思路是按照阈值切分离群值和非离群值,整体进行混合精度训练。而AWQ的论文认为:

  1. 按照离群值划分不够精确,应当按照“权重的显著性(salient)”来划分
  2. 保持显著性权重为fp16会造成硬件实现的困难和速度的降低,因此应当想办法针对这部分权重进行单独量化

AWQ量化的具体方式仍然是absmax:

image.png

不同的是,它在absmax的基础上增加了新的缩放因子s(s>1):

image.png

缩放因子s可以追溯到一篇叫做SmoothQuant的工作,这里我们不详述。

之所以能够增加因子s,是因为有几个推论:

  1. 量化的精度损失主要来自Round部分带来的舍入误差。而无论如何缩放,该部分的误差都在0~0.5之间,平均值为0.25
  2. 对1%的重要权重进行缩放并不会影响整体的缩放比例

但是对重要权重进行缩放后,输出的激活值的误差会变为:

image.png

上文提到,增加s对缩放比例和RoundErr的影响比较小,因此重要权重的整体Err会被缩小到1/s倍。

下面的问题就是如何确定这些重要参数有哪些呢?

AWQ提出了两种方案:

  1. 权重本身的L2范数
  2. 权重激活值的L2范数

经过试验发现,权重本身的L2范数对评估参数重要性没有显著作用,而权重激活值的L2范数可以提现权重的重要性特征,因此采用权重激活值来评估权重本身的重要性。

image.png

那么s的值是不是越大越好呢?由于s增大可能会影响缩放比例,因此会对非重要参数起到不良影响。根据实验,s=2可以达到最好的效果。

为了让效果更好,AWQ针对每个量化通道都进行了单独的s值评估:

image.png

目标是找到最优的s是Loss最小。由于无法直接训练(因为量化部分无法求导),因此采用了一个简单的做法:

image.png

image.png

HQQ量化

blog:https://mobiusml.github.io/hqq_blog/

HQQ量化的思路和上面的量化方式不太一样。HQQ量化的问题定义在如何在零点量化中取得最优的z和s(零点和缩放倍数)。

原问题可以定义为:

image.png

HQQ求解该问题引入了额外参数W_e:

image.png

可以看到该问题形式类似于类似Lasso回归,可以使用类似软阈值法求解。在定义了新的参数后,可以将该问题分解为两个子问题:

image.png

第一步:固定其他参数,找到使loss最低的

image.png

其中,为了让求解更简单,HQQ将缩放尺度s进行固定,仅优化z(零点)值。

在第一步中,可以使用软阈值法进行求解,在HQQ中作者使用了另一个通用软阈值求解器,以适应范数小于1的情形。

第二步可以进行等式变换变为如下形式:

image.png

其解可以直接设置为每个block内部,右侧子式的均值:

image.png

可以看到该方法和输入无关,因此不需要量化集。

总结

前提:量化是把模型的浮点型参数转换为整形(至少是更低的bit数)的过程,减少显存占用。

  1. BnB量化建议设立阈值,将离群点和非离群点分开处理,其中离群点不进行量化,非离群点进行8bit量化。同时,在4bit量化时,支持了nf4格式,该格式的数值分布并不均匀(为正态分布),使数值分布更符合LLM参数分布。
  2. GPTQ使用了泰勒级数分解,使用海森矩阵评估参数重要性以及更新量化后的参数,并利用现代GPU的特点,进行了并行计算,使显存占用和处理速度大大增加,但是它需要量化集辅助量化。
  3. AWQ认为部分参数更加重要,通过激活值尺度评估了重要参数后,对这些参数按组进行了缩放,达到了减小Loss的效果,由于需要激活值,因此AWQ也需要量化集辅助量化。
  4. HQQ通过对零点量化的公式转换,将其分解为两个子问题分别求解,找到最优的z,该迭代对输入无要求,因此不需要量化集。

QLoRA

LoRA部分可以参考另外一篇文章:

https://github.com/modelscope/modelscope-classroom/blob/main/LLM-tutorial/H.%E8%AE%AD%E7%BB%83.md#lora

image.png

简单说,LoRA是附着在模型上的额外参数矩阵,在训练时冻结原模型,仅训练LoRA部分。如果原模型是量化后的weights(即左边的Pretrained Weights部分),那么和LoRA可以很匹配:原模型占用的显存大大减小了,LoRA部分保持fp16/bf16可以正常forward/backward。

应用

除上面介绍的量化方法外,还有很多其他类型的量化方法,比如AQLM、EETQ、GGUF等,这么多的量化方式,一个一个了解使用太麻烦了,在不修改训练代码的情况下适配多种量化策略是非常重要的。

在这里使用了魔搭社区的SWIFT框架来进行量化训练。该框架在github上开源:

https://github.com/modelscope/swift

或者通过pip安装:

pip install ms-swift
# autoawq和cuda版本有对应关系,请按照`https://github.com/casper-hansen/AutoAWQ`选择版本
pip install autoawq -U
# auto_gptq和cuda版本有对应关系,请按照`https://github.com/PanQiWei/AutoGPTQ#quick-installation`选择版本
pip install auto_gptq -U
# hqq和eetq使用暂时需要从源码下载transformers和peft
pip install git+https://github.com/huggingface/transformers
pip install git+https://github.com/huggingface/peft.git
# hqq
pip install hqq
# eetq
git clone https://github.com/NetEase-FuXi/EETQ.git
cd EETQ/
git submodule update --init --recursive
pip install .

回顾下上面提到的量化方式,bnb/hqq/eetq是不需要量化数据集的,因此可以在训练前直接量化模型,速度很快。因此推荐即时量化后直接QLoRA训练模型:

swift sft --model_type llama3-8b-instruct --dataset alpaca-en --quantization_bit 8 --quant_method bnb --sft_type lora

也可以替换为hqq或者eetq:

swift sft --model_type llama3-8b-instruct --dataset alpaca-en --quantization_bit 8 --quant_method eetq --sft_type lora
# --quant_method eetq

其中bnb支持4/8 bit量化,eetq支持8bit量化,hqq支持1/2/3/4/8bit量化。

而GPTQ和AWQ由于需要量化集的存在,且量化会花费较长时间,因此一般在训练后(或者针对原始模型)再单独量化:

# GPTQ
OMP_NUM_THREADS=14 swift export --model_type llama3-8b-instruct --quant_method gptq --dataset alpaca-zh alpaca-en sharegpt-gpt4-mini --quant_seqlen 4096 --quant_bits 4
# AWQ
swift export --model_type llama3-8b-instruct --quant_bits 4 --quant_method awq --quant_n_samples 64 --quant_seqlen 4096 --dataset alpaca-zh alpaca-en sharegpt-gpt4-mini

注意,实际使用GPTQ量化时需要指定OMP_NUM_THREADS=N,否则会出现CPU占满阻塞的问题。

swift export指令会使用指定的数据集对模型进行量化,并在本地保存量化后的模型,默认的保存路径为'{model_type}-{quant_method}-{quant_bits}',也可以通过--quant_output_dir来指定

QLoRA可以支持FSDP(完全分片数据并行技术),因此可以使用BNB+LoRA在两张24G显卡上运行一个70B模型的训练:

# 源代码clone
# cd examples/pytorch/llm
# vim fsdp.sh并写入下面的内容
# pip install bitsandbytes>=0.43.0
nproc_per_node=2
CUDA_VISIBLE_DEVICES=0,1 \
accelerate launch --config_file "./scripts/llama2_70b_chat/qlora_fsdp/fsdp_offload.json" \
    llm_sft.py \
    --model_type llama2-70b-chat \
    --model_revision master \
    --sft_type lora \
    --tuner_backend peft \
    --template_type AUTO \
    --dtype bf16 \
    --output_dir output \
    --dataset leetcode-python-en \
    --train_dataset_sample -1 \
    --num_train_epochs 1 \
    --max_length 2048 \
    --check_dataset_strategy warning \
    --quantization_bit 4 \
    --bnb_4bit_comp_dtype AUTO \
    --bnb_4bit_quant_storage bfloat16 \
    --lora_rank 8 \
    --lora_alpha 32 \
    --lora_dtype AUTO \
    --lora_dropout_p 0.05 \
    --lora_target_modules DEFAULT \
    --gradient_checkpointing true \
    --batch_size 1 \
    --weight_decay 0.1 \
    --learning_rate 1e-4 \
    --gradient_accumulation_steps $(expr 16 / $nproc_per_node) \
    --max_grad_norm 0.5 \
    --warmup_ratio 0.03 \
    --eval_steps 50 \
    --save_steps 50 \
    --save_total_limit 2 \
    --logging_steps 10 \

如果只是想体验量化后的模型推理阶段,可以借助不需要校准数据集的量化方法,使用swift infer来量化模型并推理,大大减少模型推理所需的显存占用

CUDA_VISIBLE_DEVICES=0 swift infer \
    --model_type qwen1half-7b-chat \
    --quant_method bnb \
    --quantization_bit 4
CUDA_VISIBLE_DEVICES=0 swift infer \
    --model_type qwen1half-7b-chat \
    --quant_method hqq \
    --quantization_bit 4
CUDA_VISIBLE_DEVICES=0 swift infer \
    --model_type qwen1half-7b-chat \
    --quant_method eetq \
    --dtype fp16

总结

我们介绍了几种常用量化的思路,以及它们的使用方式。并且我们通过魔搭社区的训练框架SWIFT给出了使用这些量化方式的即开即用流程。如果本文的技术原理存在理解错误,欢迎讨论和反馈。

Github:

https://github.com/modelscope/swift

官方交流群:

image.png

点击直达LLM入门学习更多课程干货~

七天入门LLM大模型学习 · 研习社 (modelscope.cn)

相关文章
|
11天前
|
机器学习/深度学习 人工智能 算法
DeepSeek技术报告解析:为什么DeepSeek-R1 可以用低成本训练出高效的模型
DeepSeek-R1 通过创新的训练策略实现了显著的成本降低,同时保持了卓越的模型性能。本文将详细分析其核心训练方法。
292 11
DeepSeek技术报告解析:为什么DeepSeek-R1 可以用低成本训练出高效的模型
|
11天前
|
搜索推荐 数据挖掘 API
Lazada 淘宝详情 API 的价值与应用解析
在全球化电商浪潮下,Lazada 和淘宝作为东南亚和中国电商市场的关键力量,拥有海量商品数据和庞大用户群体。详情 API 接口为电商开发者、商家和分析师提供了获取商品详细信息(如描述、价格、库存、评价等)的工具,助力业务决策与创新。本文深入解析 Lazada 和淘宝详情 API 的应用场景及价值,并提供 Python 调用示例,帮助读者更好地理解和运用这两个强大的工具。
45 18
|
10天前
|
数据采集 搜索推荐 API
小红书笔记详情 API 接口:获取、应用与收益全解析
小红书(RED)是国内领先的生活方式分享平台,汇聚大量用户生成内容(UGC),尤以“种草”笔记闻名。小红书笔记详情API接口为开发者提供了获取笔记详细信息的强大工具,包括标题、内容、图片、点赞数等。通过注册开放平台账号、申请API权限并调用接口,开发者可构建内容分析工具、笔记推荐系统、数据爬虫等应用,提升用户体验和运营效率,创造新的商业模式。本文将详细介绍该API的获取、应用及潜在收益,并附上代码示例。
100 13
|
4天前
|
人工智能 自然语言处理 算法
DeepSeek模型的突破:性能超越R1满血版的关键技术解析
上海AI实验室周伯文团队的最新研究显示,7B版本的DeepSeek模型在性能上超越了R1满血版。该成果强调了计算最优Test-Time Scaling的重要性,并提出了一种创新的“弱到强”优化监督机制的研究思路,区别于传统的“从强到弱”策略。这一方法不仅提升了模型性能,还为未来AI研究提供了新方向。
175 5
|
21天前
|
搜索推荐 测试技术 API
探秘电商API:从测试到应用的深度解析与实战指南
电商API是电子商务背后的隐形引擎,支撑着从商品搜索、购物车更新到支付处理等各个环节的顺畅运行。它通过定义良好的接口,实现不同系统间的数据交互与功能集成,确保订单、库存和物流等信息的实时同步。RESTful、GraphQL和WebSocket等类型的API各自适用于不同的应用场景,满足多样化的需求。在测试方面,使用Postman、SoapUI和jMeter等工具进行全面的功能、性能和安全测试,确保API的稳定性和可靠性。未来,随着人工智能、大数据和物联网技术的发展,电商API将进一步智能化和标准化,为用户提供更个性化的购物体验,并推动电商行业的持续创新与进步。
54 4
|
28天前
|
JSON 小程序 UED
微信小程序 app.json 配置文件解析与应用
本文介绍了微信小程序中 `app.json` 配置文件的详细
132 12
|
21天前
|
搜索推荐 API 开发者
深度解析:利用商品详情 API 接口实现数据获取与应用
在电商蓬勃发展的今天,数据成为驱动业务增长的核心。商品详情API接口作为连接海量商品数据的桥梁,帮助运营者、商家和开发者获取精准的商品信息(如价格、描述、图片、评价等),优化策略、提升用户体验。通过理解API概念、工作原理及不同平台特点,掌握获取权限、构建请求、处理响应和错误的方法,可以将数据应用于商品展示、数据分析、竞品分析和个性化推荐等场景,助力电商创新与发展。未来,随着技术进步,API接口将与人工智能、大数据深度融合,带来更多变革。
62 3
|
3月前
|
监控 Java 应用服务中间件
高级java面试---spring.factories文件的解析源码API机制
【11月更文挑战第20天】Spring Boot是一个用于快速构建基于Spring框架的应用程序的开源框架。它通过自动配置、起步依赖和内嵌服务器等特性,极大地简化了Spring应用的开发和部署过程。本文将深入探讨Spring Boot的背景历史、业务场景、功能点以及底层原理,并通过Java代码手写模拟Spring Boot的启动过程,特别是spring.factories文件的解析源码API机制。
131 2
|
2月前
|
设计模式 存储 安全
【23种设计模式·全精解析 | 创建型模式篇】5种创建型模式的结构概述、实现、优缺点、扩展、使用场景、源码解析
创建型模式的主要关注点是“怎样创建对象?”,它的主要特点是"将对象的创建与使用分离”。这样可以降低系统的耦合度,使用者不需要关注对象的创建细节。创建型模式分为5种:单例模式、工厂方法模式抽象工厂式、原型模式、建造者模式。
【23种设计模式·全精解析 | 创建型模式篇】5种创建型模式的结构概述、实现、优缺点、扩展、使用场景、源码解析
|
2月前
|
存储 设计模式 算法
【23种设计模式·全精解析 | 行为型模式篇】11种行为型模式的结构概述、案例实现、优缺点、扩展对比、使用场景、源码解析
行为型模式用于描述程序在运行时复杂的流程控制,即描述多个类或对象之间怎样相互协作共同完成单个对象都无法单独完成的任务,它涉及算法与对象间职责的分配。行为型模式分为类行为模式和对象行为模式,前者采用继承机制来在类间分派行为,后者采用组合或聚合在对象间分配行为。由于组合关系或聚合关系比继承关系耦合度低,满足“合成复用原则”,所以对象行为模式比类行为模式具有更大的灵活性。 行为型模式分为: • 模板方法模式 • 策略模式 • 命令模式 • 职责链模式 • 状态模式 • 观察者模式 • 中介者模式 • 迭代器模式 • 访问者模式 • 备忘录模式 • 解释器模式
【23种设计模式·全精解析 | 行为型模式篇】11种行为型模式的结构概述、案例实现、优缺点、扩展对比、使用场景、源码解析

热门文章

最新文章

推荐镜像

更多