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

本文涉及的产品
全局流量管理 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)

相关文章
|
18天前
|
机器学习/深度学习 人工智能 自然语言处理
AI技术深度解析:从基础到应用的全面介绍
人工智能(AI)技术的迅猛发展,正在深刻改变着我们的生活和工作方式。从自然语言处理(NLP)到机器学习,从神经网络到大型语言模型(LLM),AI技术的每一次进步都带来了前所未有的机遇和挑战。本文将从背景、历史、业务场景、Python代码示例、流程图以及如何上手等多个方面,对AI技术中的关键组件进行深度解析,为读者呈现一个全面而深入的AI技术世界。
90 10
|
1天前
|
自然语言处理 文字识别 数据处理
多模态文件信息抽取:技术解析与实践评测!
在大数据和人工智能时代,企业和开发者面临的挑战是如何高效处理多模态数据(文本、图像、音频、视频)以快速提取有价值信息。传统方法效率低下,难以满足现代需求。本文将深度评测阿里云的多模态文件信息抽取解决方案,涵盖部署、应用、功能与性能,揭示其在复杂数据处理中的潜力。通过自然语言处理(NLP)、计算机视觉(CV)、语音识别(ASR)等技术,该方案助力企业挖掘多模态数据的价值,提升数据利用效率。
12 4
多模态文件信息抽取:技术解析与实践评测!
|
4天前
|
域名解析 负载均衡 安全
DNS技术标准趋势和安全研究
本文探讨了互联网域名基础设施的结构性安全风险,由清华大学段教授团队多年研究总结。文章指出,DNS系统的安全性不仅受代码实现影响,更源于其设计、实现、运营及治理中的固有缺陷。主要风险包括协议设计缺陷(如明文传输)、生态演进隐患(如单点故障增加)和薄弱的信任关系(如威胁情报被操纵)。团队通过多项研究揭示了这些深层次问题,并呼吁构建更加可信的DNS基础设施,以保障全球互联网的安全稳定运行。
|
4天前
|
缓存 网络协议 安全
融合DNS技术产品和生态
本文介绍了阿里云在互联网基础资源领域的最新进展和解决方案,重点围绕共筑韧性寻址、赋能新质生产展开。随着应用规模的增长,基础服务的韧性变得尤为重要。阿里云作为互联网资源的践行者,致力于推动互联网基础资源技术研究和自主创新,打造更韧性的寻址基础服务。文章还详细介绍了浙江省IPv6创新实验室的成立背景与工作进展,以及阿里云在IPv6规模化部署、DNS产品能力升级等方面的成果。此外,阿里云通过端云融合场景下的企业级DNS服务,帮助企业构建稳定安全的DNS系统,确保企业在数字世界中的稳定运行。最后,文章强调了全链路极致高可用的企业DNS解决方案,为全球互联网基础资源的创新提供了中国标准和数字化解决方案。
|
4天前
|
缓存 边缘计算 网络协议
深入解析CDN技术:加速互联网内容分发的幕后英雄
内容分发网络(CDN)是现代互联网架构的重要组成部分,通过全球分布的服务器节点,加速网站、应用和多媒体内容的传递。它不仅提升了访问速度和用户体验,还减轻了源站服务器的负担。CDN的核心技术包括缓存机制、动态加速、流媒体加速和安全防护,广泛应用于静态资源、动态内容、视频直播及大文件下载等场景,具有低延迟、高带宽、稳定性强等优势,有效降低成本并保障安全。
25 3
|
8天前
|
安全 API 数据安全/隐私保护
速卖通AliExpress商品详情API接口深度解析与实战应用
速卖通(AliExpress)作为全球化电商的重要平台,提供了丰富的商品资源和便捷的购物体验。为了提升用户体验和优化商品管理,速卖通开放了API接口,其中商品详情API尤为关键。本文介绍如何获取API密钥、调用商品详情API接口,并处理API响应数据,帮助开发者和商家高效利用这些工具。通过合理规划API调用策略和确保合法合规使用,开发者可以更好地获取商品信息,优化管理和营销策略。
|
2月前
|
监控 Java 应用服务中间件
高级java面试---spring.factories文件的解析源码API机制
【11月更文挑战第20天】Spring Boot是一个用于快速构建基于Spring框架的应用程序的开源框架。它通过自动配置、起步依赖和内嵌服务器等特性,极大地简化了Spring应用的开发和部署过程。本文将深入探讨Spring Boot的背景历史、业务场景、功能点以及底层原理,并通过Java代码手写模拟Spring Boot的启动过程,特别是spring.factories文件的解析源码API机制。
87 2
|
3月前
|
缓存 Java 程序员
Map - LinkedHashSet&Map源码解析
Map - LinkedHashSet&Map源码解析
87 0
|
10天前
|
存储 设计模式 算法
【23种设计模式·全精解析 | 行为型模式篇】11种行为型模式的结构概述、案例实现、优缺点、扩展对比、使用场景、源码解析
行为型模式用于描述程序在运行时复杂的流程控制,即描述多个类或对象之间怎样相互协作共同完成单个对象都无法单独完成的任务,它涉及算法与对象间职责的分配。行为型模式分为类行为模式和对象行为模式,前者采用继承机制来在类间分派行为,后者采用组合或聚合在对象间分配行为。由于组合关系或聚合关系比继承关系耦合度低,满足“合成复用原则”,所以对象行为模式比类行为模式具有更大的灵活性。 行为型模式分为: • 模板方法模式 • 策略模式 • 命令模式 • 职责链模式 • 状态模式 • 观察者模式 • 中介者模式 • 迭代器模式 • 访问者模式 • 备忘录模式 • 解释器模式
【23种设计模式·全精解析 | 行为型模式篇】11种行为型模式的结构概述、案例实现、优缺点、扩展对比、使用场景、源码解析
|
10天前
|
设计模式 存储 安全
【23种设计模式·全精解析 | 创建型模式篇】5种创建型模式的结构概述、实现、优缺点、扩展、使用场景、源码解析
结构型模式描述如何将类或对象按某种布局组成更大的结构。它分为类结构型模式和对象结构型模式,前者采用继承机制来组织接口和类,后者釆用组合或聚合来组合对象。由于组合关系或聚合关系比继承关系耦合度低,满足“合成复用原则”,所以对象结构型模式比类结构型模式具有更大的灵活性。 结构型模式分为以下 7 种: • 代理模式 • 适配器模式 • 装饰者模式 • 桥接模式 • 外观模式 • 组合模式 • 享元模式
【23种设计模式·全精解析 | 创建型模式篇】5种创建型模式的结构概述、实现、优缺点、扩展、使用场景、源码解析

热门文章

最新文章

推荐镜像

更多