一、装饰器模式(Decorator)
1.1 模式定义
动态地给一个对象增加一些额外的职责。就增加功能来说,装饰器模式相比生成子类更为灵活。
核心要点:
装饰器和被装饰对象继承自同一个接口或基类
装饰器包装被装饰对象,在调用前后可添加额外逻辑
可以无限嵌套装饰
1.2 结构
复制代码
Component(抽象组件)
↑ extends
ConcreteComponent(具体组件)
↑ wraps
Decorator(装饰器)
↑ extends
ConcreteDecorator(具体装饰器)
1.3 代码实现
cpp
复制代码
#include <iostream>
#include <string>
// 抽象组件:饮料
class IBeverage {
public:
virtual ~IBeverage() {}
virtual std::string description() const = 0;
virtual double cost() const = 0;
};
// 具体组件:咖啡
class Coffee : public IBeverage {
public:
std::string description() const override {
return "Coffee";
}
double cost() const override {
return 20.0;
}
};
// 装饰器基类
class BeverageDecorator : public IBeverage {
protected:
IBeverage* m_beverage;
public:
BeverageDecorator(IBeverage* beverage) : m_beverage(beverage) {}
std::string description() const override {
return m_beverage->description();
}
double cost() const override {
return m_beverage->cost();
}
};
// 具体装饰器:牛奶
class MilkDecorator : public BeverageDecorator {
public:
MilkDecorator(IBeverage* beverage) : BeverageDecorator(beverage) {}
std::string description() const override {
return m_beverage->description() + " + Milk";
}
double cost() const override {
return m_beverage->cost() + 5.0;
}
};
// 具体装饰器:糖
class SugarDecorator : public BeverageDecorator {
public:
SugarDecorator(IBeverage* beverage) : BeverageDecorator(beverage) {}
std::string description() const override {
return m_beverage->description() + " + Sugar";
}
double cost() const override {
return m_beverage->cost() + 2.0;
}
};
int main() {
// 原味咖啡
IBeverage* coffee = new Coffee();
std::cout << coffee->description() << " = " << coffee->cost() << std::endl;
// 咖啡 + 牛奶
IBeverage* milkCoffee = new MilkDecorator(coffee);
std::cout << milkCoffee->description() << " = " << milkCoffee->cost() << std::endl;
// 咖啡 + 牛奶 + 糖
IBeverage* sweetMilkCoffee = new SugarDecorator(milkCoffee);
std::cout << sweetMilkCoffee->description() << " = " << sweetMilkCoffee->cost() << std::endl;
delete sweetMilkCoffee;
delete milkCoffee;
delete coffee;
return 0;
}
1.4 流程图
复制代码
main
|
v
[创建Coffee对象]
|
v
[输出: Coffee = 20]
|
v
[创建MilkDecorator(Coffee)]
|
v
[输出: Coffee + Milk = 25]
|
v
[创建SugarDecorator(MilkDecorator(Coffee))]
|
v
[输出: Coffee + Milk + Sugar = 27]
|
v
[依次delete释放内存]
1.5 逐行解析
cpp
复制代码
// 抽象组件,定义饮料的共同接口
class IBeverage {
public:
virtual ~IBeverage() {} // 虚析构,保证多态删除安全
virtual std::string description() const = 0; // 描述
virtual double cost() const = 0; // 价格
};
// 具体组件,最基础的咖啡
class Coffee : public IBeverage {
std::string description() const override {
return "Coffee"; // 返回描述
}
double cost() const override {
return 20.0; // 价格20元
}
};
// 装饰器基类,关键:包含一个组件指针
class BeverageDecorator : public IBeverage {
protected:
IBeverage* m_beverage; // 被包装的组件
public:
BeverageDecorator(IBeverage* beverage) : m_beverage(beverage) {}
// 默认委托给被包装对象
std::string description() const override {
return m_beverage->description();
}
double cost() const override {
return m_beverage->cost();
}
};
// 具体装饰器:添加牛奶
class MilkDecorator : public BeverageDecorator {
public:
MilkDecorator(IBeverage* beverage) : BeverageDecorator(beverage) {}
std::string description() const override {
// 在原有基础上添加 "+ Milk"
return m_beverage->description() + " + Milk";
}
double cost() const override {
// 在原有价格上加5元
return m_beverage->cost() + 5.0;
}
};
1.6 对比表
特性
继承方式
灵活性
代码复杂度
装饰器模式
组合
高,可动态添加
中等
继承子类
继承
低,编译时确定
简单
1.7 面试追问 FAQ
问题
回答
装饰器与代理模式的区别?
装饰器侧重于功能增强,代理模式侧重于控制访问
装饰器可以嵌套几层?
理论上无限,但实际中2-4层为宜
如何解除装饰关系?
通过接口向上转型后,再提取原始对象
二、组合模式(Composite)
2.1 模式定义
将对象组合成树型结构以表示"部分-整体"的层次结构,使得用户对单个对象和组合对象的使用具有一致性。
核心要点:
抽象组件定义共同接口
叶子节点和组合节点实现相同的接口
组合节点可以包含叶子或其他组合节点
2.2 结构
复制代码
Component(抽象组件)
|-- Leaf(叶子节点): 实现具体操作
|-- Composite(组合节点): 包含叶子列表,实现操作时遍历所有子节点
2.3 代码实现
cpp
复制代码
#include <iostream>
#include <vector>
#include <string>
// 抽象组件:文件系统节点
class IFileSystemNode {
public:
virtual ~IFileSystemNode() {}
virtual size_t size() const = 0;
virtual void display(int depth = 0) const = 0;
};
// 叶子节点:文件
class File : public IFileSystemNode {
private:
std::string m_name;
size_t m_size;
public:
File(const std::string& name, size_t size) : m_name(name), m_size(size) {}
size_t size() const override {
return m_size;
}
void display(int depth = 0) const override {
std::string indent(depth * 2, '-');
std::cout << indent << m_name << " (" << m_size << " KB)" << std::endl;
}
};
// 组合节点:文件夹
class Folder : public IFileSystemNode {
private:
std::string m_name;
std::vector<IFileSystemNode*> m_children;
public:
Folder(const std::string& name) : m_name(name) {}
void add(IFileSystemNode* node) {
m_children.push_back(node);
}
size_t size() const override {
size_t total = 0;
for (const auto& child : m_children) {
total += child->size();
}
return total;
}
void display(int depth = 0) const override {
std::string indent(depth * 2, '-');
std::cout << indent << m_name << "/ (total: " << size() << " KB)" << std::endl;
for (const auto& child : m_children) {
child->display(depth + 1);
}
}
};
int main() {
Folder* root = new Folder("root");
File* f1 = new File("a.txt", 100);
File* f2 = new File("b.txt", 200);
Folder* subFolder = new Folder("sub");
File* f3 = new File("c.txt", 300);
subFolder->add(f3);
root->add(f1);
root->add(f2);
root->add(subFolder);
root->display();
delete root;
return 0;
}
2.4 流程图
复制代码
main
|
v
[创建root文件夹]
|
v
[创建文件a.txt(100KB), b.txt(200KB)]
|
v
[创建sub文件夹]
|
v
[创建文件c.txt(300KB)]
|
v
[sub.add(c.txt)]
|
v
[root.add(a.txt), root.add(b.txt), root.add(sub)]
|
v
[root.display()]
|
+-- root/(total: 600KB)
+-- a.txt(100KB)
+-- b.txt(200KB)
+-- sub/(total: 300KB)
+-- c.txt(300KB)
2.5 逐行解析
cpp
复制代码
// 抽象组件:所有节点共同接口
class IFileSystemNode {
public:
virtual ~IFileSystemNode() {} // 虚析构
virtual size_t size() const = 0; // 计算大小
virtual void display(int depth = 0) const = 0; // 显示结构
};
// 叶子节点:文件
class File : public IFileSystemNode {
size_t size() const override {
return m_size; // 直接返回自身大小
}
void display(int depth = 0) const override {
std::string indent(depth * 2, '-');
std::cout << indent << m_name << " (" << m_size << " KB)" << std::endl;
}
};
// 组合节点:文件夹
class Folder : public IFileSystemNode {
std::vector<IFileSystemNode*> m_children; // 子节点列表
size_t size() const override {
size_t total = 0;
for (const auto& child : m_children) {
total += child->size(); // 递归累加所有子节点大小
}
return total;
}
void display(int depth = 0) const override {
// 先显示文件夹自身
std::cout << std::string(depth * 2, '-') << m_name << "/" << std::endl;
// 再递归显示所有子节点
for (const auto& child : m_children) {
child->display(depth + 1);
}
}
};
2.6 对比表
特性
透明组合模式
安全组合模式
接口定义
包含所有操作
仅包含共同操作
安全性
低,Leaf也可以add
高,叶子节点无add
透明性
高,一致性外露
低,需判断节点类型
2.7 面试追问 FAQ
问题
回答
组合模式与迭代器模式?
组合模式构成树形结构,迭代器遍历树形结构
如何防止环状引用?
在add时检查,避免子节点已包含父节点
组合模式优点?
一致性接口,简化客户端代码
三、桥接模式(Bridge)
3.1 模式定义
将抽象部分与实现部分分离,使它们都可以独立地变化。
核心要点:
抽象部分包含实现部分的引用
两者可以独立扩展,不互相影响
避免类爆炸
3.2 结构
复制代码
Abstraction(抽象)
|ref
Implementor(实现接口)
↑
|
ConcreteImplementor(具体实现)
3.3 代码实现
cpp
复制代码
#include <iostream>
#include <string>
// 实现部分:消息发送接口
class IMessageSender {
public:
virtual ~IMessageSender() {}
virtual void send(const std::string& message) = 0;
};
// 具体实现:邮件发送
class EmailSender : public IMessageSender {
public:
void send(const std::string& message) override {
std::cout << "[Email] " << message << std::endl;
}
};
// 具体实现:短信发送
class SmsSender : public IMessageSender {
public:
void send(const std::string& message) override {
std::cout << "[SMS] " << message << std::endl;
}
};
// 具体实现:微信发送
class WechatSender : public IMessageSender {
public:
void send(const std::string& message) override {
std::cout << "[Wechat] " << message << std::endl;
}
};
// 抽象部分:消息
class Message {
protected:
IMessageSender* m_sender; // 桥接引用
public:
Message(IMessageSender* sender) : m_sender(sender) {}
virtual ~Message() {}
virtual void sendMessage(const std::string& content) = 0;
};
// 扩展抽象:普通消息
class NormalMessage : public Message {
public:
NormalMessage(IMessageSender* sender) : Message(sender) {}
void sendMessage(const std::string& content) override {
std::cout << "Normal: ";
m_sender->send(content);
}
};
// 扩展抽象:紧急消息
class UrgentMessage : public Message {
public:
UrgentMessage(IMessageSender* sender) : Message(sender) {}
void sendMessage(const std::string& content) override {
std::cout << "URGENT: ";
m_sender->send("[URGENT] " + content);
}
};
int main() {
// 普通消息用邮件发送
Message* m1 = new NormalMessage(new EmailSender());
m1->sendMessage("Hello");
// 紧急消息用短信发送
Message* m2 = new UrgentMessage(new SmsSender());
m2->sendMessage("Emergency!");
// 普通消息用微信发送
Message* m3 = new NormalMessage(new WechatSender());
m3->sendMessage("Hi");
delete m1; delete m2; delete m3;
return 0;
}
3.4 流程图
复制代码
m1 = new NormalMessage(EmailSender)
|
v
m1.sendMessage("Hello")
|
v
输出: Normal: [Email] Hello
m2 = new UrgentMessage(SmsSender)
|
v
m2.sendMessage("Emergency!")
|
v
输出: URGENT: [SMS] [URGENT] Emergency!
m3 = new NormalMessage(WechatSender)
|
v
m3.sendMessage("Hi")
|
v
输出: Normal: [Wechat] Hi
3.5 逐行解析
cpp
复制代码
// 实现接口:消息发送器
class IMessageSender {
public:
virtual ~IMessageSender() {}
virtual void send(const std::string& message) = 0; // 发送消息
};
// 抽象部分:消息(包含发送器引用)
class Message {
protected:
IMessageSender* m_sender; // 桥接指针
public:
Message(IMessageSender* sender) : m_sender(sender) {}
virtual void sendMessage(const std::string& content) = 0;
};
// 普通消息
class NormalMessage : public Message {
void sendMessage(const std::string& content) override {
std::cout << "Normal: ";
m_sender->send(content); // 委托给发送器
}
};
// 紧急消息
class UrgentMessage : public Message {
void sendMessage(const std::string& content) override {
std::cout << "URGENT: ";
m_sender->send("[URGENT] " + content); // 添加前缀后委托
}
};
3.6 对比表
模式
聚合方式
目的
桥接模式
组合(用指针)
分离抽象和实现,独立变化
适配器模式
组合/继承
转换接口,使不兼容兼容
装饰器模式
组合
动态增加职责
3.7 面试追问 FAQ
问题
回答
桥接模式和继承的区别?
继承是静态的,桥接是动态的;继承易类爆炸,桥接解耦
什么时候用桥接模式?
抽象和实现都需要独立扩展时
桥接模式优点?
减少类数量,提高可维护性
四、代理模式(Proxy)
4.1 模式定义
为其他对象提供一种代理以控制对这个对象的访问。
核心要点:
代理和真实对象实现相同接口
代理控制对真实对象的访问
客户端通过代理间接访问真实对象
4.2 结构
复制代码
Client
|
v
Proxy(代理)
|
v
RealSubject(真实对象)
4.3 代码实现
cpp
复制代码
#include <iostream>
#include <string>
// 抽象接口:图像
class IImage {
public:
virtual ~IImage() {}
virtual void display() = 0;
};
// 真实对象:大图片(加载慢)
class RealImage : public IImage {
private:
std::string m_filename;
public:
RealImage(const std::string& filename) : m_filename(filename) {
std::cout << "Loading image from disk: " << filename << std::endl;
}
void display() override {
std::cout << "Displaying: " << m_filename << std::endl;
}
};
// 代理:延迟加载
class ImageProxy : public IImage {
private:
std::string m_filename;
RealImage* m_realImage;
public:
ImageProxy(const std::string& filename)
: m_filename(filename), m_realImage(nullptr) {}
void display() override {
if (m_realImage == nullptr) {
std::cout << "[Proxy] First access, loading now..." << std::endl;
m_realImage = new RealImage(m_filename);
}
std::cout << "[Proxy] ";
m_realImage->display();
}
~ImageProxy() {
delete m_realImage;
}
};
int main() {
std::cout << "=== Creating proxies ===" << std::endl;
IImage* img1 = new ImageProxy("photo1.jpg");
IImage* img2 = new ImageProxy("photo2.jpg");
std::cout << "\n=== First display (triggers loading) ===" << std::endl;
img1->display();
img1->display(); // 第二次直接从缓存显示
std::cout << "\n=== Second display (from cache) ===" << std::endl;
img2->display();
delete img1; delete img2;
return 0;
}
4.4 流程图
复制代码
第一次img1.display()
|
v
[Proxy检查m_realImage==nullptr]
|
v
[输出: Loading image from disk: photo1.jpg]
|
v
[输出: Displaying: photo1.jpg]
第二次img1.display()
|
v
[Proxy检查m_realImage!=nullptr]
|
v
[直接调用m_realImage->display()]
|
v
[输出: Displaying: photo1.jpg]
4.5 逐行解析
cpp
复制代码
// 抽象接口
class IImage {
public:
virtual ~IImage() {}
virtual void display() = 0;
};
// 真实对象:实际加载图片
class RealImage : public IImage {
RealImage(const std::string& filename) {
// 模拟耗时操作
std::cout << "Loading image from disk: " << filename << std::endl;
}
void display() override {
std::cout << "Displaying: " << m_filename << std::endl;
}
};
// 代理:延迟加载
class ImageProxy : public IImage {
RealImage* m_realImage; // 懒加载,初始为nullptr
void display() override {
if (m_realImage == nullptr) {
std::cout << "[Proxy] First access, loading now..." << std::endl;
m_realImage = new RealImage(m_filename); // 第一次才加载
}
m_realImage->display(); // 委托
}
};
4.6 对比表
代理类型
用途
场景
远程代理
访问远程对象
WebService
虚代理
延迟加载
大图片、文档
保护代理
权限控制
访问控制
智能引用
访问时额外操作
引用计数
4.7 面试追问 FAQ
问题
回答
代理和装饰器的区别?
代理控制访问,装饰器增加功能
代理模式下 Subjects 是否实现同一接口?
是,这是透明访问的基础
如何实现远程代理?
序列化 + 网络传输
五、外观模式(Facade)
5.1 模式定义
为子系统中的一组接口提供一个统一的接口。外观模式定义了一个高级接口,使子系统更易于使用。
核心要点:
封装子系统的复杂接口
提供统一的简单接口
客户端与子系统解耦
5.2 结构
复制代码
Client --Facade--> SubSystem1
SubSystem2
SubSystem3
5.3 代码实现
cpp
复制代码
#include <iostream>
#include <string>
// 子系统1:CPU
class CPU {
public:
void start() { std::cout << "CPU: Starting..." << std::endl; }
void execute() { std::cout << "CPU: Executing instructions..." << std::endl; }
void stop() { std::cout << "CPU: Stopping..." << std::endl; }
};
// 子系统2:内存
class Memory {
public:
void load() { std::cout << "Memory: Loading data..." << std::endl; }
void clean() { std::cout << "Memory: Cleaning..." << std::endl; }
};
// 子系统3:硬盘
class HardDrive {
public:
void read() { std::cout << "HardDrive: Reading boot sector..." << std::endl; }
void write() { std::cout << "HardDrive: Writing data..." << std::endl; }
};
// 外观:电脑启动器
class ComputerFacade {
private:
CPU* m_cpu;
Memory* m_memory;
HardDrive* m_hardDrive;
public:
ComputerFacade() : m_cpu(new CPU()), m_memory(new Memory()), m_hardDrive(new HardDrive()) {}
~ComputerFacade() { delete m_cpu; delete m_memory; delete m_hardDrive; }
void start() {
std::cout << "=== Starting Computer ===" << std::endl;
m_hardDrive->read();
m_memory->load();
m_cpu->start();
m_cpu->execute();
std::cout << "=== Computer Started ===" << std::endl;
}
void shutdown() {
std::cout << "=== Shutting Down Computer ===" << std::endl;
m_cpu->stop();
m_memory->clean();
std::cout << "=== Computer Shutdown ===" << std::endl;
}
};
int main() {
ComputerFacade computer;
computer.start();
std::cout << std::endl;
computer.shutdown();
return 0;
}
5.4 流程图
复制代码
computer.start()
|
v
[输出: === Starting Computer ===]
|
v
[HardDrive.read()]
|
v
[Memory.load()]
|
v
[CPU.start()]
|
v
[CPU.execute()]
|
v
[输出: === Computer Started ===]
5.5 逐行解析
cpp
复制代码
// 外观类:封装子系统的复杂操作
class ComputerFacade {
private:
CPU* m_cpu;
Memory* m_memory;
HardDrive* m_hardDrive;
public:
// 启动电脑:一条命令代替多个子系统调用
void start() {
m_hardDrive->read(); // 读取引导扇区
m_memory->load(); // 加载数据到内存
m_cpu->start(); // 启动CPU
m_cpu->execute(); // 执行指令
}
// 关机
void shutdown() {
m_cpu->stop();
m_memory->clean();
}
};
// 客户端只需要调用外观即可
ComputerFacade computer;
computer.start(); // 一行代码启动电脑
5.6 对比表
模式
关注点
复杂度
外观模式
封装子系统,提供简单接口
简化客户端
中介者模式
封装对象间的交互
减少耦合
适配器模式
转换接口
使不兼容兼容
5.7 面试追问 FAQ
问题
回答
外观模式与迪米特法则?
外观是迪米特法则的典型实现,减少依赖
外观模式能否调用子系统所有功能?
是,但通常只封装常用操作
外观模式缺点?
可能引入不必要的耦合
六、享元模式(Flyweight)
6.1 模式定义
运用共享技术有效地支持大量细粒度的对象。
核心要点:
分离内部状态(可共享)和外部状态(不可共享)
通过工厂缓存共享对象
大幅减少内存占用
6.2 结构
复制代码
FlyweightFactory
|creates
|keeps
Flyweight <-- intrinsic state (shareable)
↑
|
ConcreteFlyweight
|extrinsic state (per-call passed)
Client
6.3 代码实现
cpp
复制代码
#include <iostream>
#include <unordered_map>
#include <string>
// 享元接口:字符
class CharacterFlyweight {
public:
virtual ~CharacterFlyweight() {}
virtual void display(char extrinsicState) = 0; // 外部状态作为参数传入
};
// 具体享元:字符(内部状态:字形数据)
class Character : public CharacterFlyweight {
private:
char m_char; // 内部状态,所有相同字符共享
public:
Character(char c) : m_char(c) {
std::cout << " [Creating flyweight for: '" << c << "']" << std::endl;
}
void display(char fontSize) override {
std::cout << "Character '" << m_char << "' with font size " << fontSize << std::endl;
}
};
// 享元工厂
class CharacterFactory {
private:
std::unordered_map<char, CharacterFlyweight*> m_pool;
public:
CharacterFlyweight* getCharacter(char c) {
auto it = m_pool.find(c);
if (it == m_pool.end()) {
std::cout << "Creating new flyweight for: ";
CharacterFlyweight* flyweight = new Character(c);
m_pool[c] = flyweight;
return flyweight;
}
std::cout << "Reusing flyweight for: ";
return it->second;
}
};
int main() {
std::cout << "=== Document with many repeated characters ===" << std::endl;
CharacterFactory factory;
std::string text = "abracadabra";
for (char c : text) {
// 字符本身('a', 'b', 'r'...)是内部状态,可共享
// 字体大小是外部状态,每次调用不同
char fontSize = (c - 'a') + 12; // 不同位置字体不同
CharacterFlyweight* flyweight = factory.getCharacter(c);
flyweight->display(fontSize);
}
std::cout << "\nTotal unique characters: " << 5 << std::endl;
std::cout << "Total characters in text: " << text.length() << std::endl;
return 0;
}
6.4 流程图
复制代码
遍历 "abracadabra"
|
v
'a': factory.getCharacter('a')
|--> 创建新的flyweight (存储在池中)
|--> display(font=12)
|
v
'b': factory.getCharacter('b')
|--> 创建新的flyweight
|--> display(font=13)
|
v
'r': factory.getCharacter('r')
|--> 创建新的flyweight
|--> display(font=18)
|
v
'a' again: factory.getCharacter('a')
|--> 复用已有flyweight
|--> display(font=12)
|
v
... (5个不同字符复用多次)
6.5 逐行解析
cpp
复制代码
// 享元接口
class CharacterFlyweight {
public:
// 外部状态作为参数传入,不存储在享元中
virtual void display(char fontSize) = 0;
};
// 具体享元:内部状态(字符代码)存储在对象中
class Character : public CharacterFlyweight {
private:
char m_char; // 内部状态,所有'a'共享同一个对象
public:
Character(char c) : m_char(c) {
std::cout << " [Creating flyweight for: '" << c << "']" << std::endl;
}
void display(char fontSize) override {
// 内部状态 + 外部状态 = 完整信息
std::cout << "Character '" << m_char << "' with font size " << fontSize << std::endl;
}
};
// 工厂:管理享元池
class CharacterFactory {
std::unordered_map<char, CharacterFlyweight*> m_pool;
CharacterFlyweight* getCharacter(char c) {
if (m_pool.find(c) == m_pool.end()) {
m_pool[c] = new Character(c); // 不存在则创建
}
return m_pool[c]; // 存在则复用
}
};
6.6 对比表
优化方式
减少
适用场景
享元模式
对象数量
大量重复对象
对象池模式
分配开销
连接池、线程池
单例模式
对象数量
全局唯一
6.7 面试追问 FAQ
问题
回答
内部状态和外部状态?
内部状态可共享,外部状态随场景变化
享元模式线程安全?
工厂需要加锁保护池
何时用享元模式?
对象数量大且可共享时,如文本编辑器字符
七、总结
7.1 模式对比总表
模式
结构类型
核心目的
关键词
装饰器
结构型
动态增加职责
包装、嵌套
组合
结构型
树形结构一致处理
递归、整体-部分
桥接
结构型
分离抽象与实现
解耦、独立变化
代理
结构型
控制对象访问
控制、延迟
外观
结构型
封装子系统复杂接口
简化、统一
享元
结构型
共享细粒度对象
内部状态、池化
7.2 设计模式分类速查
复制代码
创建型(5个)
单例、工厂、抽象工厂、建造者、原型
结构型(7个)
代理、装饰、桥接、组合、外观、享元、适配器
行为型(11个)
策略、命令、职责链、状态、观察者、中介者、迭代器、模板方法、访问者、解释器、备忘录
7.3 选用指南
场景
推荐模式
希望动态给对象增加功能
装饰器
处理树形结构,一致性操作
组合
抽象和实现需要独立扩展
桥接
延迟加载大对象
代理
封装复杂子系统
外观
大量重复对象共享
享元
根据零声教育教学写作https://github.com/0voice