Chemmy's Blog

chengming0916@outlook.com

桥接模式(Bridge Pattern)是结构型设计模式的核心成员之一,其核心设计思想是将抽象部分与它的实现部分分离,使两者能够独立地定义、扩展,互不干扰。这种模式摒弃了传统继承带来的强耦合问题,通过“组合替代继承”的方式,让抽象维度与实现维度可以沿着各自的方向灵活迭代,是解决多维度扩展、避免继承体系臃肿的关键设计方案。

一、桥接模式核心结构

桥接模式的设计核心的是“解耦双维度”,通过四个角色的分工协作,实现抽象与实现的分离,确保两个维度可独立扩展,各角色职责清晰、边界明确:

  • 抽象化(Abstraction):定义抽象层的核心接口,同时持有一个指向实现化对象的引用,是“抽象维度”的顶层抽象,负责封装抽象层的通用逻辑,不直接依赖具体实现。

  • 扩展抽象化(Refined Abstraction):继承或实现抽象化接口,是抽象维度的具体扩展,在抽象层基础上增加特定业务逻辑,无需关注实现层的具体细节。

  • 实现化(Implementor):定义实现层的核心接口,仅声明实现层的基础方法,供扩展抽象化调用,是“实现维度”的顶层规范,与抽象层解耦。

  • 具体实现化(Concrete Implementor):实现实现化接口,是实现维度的具体落地,负责提供底层的实现逻辑,可独立扩展新的实现方式,无需修改抽象层代码。

核心逻辑拆解:抽象维度通过持有实现维度的引用,间接调用实现维度的方法,实现“抽象依赖实现、实现不依赖抽象”的解耦效果。当需要扩展时,可单独新增抽象维度的扩展类(如新增智能遥控器)或实现维度的具体类(如新增投影仪),无需修改原有代码,完全符合“开闭原则”。

二、多语言实现桥接模式

桥接模式的核心是“双维度分离与组合”,不同语言因语法特性差异,实现方式略有不同,但核心逻辑高度统一。以下基于“设备控制”的统一场景(遥控器_抽象维度_与设备_实现维度_的桥接),实现C#、Python、Golang、C++、纯C五种语言的完整可运行案例,清晰呈现各语言的适配方式。

2.1 C# 实现(面向对象标准实现)

C# 作为强类型面向对象语言,通过接口清晰界定实现化规范,通过抽象类定义抽象层,依托继承与组合完成桥接,代码结构严谨,贴合企业级开发规范。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
using System;
using System.Threading;

// 实现化接口(Implementor):设备的核心操作规范
public interface IDevice
{
// 设备开机方法
void TurnOn();
// 设备关机方法
void TurnOff();
}

// 具体实现化1:电视(设备维度的具体实现)
public class TV : IDevice
{
public void TurnOn() => Console.WriteLine("电视已开机,正在加载节目...");
public void TurnOff() => Console.WriteLine("电视已关机,已保存观看记录\n");
}

// 具体实现化2:空调(设备维度的扩展实现)
public class AirConditioner : IDevice
{
public void TurnOn() => Console.WriteLine("空调已开机,正在调节至26℃...");
public void TurnOff() => Console.WriteLine("空调已关机,已关闭节能模式\n");
}

// 抽象化(Abstraction):遥控器的抽象层,持有设备引用
public abstract class RemoteControl
{
// 持有实现化对象的引用,建立抽象与实现的桥接
protected IDevice _device;

// 构造函数注入设备,实现松耦合
public RemoteControl(IDevice device)
{
_device = device;
}

// 抽象方法:遥控器核心操作(由扩展抽象化实现)
public abstract void PowerOperation();
}

// 扩展抽象化:普通遥控器(抽象维度的具体实现)
public class BasicRemote : RemoteControl
{
public BasicRemote(IDevice device) : base(device) { }

// 实现抽象方法,封装遥控器的操作逻辑
public override void PowerOperation()
{
Console.WriteLine("执行普通遥控器电源操作:");
_device.TurnOn();
Thread.Sleep(1000); // 模拟设备运行1秒
_device.TurnOff();
}
}

// 客户端调用:仅关注抽象层与实现层的组合,无需感知桥接细节
class Program
{
static void Main()
{
// 组合1:普通遥控器 + 电视
IDevice tv = new TV();
RemoteControl tvRemote = new BasicRemote(tv);
tvRemote.PowerOperation();

// 组合2:普通遥控器 + 空调
IDevice ac = new AirConditioner();
RemoteControl acRemote = new BasicRemote(ac);
acRemote.PowerOperation();
}
}

2.2 Python 实现(动态语言简洁实现)

Python 遵循“鸭子类型”,无需显式定义接口,通过类的继承模拟抽象层与实现层,依托组合建立桥接关系,代码简洁灵活,无需繁琐的类型声明,适配快速开发场景。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
import time

# 实现化类(Implementor):设备的抽象基类,定义实现层规范
class Device:
def turn_on(self):
"""设备开机方法,由具体设备实现"""
raise NotImplementedError("具体设备需实现开机方法")

def turn_off(self):
"""设备关机方法,由具体设备实现"""
raise NotImplementedError("具体设备需实现关机方法")

# 具体实现化1:电视
class TV(Device):
def turn_on(self):
print("电视已开机,正在加载节目...")

def turn_off(self):
print("电视已关机,已保存观看记录\n")

# 具体实现化2:空调
class AirConditioner(Device):
def turn_on(self):
print("空调已开机,正在调节至26℃...")

def turn_off(self):
print("空调已关机,已关闭节能模式\n")

# 抽象化类(Abstraction):遥控器抽象层,持有设备引用
class RemoteControl:
def __init__(self, device):
# 组合设备对象,建立桥接
self.device = device

def power_operation(self):
"""遥控器核心操作,由扩展抽象化实现"""
raise NotImplementedError("具体遥控器需实现电源操作方法")

# 扩展抽象化:普通遥控器
class BasicRemote(RemoteControl):
def power_operation(self):
print("执行普通遥控器电源操作:")
self.device.turn_on()
time.sleep(1) # 模拟设备运行1秒
self.device.turn_off()

# 客户端调用:灵活组合抽象与实现
if __name__ == "__main__":
# 组合1:普通遥控器控制电视
tv = TV()
tv_remote = BasicRemote(tv)
tv_remote.power_operation()

# 组合2:普通遥控器控制空调
ac = AirConditioner()
ac_remote = BasicRemote(ac)
ac_remote.power_operation()

2.3 Go 实现(组合优于继承的极简实现)

Go 语言无类和继承概念,核心遵循“组合优于继承”的设计哲学,通过接口定义实现化规范,通过结构体组合建立抽象与实现的桥接,贴合Go语言极简、高效的开发理念。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
package main

import (
mt"
time"
)

// 实现化接口(Implementor):设备操作接口
type Device interface {
rnOn() // 开机方法
TurnOff() // 关机方法
}

// 具体实现化1:电视
type TV struct{}

// 实现Device接口的开机方法
func (t *TV) TurnOn() {
Println("电视已开机,正在加载节目...")
}

// 实现Device接口的关机方法
func (t *TV) TurnOff() {
ftln("电视已关机,已保存观看记录\n")
}

// 具体实现化2:空调
type AirConditioner struct{}

// 实现Device接口的开机方法
func (a *AirConditioner) TurnOn() {
mt.Println("空调已开机,正在调节至26℃...")
}

// 实现Device接口的关机方法
func (a *AirConditioner) TurnOff() {
Println("空调已关机,已关闭节能模式\n")
}

// 抽象化结构体(Abstraction):遥控器抽象层,组合设备接口
type RemoteControl struct {
evice Device // 持有实现化接口引用,建立桥接
}

// 扩展抽象化:普通遥控器,组合抽象化结构体
type BasicRemote struct {
RemoteControl // 嵌入结构体,实现抽象层的继承效果
}

// 扩展抽象化的核心操作方法
func (b *BasicRemote) PowerOperation() {
fmt.Println("执行普通遥控器电源操作:")
b.device.TurnOn()
ime.Sleep(1 * time.Second) // 模拟设备运行1秒
.device.TurnOff()
}

// 客户端调用:通过接口组合,实现灵活适配
func main() {
/ 组合1:普通遥控器 + 电视
tv := &TV{}
tvRemote := &BasicRemote{RemoteControl{device: tv}}
tvRemote.PowerOperation()

/ 组合2:普通遥控器 + 空调
&AirConditioner{}
cRemote := &BasicRemote{RemoteControl{device: ac}}
Remote.PowerOperation()
}
ac a ac := / / b t d fmt. fmt.Prin fmt. Tu " "f

2.4 C++ 实现(面向对象经典实现)

C++ 作为经典面向对象语言,通过纯虚函数定义抽象接口(抽象化与实现化),依托类继承实现扩展,通过指针持有实现化对象,完成桥接逻辑,兼顾灵活性与性能,适配底层开发场景。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
#include <iostream>
#include <chrono>
#include <thread>

// 实现化接口(Implementor):设备操作抽象接口
class Device {
public:
// 纯虚函数,定义设备开机规范
virtual void turnOn() = 0;
// 纯虚函数,定义设备关机规范
virtual void turnOff() = 0;
// 虚析构函数,避免析构时内存泄漏
virtual ~Device() = default;
};

// 具体实现化1:电视
class TV : public Device {
public:
void turnOn() override {
std::cout << "电视已开机,正在加载节目..." << std::endl;
}
void turnOff() override {
std::cout << "电视已关机,已保存观看记录\n" << std::endl;
}
};

// 具体实现化2:空调
class AirConditioner : public Device {
public:
void turnOn() override {
std::cout << "空调已开机,正在调节至26℃..." << std::endl;
}
void turnOff() override {
std::cout << "空调已关机,已关闭节能模式\n" << std::endl;
}
};

// 抽象化类(Abstraction):遥控器抽象层
class RemoteControl {
protected:
Device* device; // 持有实现化对象指针,建立桥接
public:
// 构造函数注入设备
RemoteControl(Device* dev) : device(dev) {}
// 虚析构函数
virtual ~RemoteControl() = default;
// 纯虚函数,定义遥控器核心操作
virtual void powerOperation() = 0;
};

// 扩展抽象化:普通遥控器
class BasicRemote : public RemoteControl {
public:
BasicRemote(Device* dev) : RemoteControl(dev) {}
// 实现核心操作方法
void powerOperation() override {
std::cout << "执行普通遥控器电源操作:" << std::endl;
device->turnOn();
// 模拟设备运行1秒
std::this_thread::sleep_for(std::chrono::seconds(1));
device->turnOff();
}
};

// 客户端调用:管理抽象与实现的组合,释放内存
int main() {
// 组合1:普通遥控器 + 电视
Device* tv = new TV();
RemoteControl* tvRemote = new BasicRemote(tv);
tvRemote->powerOperation();

// 组合2:普通遥控器 + 空调
Device* ac = new AirConditioner();
RemoteControl* acRemote = new BasicRemote(ac);
acRemote->powerOperation();

// 释放内存,避免泄漏
delete tvRemote;
delete tv;
delete acRemote;
delete ac;

return 0;
}

2.5 纯C语言实现(结构体+函数指针模拟实现)

纯C语言无面向对象特性,通过“结构体封装数据+函数指针模拟接口”,模拟抽象化与实现化的分离,依托结构体嵌套和函数指针赋值,建立桥接关系,代码虽冗余但底层可控,适配嵌入式、底层开发场景。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
#include <stdio.h>
#include <unistd.h>

// 实现化结构体(模拟Implementor接口):设备操作规范
typedef struct Device {
void (*turn_on)(struct Device*); // 开机函数指针
void (*turn_off)(struct Device*); // 关机函数指针
} Device;

// 具体实现化1:电视(嵌入Device结构体,实现设备接口)
typedef struct TV {
Device device; // 嵌套实现化结构体,建立桥接基础
} TV;

// 电视的开机实现
void tv_turn_on(Device* dev) {
printf("电视已开机,正在加载节目...\n");
}

// 电视的关机实现
void tv_turn_off(Device* dev) {
printf("电视已关机,已保存观看记录\n\n");
}

// 初始化电视:绑定函数指针,实现设备接口
void tv_init(TV* tv) {
tv->device.turn_on = tv_turn_on;
tv->device.turn_off = tv_turn_off;
}

// 具体实现化2:空调(嵌入Device结构体)
typedef struct AirConditioner {
Device device; // 嵌套实现化结构体
} AirConditioner;

// 空调的开机实现
void ac_turn_on(Device* dev) {
printf("空调已开机,正在调节至26℃...\n");
}

// 空调的关机实现
void ac_turn_off(Device* dev) {
printf("空调已关机,已关闭节能模式\n\n");
}

// 初始化空调:绑定函数指针
void ac_init(AirConditioner* ac) {
ac->device.turn_on = ac_turn_on;
ac->device.turn_off = ac_turn_off;
}

// 抽象化结构体(模拟Abstraction):遥控器抽象层
typedef struct RemoteControl {
Device* device; // 持有实现化结构体指针,建立桥接
void (*power_operation)(struct RemoteControl*); // 核心操作函数指针
} RemoteControl;

// 扩展抽象化:普通遥控器的核心操作实现
void basic_remote_power_operation(RemoteControl* remote) {
printf("执行普通遥控器电源操作:\n");
remote->device->turn_on(remote->device);
sleep(1); // 模拟设备运行1秒
remote->device->turn_off(remote->device);
}

// 初始化遥控器:绑定设备和核心操作方法
void remote_control_init(RemoteControl* remote, Device* dev) {
remote->device = dev;
remote->power_operation = basic_remote_power_operation;
}

// 客户端调用:手动组合抽象与实现,完成桥接逻辑
int main() {
// 组合1:普通遥控器 + 电视
TV tv;
tv_init(&tv);
RemoteControl tv_remote;
remote_control_init(&tv_remote, (Device*)&tv);
tv_remote.power_operation(&tv_remote);

// 组合2:普通遥控器 + 空调
AirConditioner ac;
ac_init(&ac);
RemoteControl ac_remote;
remote_control_init(&ac_remote, (Device*)&ac);
ac_remote.power_operation(&ac_remote);

return 0;
}

三、桥接模式的优缺点

桥接模式的核心价值的是“解耦双维度、优化扩展能力”,其优缺点均围绕这一核心展开,需结合系统复杂度和扩展需求权衡使用,避免过度设计。

3.1 核心优点

  • 彻底解耦抽象与实现:抽象层与实现层完全分离,两者可独立迭代,新增抽象维度或实现维度无需修改原有代码,符合“开闭原则”,降低系统维护成本。

  • 避免继承爆炸:解决了多维度扩展带来的继承体系臃肿问题(例如“遥控器类型×设备类型”的组合,若用继承会产生大量子类),通过组合实现更灵活的扩展。

  • 提升系统扩展性:抽象维度和实现维度可单独扩展,例如新增“语音遥控器”(扩展抽象化)无需修改设备代码,新增“投影仪”(具体实现化)无需修改遥控器代码。

  • 符合合成复用原则:优先使用对象组合而非继承,降低代码耦合度,提升代码的可复用性和可维护性。

  • 支持动态切换实现:可在运行时动态更换实现化对象,例如遥控器可切换控制电视、空调等不同设备,灵活性极高。

3.2 主要缺点

  • 增加系统复杂度:引入抽象层、实现层及桥接关系,会增加代码量和类/结构体数量,简单场景下会提升理解成本和开发成本。

  • 设计门槛较高:需要提前精准识别系统中的“抽象维度”和“实现维度”,对设计人员的架构能力要求较高,若维度划分不当,反而会导致代码更难维护。

  • 间接调用带来轻微性能损耗:抽象层通过引用/指针调用实现层方法,存在少量间接调用开销(通常可忽略,仅在高频调用场景下需关注)。

四、桥接模式的使用场景

桥接模式的核心适用场景是“系统存在两个及以上独立变化的维度”,且需要长期扩展,具体场景如下:

  • 系统存在双独立扩展维度:例如“产品类型(抽象)与产品品牌(实现)”“UI组件(抽象)与渲染引擎(实现)”“遥控器(抽象)与设备(实现)”,两者需独立扩展。

  • 避免继承体系臃肿:当一个类的扩展方向超过一个时,继承会导致子类数量呈指数级增长(继承爆炸),桥接模式可通过组合替代继承,简化架构。

  • 抽象与实现需解耦:例如跨平台开发中,“业务逻辑(抽象)”与“平台API(实现)”分离,适配不同操作系统(Windows、Linux、Mac),无需修改业务逻辑代码。

  • 需要动态切换实现:需在运行时灵活切换对象的实现方式,例如视频播放器的“播放逻辑(抽象)”与“解码方式(实现)”,可动态切换硬解码、软解码。

  • 复用现有实现:已有多个实现类,需在不修改其代码的前提下,为其提供统一的抽象接口,实现多实现的统一调用。

典型实战案例

  • 图形界面框架:“窗口样式(抽象维度:普通窗口、弹窗、全屏窗口)”与“底层渲染(实现维度:DirectX、OpenGL、CPU渲染)”分离,支持灵活扩展。

  • 数据库驱动:“数据库操作接口(抽象维度:查询、插入、删除)”与“不同数据库适配(实现维度:MySQL、PostgreSQL、Oracle)”分离,统一操作接口。

  • 外设控制库:“控制逻辑(抽象维度:普通控制、智能控制)”与“外设协议(实现维度:蓝牙、WiFi、红外)”分离,适配不同类型外设。

  • 日志框架:“日志操作(抽象维度:普通日志、异步日志)”与“日志输出方式(实现维度:文件输出、控制台输出、远程上报)”分离,支持动态切换输出方式。

五、总结

桥接模式的核心是“分离抽象与实现,通过组合实现解耦”,其本质是打破继承的强耦合枷锁,让两个独立变化的维度能够自由扩展、互不干扰。它不是为了简化代码,而是为了优化系统架构,提升系统的可扩展性和可维护性,尤其适用于复杂系统的多维度扩展场景。

从多语言实现来看,尽管语法形式差异显著,但核心逻辑高度统一,且适配不同语言的设计理念:

  • 面向对象语言(C#、Python、C++):依托接口/抽象类定义双维度规范,通过继承扩展抽象层,通过组合建立桥接,代码结构清晰、易维护;

  • Go语言:遵循“组合优于继承”,通过接口定义实现化规范,通过结构体嵌套组合抽象层与实现层,极简且高效,贴合语言特性;

  • 纯C语言:通过结构体+函数指针模拟面向对象特性,手动实现双维度分离与桥接,底层可控,适配嵌入式等资源受限场景。

在工程实践中,使用桥接模式需注意两点:一是明确识别系统的双独立维度,避免维度划分不当导致的架构冗余;二是避免过度使用,简单场景(无多维度扩展需求)下,直接使用继承或组合更简洁。当系统需要长期扩展、存在多维度变化时,桥接模式是平衡扩展性与耦合度的最优设计方案之一,是每一位开发者必备的架构设计工具。

适配器模式(Adapter Pattern)是软件工程中经典的结构型设计模式,其核心价值在于解决接口不兼容问题——将一个类或模块的接口,转换为客户端期望的另一种接口,使得原本因接口差异无法协同工作的组件,能够无缝集成、正常交互。类比现实场景,电源适配器可让不同插头规格的电器适配统一插座,而适配器模式正是软件世界中的“接口转换器”,是系统集成、遗留代码改造的核心工具。

一、适配器模式核心结构

适配器模式的设计围绕“接口转换”展开,核心包含四个角色,各角色分工明确、协同完成适配逻辑,确保客户端与适配者的解耦:

  • 目标接口(Target):客户端期望的标准接口,定义了客户端可直接调用的方法规范,是客户端与系统交互的统一入口。

  • 适配者(Adaptee):现有系统中已存在的组件(类/模块),其功能符合需求,但接口格式与目标接口不兼容,是需要被适配的核心对象。

  • 适配器(Adapter):模式的核心角色,一边实现目标接口,一边持有适配者的引用,负责将客户端的请求转换为适配者能识别的调用,完成接口适配。

  • 客户(Client):仅依赖目标接口进行交互,无需感知适配者的存在,也无需关注接口转换的细节,实现与适配者的完全解耦。

根据实现方式的不同,适配器模式分为两类,适配不同语言特性与业务场景:

  • 类适配器:通过继承适配者、实现目标接口完成适配,依赖语言的多继承特性(如C++),耦合度略高,灵活性有限。

  • 对象适配器:通过组合方式持有适配者实例、实现目标接口完成适配,不依赖继承,耦合度低、灵活性高,是更通用的实现方式(如C#、Python、Go、纯C)。

二、多语言实现适配器模式

不同语言因语法特性(如继承机制、接口定义、动态特性)差异,适配器模式的实现方式各有侧重,但核心逻辑一致——通过适配器完成接口转换。以下基于“第三方组件集成”的统一场景(支付、日志组件适配),实现C#、Python、Golang、C++、纯C五种语言的完整案例,均可直接编译运行。

2.1 C# 实现(对象适配器)

C# 不支持多继承,因此优先采用对象适配器模式,依托接口定义目标规范,通过组合方式持有适配者实例,兼顾解耦性与代码可读性,贴合.NET开发规范。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
using System;

// 目标接口:客户端期望的统一支付接口
public interface IPayment
{
void Pay(double amount); // 统一支付方法,参数为支付金额
}

// 适配者:第三方支付宝SDK(接口不兼容,方法名、参数类型可能存在差异)
public class AlipaySDK
{
// 第三方SDK的支付方法,参数为decimal类型,方法名与目标接口不一致
public void DoAlipayPayment(decimal money)
{
Console.WriteLine($"支付宝支付:{money:F1} 元");
}
}

// 适配器:将AlipaySDK适配为IPayment接口,完成接口转换
public class AlipayAdapter : IPayment
{
// 组合适配者实例,实现松耦合
private readonly AlipaySDK _alipaySDK;

// 构造函数注入适配者,提升灵活性
public AlipayAdapter(AlipaySDK alipaySDK)
{
_alipaySDK = alipaySDK;
}

// 实现目标接口的Pay方法,完成参数转换与方法转发
public void Pay(double amount)
{
// 将客户端传入的double类型金额,转换为第三方SDK所需的decimal类型
_alipaySDK.DoAlipayPayment(Convert.ToDecimal(amount));
}
}

// 客户端调用:仅依赖目标接口,无需感知适配者细节
class Client
{
static void Main(string[] args)
{
// 初始化适配者与适配器
IPayment payment = new AlipayAdapter(new AlipaySDK());
// 客户端直接调用目标接口方法,适配逻辑被适配器封装
payment.Pay(100.5); // 输出:支付宝支付:100.5 元
}
}

2.2 Python 实现(对象适配器)

Python 是动态语言,无需显式定义接口(遵循“鸭子类型”),通过类的组合实现对象适配器,代码简洁灵活,无需繁琐的类型声明,适配快速开发场景。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
# 目标接口(约定):客户端期望的统一支付接口,定义pay方法
class PaymentTarget:
def pay(self, amount):
"""统一支付方法,子类需实现该方法"""
raise NotImplementedError("请实现pay方法以完成支付适配")

# 适配者:第三方微信支付SDK(接口不兼容,方法名与目标接口不一致)
class WeChatPaySDK:
def do_wechat_pay(self, money):
"""第三方微信支付方法"""
print(f"微信支付:{money:.1f} 元")

# 适配器:继承目标接口约定,组合适配者,完成接口转换
class WeChatPayAdapter(PaymentTarget):
def __init__(self, wechat_sdk):
# 组合适配者实例,实现松耦合
self.wechat_sdk = wechat_sdk

def pay(self, amount):
"""实现目标接口的pay方法,转发请求到适配者"""
self.wechat_sdk.do_wechat_pay(amount)

# 客户端调用:仅与目标接口交互,无需关注适配细节
if __name__ == "__main__":
# 初始化适配者与适配器
payment = WeChatPayAdapter(WeChatPaySDK())
# 调用统一支付方法
payment.pay(200.8) # 输出:微信支付:200.8 元

2.3 Go 实现(对象适配器)

Go 语言无类和继承概念,核心是“面向接口编程”,通过结构体组合适配者、实现目标接口完成适配,接口匹配遵循“鸭子类型”(只需方法签名一致),贴合Go语言极简、高效的设计哲学。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
package main

import "fmt"

// 目标接口:客户端期望的统一支付接口
type Payment interface {
amount float64) // 统一支付方法,参数为float64类型
}

// 适配者:第三方银联支付SDK(接口不兼容,参数类型与目标接口不一致)
type UnionPaySDK struct{}

// 第三方SDK的支付方法,参数为float32类型
func (u *UnionPaySDK) DoUnionPay(money float32) {
mt.Printf("银联支付:%.1f 元\n", money)
}

// 适配器:结构体组合适配者,实现目标接口
type UnionPayAdapter struct {
ionPay *UnionPaySDK // 持有适配者实例
}

// 实现目标接口的Pay方法,完成参数转换与请求转发
func (a *UnionPayAdapter) Pay(amount float64) {
户端传入的float64类型,转换为适配者所需的float32类型
.unionPay.DoUnionPay(float32(amount))
}

// 客户端调用:依赖目标接口,解耦适配者
func main() {
// 初始化适配器(注入适配者)
var payment Payment = &UnionPayAdapter{unionPay: &UnionPaySDK{}}
/ 调用统一支付方法
payment.Pay(300.6) // 输出:银联支付:300.6 元
}
/ a // 将客 un f Pay(

2.4 C++ 实现(类适配器+对象适配器)

C++ 支持多继承,可同时实现类适配器与对象适配器。类适配器通过继承适配者和目标接口完成适配,耦合度略高;对象适配器通过组合实现,更推荐使用。以下重点展示类适配器,兼顾两种实现的特性。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
#include <iostream>
#include <string>
using namespace std;

// 目标接口:客户端期望的统一日志接口
class LogTarget {
public:
// 纯虚函数,定义统一日志方法
virtual void Log(string msg) = 0;
// 虚析构函数,避免析构时内存泄漏
virtual ~LogTarget() = default;
};

// 适配者:第三方文件日志SDK(接口不兼容,方法参数与目标接口不一致)
class FileLogSDK {
public:
// 第三方日志方法,参数为const char*类型
void WriteFileLog(const char* message) {
cout << "文件日志:" << message << endl;
}
};

// 类适配器:继承目标接口和适配者,完成接口转换
class FileLogAdapter : public LogTarget, public FileLogSDK {
public:
// 实现目标接口的Log方法
void Log(string msg) override {
// 将string类型转换为const char*,调用适配者的日志方法
WriteFileLog(msg.c_str());
}
};

// 客户端调用:依赖目标接口,无需感知适配者
int main() {
LogTarget* logger = new FileLogAdapter();
logger->Log("系统启动成功,日志记录正常"); // 输出:文件日志:系统启动成功,日志记录正常
delete logger; // 释放内存,避免泄漏
return 0;
}

2.5 纯C语言实现(对象适配器)

纯C语言无类和接口概念,通过“结构体封装数据、函数指针模拟接口”,模拟面向对象的特性,实现对象适配器。核心是通过结构体组合适配者,用函数指针实现目标接口,手动完成请求转发,适配嵌入式、底层开发场景。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

// 目标接口:用函数指针模拟统一支付接口
typedef struct {
// 目标接口方法:参数为适配器实例和支付金额
void (*Pay)(void* adapter, float amount);
} PaymentInterface;

// 适配者:第三方苹果支付SDK(用结构体模拟“类”)
typedef struct {
char name[20]; // SDK版本信息
} ApplePaySDK;

// 适配者的支付方法(模拟类的成员方法)
void ApplePaySDK_DoPay(ApplePaySDK* sdk, float money) {
printf("苹果支付:%.1f 元(SDK版本:%s)\n", money, sdk->name);
}

// 适配器:结构体组合适配者,实现目标接口
typedef struct {
PaymentInterface interface; // 目标接口(函数指针)
ApplePaySDK* applePay; // 组合适配者实例
} ApplePayAdapter;

// 适配器的Pay方法实现(目标接口的具体逻辑)
void ApplePayAdapter_Pay(void* adapter, float amount) {
// 类型转换,获取适配器实例
ApplePayAdapter* adapterObj = (ApplePayAdapter*)adapter;
// 转发请求到适配者的支付方法
ApplePaySDK_DoPay(adapterObj->applePay, amount);
}

// 客户端调用:通过函数指针调用目标接口
int main() {
// 初始化适配者
ApplePaySDK* applePay = (ApplePaySDK*)malloc(sizeof(ApplePaySDK));
strcpy(applePay->name, "ApplePay v1.0");

// 初始化适配器:绑定目标接口方法,关联适配者
ApplePayAdapter* adapter = (ApplePayAdapter*)malloc(sizeof(ApplePayAdapter));
adapter->interface.Pay = ApplePayAdapter_Pay;
adapter->applePay = applePay;

// 客户端调用目标接口,无需关注适配细节
adapter->interface.Pay(adapter, 400.9); // 输出:苹果支付:400.9 元(SDK版本:ApplePay v1.0)

// 释放内存,避免泄漏
free(applePay);
free(adapter);
return 0;
}

三、适配器模式的优缺点

适配器模式的核心价值是“兼容旧接口、集成新组件”,其优缺点均围绕“接口转换”的核心逻辑展开,需结合业务场景权衡使用,避免过度设计。

3.1 核心优点

  • 解决接口兼容问题:无需修改原有适配者代码和客户端代码,即可实现不兼容接口的协同工作,完全符合“开闭原则”,降低系统改造风险。

  • 解耦客户端与适配者:客户端仅依赖目标接口,无需感知适配者的实现细节和接口差异,降低代码耦合度,提升系统可维护性。

  • 复用现有组件:无需为适配新接口重写现有组件逻辑,充分复用已有代码(如第三方SDK、遗留系统组件),减少开发工作量。

  • 灵活性高:可灵活替换不同的适配者,适配不同版本的第三方组件或遗留系统,无需修改客户端和目标接口,扩展成本低。

3.2 主要缺点

  • 增加系统复杂度:引入适配器类/结构体后,会增加系统的代码量和类结构复杂度,提升代码理解和维护成本。

  • 存在轻微性能损耗:适配过程中的参数转换、方法转发,会带来少量性能开销(通常可忽略,仅在高频调用场景下需关注)。

  • 类适配器局限性强:类适配器依赖多继承,耦合度高于对象适配器,且受限于语言的继承特性(如C#、Java不支持多继承),灵活性不足。

  • 适配逻辑维护成本高:若适配者接口发生变更,需同步修改适配器的转换逻辑,增加后期维护成本。

四、适配器模式的使用场景

适配器模式的核心适用场景是“接口不兼容但功能需复用”,尤其在系统集成、遗留代码改造、第三方组件引入等场景中,能发挥重要作用,具体如下:

  • 集成第三方组件:项目引入第三方SDK(如支付、日志、缓存、地图组件),其接口格式与项目现有接口不兼容,无需修改SDK源码,通过适配器完成适配。

  • 改造遗留系统:维护老旧系统时,需将遗留组件接入新的业务系统,无需重构遗留代码,通过适配器适配新系统的接口规范,降低改造风险。

  • 多版本接口兼容:同一功能存在多个版本的接口(如API v1/v2),通过适配器统一对外暴露的接口,让客户端无需感知版本差异,提升兼容性。

  • 跨语言交互:多语言协同开发的项目中,适配不同语言的接口规范(如C语言接口适配Go/Python的调用逻辑),实现跨语言组件的无缝集成。

  • 单元测试场景:单元测试中,适配测试桩(Mock对象)到目标接口,模拟第三方依赖的行为,确保测试用例的独立性和可执行性。

典型实战案例

  • 电商系统集成多种支付方式(支付宝、微信、银联),通过适配器统一支付接口,客户端无需区分支付类型;

  • 日志系统适配不同的日志组件(文件日志、控制台日志、第三方日志服务),通过适配器统一日志输出接口;

  • 旧系统迁移时,通过适配器让遗留模块适配新系统的接口,逐步替换旧组件,实现平滑过渡;

  • 框架开发中,适配不同的数据库驱动(MySQL、PostgreSQL、Oracle),统一数据库操作接口,提升框架兼容性。

五、总结

适配器模式的核心是“接口转换”,本质是通过一个中间层(适配器),屏蔽接口差异,实现不兼容组件的协同工作,其核心价值在于“兼容现有代码、降低集成成本”,是系统扩展和重构的重要工具。

从多语言实现来看,尽管语法形式差异显著,但核心逻辑高度统一,且适配不同语言的特性:

  • 面向对象语言(C#、Python、C++):依托类、接口、继承/组合实现适配,其中对象适配器因耦合度低、灵活性高,成为主流实现方式;

  • 静态语言(Go、C++、C#):需关注类型转换和接口匹配,代码严谨性高,适合高性能、企业级开发场景;

  • 动态语言(Python):无需显式定义接口,适配逻辑更简洁,适合快速开发、迭代场景;

  • 过程式语言(纯C):通过结构体+函数指针模拟面向对象特性,实现适配逻辑,代码冗余但底层可控,适合嵌入式、底层开发场景。

在工程实践中,使用适配器模式需注意两点:一是优先选择对象适配器,降低代码耦合度;二是避免过度使用——若接口差异过大,或适配逻辑过于复杂,重构接口可能比引入适配器更高效。适配器模式并非万能,但在接口兼容、组件集成场景中,能有效提升系统的复用性、扩展性和可维护性,是每一位开发者都应掌握的设计模式。

原型模式是一种创建型设计模式,其核心思想是通过复制已有对象(原型)来创建新对象,而非通过构造函数从头初始化。这种模式能有效减少重复初始化的开销,尤其适用于创建复杂对象或大量相似对象的场景。本文将从核心结构、多语言实现、优缺点、使用场景等维度全面解析原型模式。

一、原型模式核心结构

原型模式的核心包含两个关键角色,同时需重点区分浅拷贝与深拷贝,这是原型模式的核心要点:

1.1 核心角色

  • 抽象原型(Prototype):定义克隆自身的接口,通常包含一个Clone方法,声明对象拷贝的规范,是所有具体原型的公共约束。

  • 具体原型(Concrete Prototype):实现抽象原型的Clone方法,完成自身的拷贝逻辑,根据需求实现浅拷贝或深拷贝。

1.2 核心概念:浅拷贝与深拷贝

原型模式的核心差异的在于拷贝的深度,直接决定新旧对象的独立性:

  • 浅拷贝:仅复制对象本身及基本类型成员,引用类型成员(如指针、对象引用)仅复制引用地址,新旧对象共享同一引用对象,一方修改会影响另一方。

  • 深拷贝:完全复制对象及所有嵌套的引用类型成员,为每个引用类型成员重新分配内存并复制内容,新旧对象相互独立,修改互不影响。

二、多语言实现原型模式

不同语言因语法特性、内置工具差异,原型模式的实现方式各有侧重,以下结合C#、Python、Golang、C++、纯C五种语言,实现统一场景(拷贝包含引用类型成员的Person对象),清晰展示深浅拷贝的实现逻辑。

2.1 C# 实现(内置接口+序列化)

C# 内置ICloneable接口作为抽象原型,通过MemberwiseClone实现浅拷贝,深拷贝可借助序列化快速实现,无需手动处理嵌套引用,适配面向对象开发场景。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
using System;
using System.IO;
using System.Runtime.Serialization.Formatters.Binary;

// 抽象原型接口(复用系统内置ICloneable,简化开发)
public interface IPrototype : ICloneable { }

// 具体原型(包含引用类型成员)
[Serializable] // 深拷贝需添加序列化标记,否则无法序列化引用类型
public class Person : IPrototype
{
public string Name { get; set; }
public int Age { get; set; }
public Address Address { get; set; } // 引用类型成员(嵌套对象)

// 浅拷贝实现:调用系统内置方法,仅拷贝值类型和引用地址
public object Clone()
{
return this.MemberwiseClone(); // 内置浅拷贝方法,高效简洁
}

// 深拷贝实现:通过二进制序列化/反序列化,自动处理嵌套引用
public Person DeepClone()
{
using (var ms = new MemoryStream())
{
var formatter = new BinaryFormatter();
formatter.Serialize(ms, this); // 序列化对象
ms.Position = 0; // 重置流位置
return (Person)formatter.Deserialize(ms); // 反序列化生成新对象
}
}
}

// 引用类型成员(需同步添加序列化标记)
[Serializable]
public class Address
{
public string City { get; set; }
public string Street { get; set; }
}

// 测试代码(验证深浅拷贝效果)
class Program
{
static void Main()
{
// 初始化原型对象
var prototype = new Person
{
Name = "张三",
Age = 25,
Address = new Address { City = "北京", Street = "朝阳路" }
};

// 浅拷贝测试
var shallowCopy = (Person)prototype.Clone();
shallowCopy.Address.City = "上海"; // 修改引用成员
Console.WriteLine($"浅拷贝后原型地址:{prototype.Address.City}"); // 输出:上海(原型受影响)

// 深拷贝测试
var deepCopy = prototype.DeepClone();
deepCopy.Address.City = "广州"; // 修改引用成员
Console.WriteLine($"深拷贝后原型地址:{prototype.Address.City}"); // 输出:上海(原型不受影响)
}
}

2.2 Python 实现(内置copy模块)

Python 遵循“鸭子类型”,无需显式定义抽象原型接口,copy模块内置copy()(浅拷贝)和deepcopy()(深拷贝)方法,可直接复用,大幅简化代码,适配快速开发场景。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
import copy

# 引用类型:地址类
class Address:
def __init__(self, city, street):
self.city = city
self.street = street

# 具体原型类:人员类
class Person:
def __init__(self, name, age, address):
self.name = name # 基本类型
self.age = age # 基本类型
self.address = address # 引用类型成员

# 浅拷贝方法:复用copy模块
def shallow_clone(self):
return copy.copy(self)

# 深拷贝方法:复用copy模块,自动处理嵌套引用
def deep_clone(self):
return copy.deepcopy(self)

# 测试代码
if __name__ == "__main__":
# 初始化原型对象
prototype = Person("张三", 25, Address("北京", "朝阳路"))

# 浅拷贝验证
shallow_copy = prototype.shallow_clone()
shallow_copy.address.city = "上海"
print(f"浅拷贝后原型地址:{prototype.address.city}") # 输出:上海

# 深拷贝验证
deep_copy = prototype.deep_clone()
deep_copy.address.city = "广州"
print(f"深拷贝后原型地址:{prototype.address.city}") # 输出:上海

2.3 Golang 实现(结构体方法+序列化)

Golang 无类和继承,通过结构体模拟原型,浅拷贝可通过结构体值传递实现,深拷贝可借助JSON序列化实现通用逻辑,兼顾简洁性与性能,符合Go语言极简设计哲学。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
package main

import (
coding/json"
fmt"
)

// 引用类型:地址结构体
type Address struct {
y string
et string
}

// 具体原型:人员结构体
type Person struct {
e string
Age int
*Address // 指针类型(引用类型)
}

// 浅拷贝:结构体值传递,指针成员仅复制地址
func (p *Person) ShallowClone() *Person {
e := *p // 值拷贝,指针成员仍指向原地址
eturn &clone
}

// 深拷贝:通过JSON序列化/反序列化,通用且无需手动处理嵌套
func (p *Person) DeepClone() (*Person, error) {
序列化原对象
data, err := json.Marshal(p)
r != nil {
eturn nil, err
序列化生成新对象
r clone Person
ern.Unmarshal(data, &clone)
f err != nil {
return nil, err
turn &clone, nil
}

func main() {
/ 初始化原型对象
prototype := &Person{
Name: "张三",
ge: 25,
ddress: &Address{
City: "北京",
treet: "朝阳路",
}

/ 浅拷贝测试
shallowCopy := prototype.ShallowClone()
shallowCopy.Address.City = "上海"
fmt.Printf("浅拷贝后原型地址:%s\n", prototype.Address.City) // 输出:上海

/ 深拷贝测试
pCopy, _ := prototype.DeepClone()
deepCopy.Address.City = "广州"
fmt.Printf("深拷贝后原型地址:%s\n", prototype.Address.City) // 输出:上海
}
dee / / },
S A A / }
re ir = jso va}
// 反 r if er // r clonAddress Nam Stre Cit " "en

2.4 C++ 实现(拷贝构造函数)

C++ 通过拷贝构造函数实现原型模式,默认拷贝构造为浅拷贝,深拷贝需手动重载拷贝构造函数或自定义克隆方法,需注意内存管理,避免内存泄漏,适配高性能底层开发场景。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
#include <iostream>
#include <string>
using namespace std;

// 引用类型:地址类
class Address {
public:
string city;
string street;
// 构造函数
Address(string c, string s) : city(c), street(s) {}
};

// 具体原型:人员类
class Person {
private:
string name;
int age;
Address* address; // 指针(引用类型)
public:
// 构造函数
Person(string n, int a, Address* addr) : name(n), age(a), address(addr) {}

// 浅拷贝构造函数(默认行为,仅复制指针)
Person(const Person& other) {
this->name = other.name;
this->age = other.age;
this->address = other.address; // 共享指针,浅拷贝
}

// 深拷贝方法:手动创建新的引用对象,实现完全拷贝
Person* DeepClone() {
Address* newAddr = new Address(this->address->city, this->address->street);
return new Person(this->name, this->age, newAddr);
}

// 析构函数:释放内存,避免泄漏
~Person() {
delete address;
}

// 辅助方法:修改地址城市
void setCity(string c) {
this->address->city = c;
}

// 辅助方法:获取地址城市
string getCity() {
return this->address->city;
}
};

// 测试代码
int main() {
// 初始化原型对象
Address* addr = new Address("北京", "朝阳路");
Person* prototype = new Person("张三", 25, addr);

// 浅拷贝测试
Person shallowCopy = *prototype; // 调用浅拷贝构造函数
shallowCopy.setCity("上海");
cout << "浅拷贝后原型地址:" << prototype->getCity() << endl; // 输出:上海

// 深拷贝测试
Person* deepCopy = prototype->DeepClone();
deepCopy->setCity("广州");
cout << "深拷贝后原型地址:" << prototype->getCity() << endl; // 输出:上海

// 释放内存
delete prototype;
delete deepCopy;
return 0;
}

2.5 纯C语言实现(结构体+函数模拟)

纯C语言无面向对象特性,通过结构体封装数据,函数模拟克隆行为,深浅拷贝均需手动处理指针和内存分配,代码冗余但底层可控,适配嵌入式、底层开发场景。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

// 引用类型:地址结构体
typedef struct {
char* city;
char* street;
} Address;

// 具体原型:人员结构体
typedef struct {
char* name;
int age;
Address* address;
} Person;

// 工具函数:初始化Address
Address* address_init(const char* city, const char* street) {
Address* addr = (Address*)malloc(sizeof(Address));
addr->city = (char*)malloc(strlen(city) + 1);
strcpy(addr->city, city);
addr->street = (char*)malloc(strlen(street) + 1);
strcpy(addr->street, street);
return addr;
}

// 工具函数:初始化Person
Person* person_init(const char* name, int age, Address* addr) {
Person* p = (Person*)malloc(sizeof(Person));
p->name = (char*)malloc(strlen(name) + 1);
strcpy(p->name, name);
p->age = age;
p->address = addr;
return p;
}

// 浅拷贝函数:仅复制结构体,共享指针成员
Person* person_shallow_clone(Person* p) {
Person* clone = (Person*)malloc(sizeof(Person));
clone->name = p->name; // 共享字符串指针
clone->age = p->age; // 复制基本类型
clone->address = p->address; // 共享Address指针
return clone;
}

// 深拷贝函数:手动复制所有指针成员,分配新内存
Person* person_deep_clone(Person* p) {
// 深拷贝Address
Address* newAddr = (Address*)malloc(sizeof(Address));
newAddr->city = (char*)malloc(strlen(p->address->city) + 1);
strcpy(newAddr->city, p->address->city);
newAddr->street = (char*)malloc(strlen(p->address->street) + 1);
strcpy(newAddr->street, p->address->street);

// 深拷贝Person
Person* clone = (Person*)malloc(sizeof(Person));
clone->name = (char*)malloc(strlen(p->name) + 1);
strcpy(clone->name, p->name);
clone->age = p->age;
clone->address = newAddr;
return clone;
}

// 工具函数:释放Person内存
void person_free(Person* p) {
free(p->name);
free(p->address->city);
free(p->address->street);
free(p->address);
free(p);
}

// 测试代码
int main() {
// 初始化原型对象
Address* addr = address_init("北京", "朝阳路");
Person* prototype = person_init("张三", 25, addr);

// 浅拷贝测试
Person* shallowCopy = person_shallow_clone(prototype);
// 修改浅拷贝对象的引用成员(需先释放原内存,避免内存泄漏)
free(shallowCopy->address->city);
shallowCopy->address->city = (char*)malloc(strlen("上海") + 1);
strcpy(shallowCopy->address->city, "上海");
printf("浅拷贝后原型地址:%s\n", prototype->address->city); // 输出:上海

// 深拷贝测试
Person* deepCopy = person_deep_clone(prototype);
free(deepCopy->address->city);
deepCopy->address->city = (char*)malloc(strlen("广州") + 1);
strcpy(deepCopy->address->city, "广州");
printf("深拷贝后原型地址:%s\n", prototype->address->city); // 输出:上海

// 释放内存
person_free(prototype);
free(shallowCopy); // 浅拷贝仅释放结构体,不释放共享指针
person_free(deepCopy);

return 0;
}

三、原型模式的优缺点

原型模式的价值与局限均围绕“拷贝替代创建”的核心逻辑,需结合场景权衡使用,避免过度设计。

3.1 核心优点

  • 降低对象创建开销:对于初始化成本高的对象(如数据库连接、大文件解析、复杂计算对象),拷贝比重新初始化更高效,减少重复操作。

  • 简化对象创建逻辑:无需关注构造函数的参数、访问权限等限制,直接复制已有原型对象,降低创建复杂度,提升开发效率。

  • 支持动态扩展:可在运行时动态修改原型对象,生成不同变体的新对象,无需修改原有代码,符合“开闭原则”。

  • 保护原型状态:深拷贝可保留原型对象的初始状态,新对象的修改不会影响原型,适用于需要基准模板的场景。

3.2 主要缺点

  • 深拷贝实现复杂:嵌套引用类型越多,深拷贝逻辑越繁琐,易出现内存泄漏(如C/C++)、循环引用(如Python)等问题,增加开发难度。

  • 维护成本较高:当原型对象的属性或结构发生变更时,需同步修改拷贝逻辑(尤其是深拷贝),否则会出现拷贝不完整的问题。

  • 性能损耗差异:深拷贝涉及大量内存复制,在高频拷贝、大对象拷贝场景下,性能损耗明显高于浅拷贝和直接创建。

  • 非面向对象语言适配差:纯C等无面向对象特性的语言,需手动模拟原型结构和拷贝逻辑,代码冗余度高,维护不便。

四、原型模式的使用场景

原型模式的核心适用场景是“对象创建成本高、需批量生成相似对象”,同时需根据引用类型的存在与否,选择浅拷贝或深拷贝。

  • 对象创建成本高:如创建包含大量数据的缓存对象、需频繁读取文件/数据库的配置对象、经过复杂计算初始化的对象。

  • 批量生成相似对象:如游戏中的角色、粒子系统、NPC,电商系统中的批量订单,仅属性略有差异,通过拷贝原型可快速生成。

  • 动态生成对象变体:如根据模板生成不同主题的UI组件、不同配置的接口请求对象,无需重复编写初始化逻辑。

  • 避免构造函数耦合:当对象构造逻辑复杂,且创建逻辑需与业务逻辑隔离时,拷贝原型可降低代码耦合度。

  • 浅拷贝适用场景:对象无引用类型成员,或引用成员为只读数据、无需独立修改,追求拷贝效率。

  • 深拷贝适用场景:对象包含嵌套引用类型,且新旧对象需完全独立(如多线程操作、对象修改不影响原型、需保留基准状态)。

典型实战案例

  • 设计工具的“复制粘贴”功能(如PS图层、Axure组件),本质是原型模式的浅拷贝/深拷贝应用;

  • 数据库连接池中的连接对象克隆,避免频繁创建/关闭连接,提升数据库访问性能;

  • 序列化/反序列化场景(如JSON、二进制序列化),核心是深拷贝的实现,用于对象传输、持久化;

  • 游戏开发中的角色实例生成,通过原型拷贝快速创建大量相似角色,仅修改属性(如血量、攻击力)。

五、总结

原型模式以“拷贝替代创建”为核心,核心价值在于平衡对象创建的性能与复杂度,其核心难点是深浅拷贝的选择与实现。不同语言的实现方式,反映了语言本身的设计理念和适用场景:

  • 高级面向对象语言(C#、Python):提供内置工具(接口、模块)简化拷贝逻辑,深拷贝可通过序列化快速实现,开发效率高;

  • 静态语言(Golang):通过结构体方法+序列化实现通用拷贝,兼顾简洁性与性能,贴合语言极简特性;

  • 编译型语言(C++):需手动管理拷贝构造函数和内存,深拷贝实现灵活但易出错,适配高性能底层开发;

  • 纯C语言:通过结构体+函数模拟原型模式,代码冗余但底层可控,适用于嵌入式等资源受限场景。

在工程实践中,原型模式并非万能,需注意:浅拷贝虽高效但存在数据共享风险,深拷贝虽安全但性能开销较高;当对象结构简单、创建成本低时,直接使用构造函数更简洁。原型模式可与工厂模式、单例模式协同使用(如单例管理原型对象,工厂负责克隆分发),最大化发挥其价值,成为优化复杂对象创建流程的重要工具。

在软件开发中,创建复杂对象往往需要经历多个步骤,且不同场景下对象的组件配置、构建顺序可能存在差异。建造者模式(Builder Pattern)作为经典的创建型设计模式,核心价值在于将复杂对象的构建过程与最终表示分离,让相同的构建流程能生成不同的产品形态,同时屏蔽底层构建细节,大幅提升代码的灵活性与可维护性。

一、建造者模式核心结构

建造者模式通过分层设计解耦对象构建逻辑,其经典结构包含5个核心角色,各角色分工明确、协同完成复杂对象的创建,确保构建过程的规范性与灵活性。

1.1 核心角色及职责

角色 核心职责
产品(Product) 待构建的复杂对象,由多个组件/部分组成(如电脑包含CPU、内存、硬盘等核心组件)。
抽象建造者(Builder) 定义构建产品各组件的抽象接口,声明“构建组件”和“获取产品”的核心方法,为所有具体建造者提供统一规范。
具体建造者(ConcreteBuilder) 实现抽象建造者的接口,完成产品各组件的具体构建逻辑,内部持有最终构建的产品实例,负责组件的组装与初始化。
指挥者(Director) 控制构建流程的执行顺序,调用具体建造者的方法完成对象构建,隔离客户端与底层构建细节,确保流程的一致性。
客户端(Client) 创建指挥者和具体建造者实例,通过指挥者触发构建流程,无需关注构建细节,最终获取成品对象。

1.2 核心设计思想

建造者模式的核心逻辑的是“分离构建与表示”:客户端只需指定具体建造者的类型,指挥者便会按照预设流程调用建造者的组件构建方法,无需关注组件如何组装、顺序如何安排,即可生成不同配置的产品。这种设计既保证了构建流程的规范性,又实现了产品变体的灵活扩展。

二、多语言实现建造者模式

为便于跨语言对比理解,本文以“构建不同配置的电脑”为统一场景(产品:电脑;具体建造者:游戏电脑建造者、办公电脑建造者;指挥者:电脑组装指挥者),分别通过C#、Python、Golang、C++、纯C语言实现建造者模式,贴合各语言特性与工程实践规范,所有代码均可直接编译运行。

2.1 C# 实现(抽象类+继承,经典面向对象落地)

C#作为强类型面向对象语言,完全契合建造者模式的经典类结构,通过抽象类定义建造规范,子类实现具体构建逻辑,具备良好的类型安全性和代码可读性,适合企业级系统开发。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
using System;

// 产品:电脑(封装核心组件)
public class Computer
{
public string CPU { get; set; }
public string RAM { get; set; }
public string HardDisk { get; set; }

// 重写ToString,便于展示产品配置
public override string ToString()
{
return $"电脑配置:CPU={CPU},内存={RAM},硬盘={HardDisk}";
}
}

// 抽象建造者:定义电脑构建的统一接口
public abstract class ComputerBuilder
{
protected Computer _computer = new Computer(); // 持有产品实例,供子类操作
public abstract void BuildCPU(); // 构建CPU组件
public abstract void BuildRAM(); // 构建内存组件
public abstract void BuildHardDisk(); // 构建硬盘组件
public Computer GetComputer() => _computer; // 返回构建完成的产品
}

// 具体建造者1:游戏电脑建造者(高性能配置)
public class GamingComputerBuilder : ComputerBuilder
{
public override void BuildCPU() => _computer.CPU = "Intel i9-14900K";
public override void BuildRAM() => _computer.RAM = "32GB DDR5 6400";
public override void BuildHardDisk() => _computer.HardDisk = "2TB NVMe PCIe4.0";
}

// 具体建造者2:办公电脑建造者(高性价比配置)
public class OfficeComputerBuilder : ComputerBuilder
{
public override void BuildCPU() => _computer.CPU = "Intel i5-13400";
public override void BuildRAM() => _computer.RAM = "16GB DDR4 3200";
public override void BuildHardDisk() => _computer.HardDisk = "1TB SATA3 SSD";
}

// 指挥者:控制电脑构建的流程顺序
public class ComputerDirector
{
// 统一构建流程,屏蔽底层实现细节
public Computer Construct(ComputerBuilder builder)
{
builder.BuildCPU(); // 优先构建核心CPU
builder.BuildRAM(); // 其次构建内存
builder.BuildHardDisk(); // 最后构建存储设备
return builder.GetComputer();
}
}

// 客户端调用示例
class Program
{
static void Main(string[] args)
{
ComputerDirector director = new ComputerDirector();

// 构建游戏电脑
ComputerBuilder gamingBuilder = new GamingComputerBuilder();
Computer gamingPC = director.Construct(gamingBuilder);
Console.WriteLine(gamingPC);

// 切换建造者,构建办公电脑(无需修改其他逻辑)
ComputerBuilder officeBuilder = new OfficeComputerBuilder();
Computer officePC = director.Construct(officeBuilder);
Console.WriteLine(officePC);
}
}

2.2 Python 实现(动态特性+极简设计)

Python无严格的抽象类语法,通过基类抛出异常实现“抽象接口”的约束,结合动态语言的灵活性简化代码,无需繁琐的类型声明,兼顾可读性与开发效率,适合快速迭代场景。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
# 产品:电脑
class Computer:
def __init__(self):
self.cpu = None # CPU组件
self.ram = None # 内存组件
self.hard_disk = None # 硬盘组件

def __str__(self):
return f"电脑配置:CPU={self.cpu},内存={self.ram},硬盘={self.hard_disk}"

# 抽象建造者(基类,定义规范)
class ComputerBuilder:
def __init__(self):
self.computer = Computer() # 初始化产品实例

def build_cpu(self):
# 抽象方法,子类必须实现
raise NotImplementedError("子类必须重写build_cpu方法,实现CPU构建逻辑")

def build_ram(self):
raise NotImplementedError("子类必须重写build_ram方法,实现内存构建逻辑")

def build_hard_disk(self):
raise NotImplementedError("子类必须重写build_hard_disk方法,实现硬盘构建逻辑")

def get_computer(self):
# 返回构建完成的产品
return self.computer

# 具体建造者1:游戏电脑建造者
class GamingComputerBuilder(ComputerBuilder):
def build_cpu(self):
self.computer.cpu = "AMD Ryzen 9 7950X"

def build_ram(self):
self.computer.ram = "64GB DDR5 6000"

def build_hard_disk(self):
self.computer.hard_disk = "4TB NVMe PCIe5.0"

# 具体建造者2:办公电脑建造者
class OfficeComputerBuilder(ComputerBuilder):
def build_cpu(self):
self.computer.cpu = "AMD Ryzen 5 7600"

def build_ram(self):
self.computer.ram = "8GB DDR4 3200"

def build_hard_disk(self):
self.computer.hard_disk = "512GB SATA3 SSD"

# 指挥者:静态方法简化调用,控制构建流程
class ComputerDirector:
@staticmethod
def construct(builder):
# 固定构建顺序,确保组件兼容性
builder.build_cpu()
builder.build_ram()
builder.build_hard_disk()
return builder.get_computer()

# 客户端调用
if __name__ == "__main__":
# 构建游戏电脑
gaming_builder = GamingComputerBuilder()
gaming_pc = ComputerDirector.construct(gaming_builder)
print(gaming_pc)

# 构建办公电脑
office_builder = OfficeComputerBuilder()
office_pc = ComputerDirector.construct(office_builder)
print(office_pc)

2.3 Golang 实现(接口+结构体,面向接口编程)

Golang无类和继承特性,核心是“面向接口编程”,通过接口定义建造者规范,结构体实现接口方法,贴合Go语言“极简、高效”的设计哲学,代码无冗余、执行效率高。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
package main

import "fmt"

// 产品:电脑(封装核心组件)
type Computer struct {
CPU string // 中央处理器
RAM string // 内存
HardDisk string // 硬盘
}

// 自定义String方法,用于展示产品配置
func (c *Computer) String() string {
return fmt.Sprintf("电脑配置:CPU=%s,内存=%s,硬盘=%s", c.CPU, c.RAM, c.HardDisk)
}

// 抽象建造者:接口定义电脑构建的规范
type ComputerBuilder interface {
BuildCPU() // 构建CPU
BuildRAM() // 构建内存
BuildHardDisk() // 构建硬盘
GetComputer() *Computer // 获取成品电脑
}

// 具体建造者1:游戏电脑建造者
type GamingComputerBuilder struct {
computer *Computer // 持有产品实例
}

// 初始化游戏电脑建造者
func NewGamingComputerBuilder() *GamingComputerBuilder {
return &GamingComputerBuilder{computer: &Computer{}}
}

func (g *GamingComputerBuilder) BuildCPU() {
g.computer.CPU = "Intel i7-14700KF"
}

func (g *GamingComputerBuilder) BuildRAM() {
g.computer.RAM = "48GB DDR5 6200"
}

func (g *GamingComputerBuilder) BuildHardDisk() {
g.computer.HardDisk = "2TB NVMe PCIe4.0"
}

func (g *GamingComputerBuilder) GetComputer() *Computer {
return g.computer
}

// 具体建造者2:办公电脑建造者
type OfficeComputerBuilder struct {
computer *Computer // 持有产品实例
}

// 初始化办公电脑建造者
func NewOfficeComputerBuilder() *OfficeComputerBuilder {
return &OfficeComputerBuilder{computer: &Computer{}}
}

func (o *OfficeComputerBuilder) BuildCPU() {
o.computer.CPU = "Intel i3-12100"
}

func (o *OfficeComputerBuilder) BuildRAM() {
o.computer.RAM = "8GB DDR4 2666"
}

func (o *OfficeComputerBuilder) BuildHardDisk() {
o.computer.HardDisk = "512GB SATA3 SSD"
}

func (o *OfficeComputerBuilder) GetComputer() *Computer {
return o.computer
}

// 指挥者:控制构建流程,解耦客户端与建造细节
type ComputerDirector struct{}

func (d *ComputerDirector) Construct(builder ComputerBuilder) *Computer {
// 按固定顺序调用构建方法
builder.BuildCPU()
builder.BuildRAM()
builder.BuildHardDisk()
return builder.GetComputer()
}

// 客户端调用
func main() {
director := &ComputerDirector{}

// 构建游戏电脑
gamingBuilder := NewGamingComputerBuilder()
gamingPC := director.Construct(gamingBuilder)
fmt.Println(gamingPC)

// 构建办公电脑
officeBuilder := NewOfficeComputerBuilder()
officePC := director.Construct(officeBuilder)
fmt.Println(officePC)
}

2.4 C++ 实现(抽象类+多态,高性能落地)

C++通过纯虚函数定义抽象建造者接口,子类继承并实现具体构建逻辑,需注意定义虚析构函数以避免内存泄漏,兼顾多态特性与性能,适合高性能、底层开发场景,是建造者模式的经典落地方式。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
#include <iostream>
#include <string>
using namespace std;

// 产品:电脑
class Computer {
private:
string cpu; // CPU组件
string ram; // 内存组件
string hardDisk; // 硬盘组件
public:
// 设置组件的setter方法
void setCPU(string cpu) { this->cpu = cpu; }
void setRAM(string ram) { this->ram = ram; }
void setHardDisk(string hardDisk) { this->hardDisk = hardDisk; }

// 展示产品配置
string toString() {
return "电脑配置:CPU=" + cpu + ",内存=" + ram + ",硬盘=" + hardDisk;
}
};

// 抽象建造者:抽象类定义构建接口
class ComputerBuilder {
protected:
Computer* computer; // 持有产品实例
public:
ComputerBuilder() { computer = new Computer(); }
virtual ~ComputerBuilder() { delete computer; } // 虚析构函数,避免内存泄漏
virtual void buildCPU() = 0; // 纯虚函数,强制子类实现
virtual void buildRAM() = 0;
virtual void buildHardDisk() = 0;
Computer* getComputer() { return computer; } // 返回成品
};

// 具体建造者1:游戏电脑建造者
class GamingComputerBuilder : public ComputerBuilder {
public:
void buildCPU() override { computer->setCPU("AMD Ryzen 7 7800X3D"); }
void buildRAM() override { computer->setRAM("32GB DDR5 5600"); }
void buildHardDisk() override { computer->setHardDisk("2TB NVMe PCIe4.0"); }
};

// 具体建造者2:办公电脑建造者
class OfficeComputerBuilder : public ComputerBuilder {
public:
void buildCPU() override { computer->setCPU("AMD Ryzen 3 7300X"); }
void buildRAM() override { computer->setRAM("16GB DDR4 3200"); }
void buildHardDisk() override { computer->setHardDisk("1TB SATA3 HDD"); }
};

// 指挥者:控制构建流程
class ComputerDirector {
public:
Computer* construct(ComputerBuilder* builder) {
// 按顺序调用构建方法,确保组件正常组装
builder->buildCPU();
builder->buildRAM();
builder->buildHardDisk();
return builder->getComputer();
}
};

// 客户端调用
int main() {
ComputerDirector director;

// 构建游戏电脑
ComputerBuilder* gamingBuilder = new GamingComputerBuilder();
Computer* gamingPC = director.construct(gamingBuilder);
cout << gamingPC->toString() << endl;

// 构建办公电脑
ComputerBuilder* officeBuilder = new OfficeComputerBuilder();
Computer* officePC = director.construct(officeBuilder);
cout << officePC->toString() << endl;

// 释放内存,避免泄漏
delete gamingBuilder;
delete officeBuilder;
delete gamingPC;
delete officePC;
return 0;
}

2.5 纯C语言实现(结构体+函数指针,模拟面向对象)

纯C语言无面向对象特性,通过“结构体封装数据、函数指针封装行为”模拟抽象建造者和多态特性,核心是解耦构建流程与组件实现,代码轻量化、执行高效,适合嵌入式、底层开发场景。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

// 产品:电脑(结构体封装核心组件)
typedef struct {
char cpu[32]; // CPU组件
char ram[32]; // 内存组件
char hard_disk[32];// 硬盘组件
} Computer;

// 抽象建造者:函数指针模拟构建行为,定义统一规范
typedef struct {
Computer* computer;
void (*build_cpu)(struct ComputerBuilder*); // 构建CPU的函数指针
void (*build_ram)(struct ComputerBuilder*); // 构建内存的函数指针
void (*build_hard_disk)(struct ComputerBuilder*); // 构建硬盘的函数指针
} ComputerBuilder;

// 具体建造者1:游戏电脑建造者(组合抽象建造者,模拟继承)
typedef struct {
ComputerBuilder builder;
} GamingComputerBuilder;

// 游戏电脑CPU构建逻辑
void gaming_build_cpu(ComputerBuilder* b) {
strcpy(b->computer->cpu, "Intel i9-14900KF");
}

// 游戏电脑内存构建逻辑
void gaming_build_ram(ComputerBuilder* b) {
strcpy(b->computer->ram, "64GB DDR5 6400");
}

// 游戏电脑硬盘构建逻辑
void gaming_build_hard_disk(ComputerBuilder* b) {
strcpy(b->computer->hard_disk, "4TB NVMe PCIe5.0");
}

// 初始化游戏电脑建造者(绑定函数指针,完成初始化)
GamingComputerBuilder* new_gaming_builder() {
GamingComputerBuilder* builder = (GamingComputerBuilder*)malloc(sizeof(GamingComputerBuilder));
builder->builder.computer = (Computer*)malloc(sizeof(Computer));
builder->builder.build_cpu = gaming_build_cpu;
builder->builder.build_ram = gaming_build_ram;
builder->builder.build_hard_disk = gaming_build_hard_disk;
return builder;
}

// 具体建造者2:办公电脑建造者(组合抽象建造者,模拟继承)
typedef struct {
ComputerBuilder builder;
} OfficeComputerBuilder;

// 办公电脑CPU构建逻辑
void office_build_cpu(ComputerBuilder* b) {
strcpy(b->computer->cpu, "Intel i5-12400");
}

// 办公电脑内存构建逻辑
void office_build_ram(ComputerBuilder* b) {
strcpy(b->computer->ram, "16GB DDR4 3200");
}

// 办公电脑硬盘构建逻辑
void office_build_hard_disk(ComputerBuilder* b) {
strcpy(b->computer->hard_disk, "1TB SATA3 SSD");
}

// 初始化办公电脑建造者
OfficeComputerBuilder* new_office_builder() {
OfficeComputerBuilder* builder = (OfficeComputerBuilder*)malloc(sizeof(OfficeComputerBuilder));
builder->builder.computer = (Computer*)malloc(sizeof(Computer));
builder->builder.build_cpu = office_build_cpu;
builder->builder.build_ram = office_build_ram;
builder->builder.build_hard_disk = office_build_hard_disk;
return builder;
}

// 指挥者:控制构建流程,调用建造者的构建方法
Computer* construct(ComputerBuilder* builder) {
builder->build_cpu(builder);
builder->build_ram(builder);
builder->build_hard_disk(builder);
return builder->computer;
}

// 打印电脑配置
void print_computer(Computer* pc) {
printf("电脑配置:CPU=%s,内存=%s,硬盘=%s\n", pc->cpu, pc->ram, pc->hard_disk);
}

// 客户端调用
int main() {
// 构建游戏电脑
GamingComputerBuilder* gaming_builder = new_gaming_builder();
Computer* gaming_pc = construct(&gaming_builder->builder);
print_computer(gaming_pc);

// 构建办公电脑
OfficeComputerBuilder* office_builder = new_office_builder();
Computer* office_pc = construct(&office_builder->builder);
print_computer(office_pc);

// 释放内存,避免泄漏
free(gaming_builder->builder.computer);
free(gaming_builder);
free(office_builder->builder.computer);
free(office_builder);
free(gaming_pc);
free(office_pc);
return 0;
}

三、建造者模式的优缺点

建造者模式是为解决复杂对象构建问题而生的,其优势与劣势均源于“分离构建与表示”的设计思路,需结合实际业务场景权衡使用。

3.1 核心优点

  • 解耦构建与表示:产品的内部结构、组件组装逻辑封装在具体建造者中,产品结构变化时仅需修改建造者,无需改动指挥者和客户端,完全符合“开闭原则”。

  • 灵活扩展产品变体:替换具体建造者即可快速生成不同配置的产品,无需修改构建流程,适配多变体产品的创建需求,降低扩展成本。

  • 精细化控制构建过程:指挥者统一管理构建步骤,可实现分步构建、暂停/恢复构建,甚至动态调整组件配置,适用于需逐步组装的复杂对象。

  • 提升代码可维护性:客户端无需关注复杂的构建细节,只需指定建造者类型,代码逻辑清晰、可读性强,便于后期迭代与调试。

3.2 主要缺点

  • 适用场景受限:仅适用于“复杂对象+构建步骤固定”的场景,对于结构简单、无需分步构建的对象,使用建造者模式会增加代码冗余,降低开发效率。

  • 类/结构体数量膨胀:每新增一种产品变体,需对应新增一个具体建造者,当产品变体过多时,会导致类/结构体数量激增,增加代码维护成本。

  • 依赖固定构建流程:指挥者的构建顺序固定,若不同产品的构建顺序差异较大,需修改指挥者代码,违反“开闭原则”,灵活性不足。

四、建造者模式的使用场景

建造者模式的核心价值在于“复杂对象的分步构建与灵活扩展”,适用于以下核心场景,能显著提升代码的可维护性与扩展性:

  • 复杂对象分步构建:对象由多个组件组成,且组件构建有明确顺序(如汽车组装:底盘→发动机→车身→内饰;文档生成:标题→正文→页码→格式)。

  • 多变体产品创建:同一类产品有多种配置变体,且构建逻辑相似(如不同配置的电脑、不同规格的订单、不同样式的报表),需灵活切换产品形态。

  • 屏蔽构建细节:希望客户端仅关注产品结果,无需了解组件如何组装、依赖如何处理(如框架中的对象工厂、SDK中的实例创建),降低客户端使用成本。

  • 动态调整构建过程:需在构建过程中动态修改组件配置(如分步构建HTTP请求:先设置Header,再添加Body,最后设置请求参数)。

典型实战案例

  • JDK中的StringBuilder(简化版建造者,无指挥者,自身完成字符序列的分步构建);

  • MyBatis的SqlSessionFactoryBuilder(分步构建SqlSessionFactory,支持不同配置文件适配);

  • 前端框架中复杂表单/组件的构建器(如Element UI的表单构建器,支持分步配置表单字段);

  • 电商系统中的订单构建(不同类型订单的组件配置不同,通过建造者模式统一构建流程)。

五、总结

建造者模式的核心是“分离复杂对象的构建流程与组件实现”,通过抽象建造者定义规范、具体建造者实现细节、指挥者控制顺序,既解决了复杂对象构建的灵活性问题,又屏蔽了底层构建细节,提升了代码的可维护性与扩展性。

从多语言实现来看,尽管各语言的语法特性差异显著,但核心逻辑高度统一,均围绕“解耦构建与表示”展开:

  • 面向对象语言(C#、Python、Golang、C++):通过类/接口/结构体+多态实现,贴合经典设计模式结构,代码更易理解与扩展,适配中高层开发场景;

  • 过程式语言(纯C):通过结构体+函数指针模拟面向对象特性,核心是封装构建行为,代码轻量化、执行高效,适配嵌入式、底层开发场景。

使用建造者模式的关键是“匹配业务场景”:若对象结构简单、变体较少,无需使用建造者模式,避免过度设计;若对象复杂且需灵活定制、分步构建,建造者模式能发挥其最大价值。同时,无需拘泥于“指挥者+建造者”的固定结构,简化版建造者(无指挥者)在实际开发中也广泛应用,核心是把握“构建与表示分离”的本质,而非形式。

环境说明

默认已安装Prometheus服务,服务地址:192.168.56.200


一、获取交换机SNMP信息

参数
SNMP服务IP(交换机IP) 172.20.2.83
SNMP Community dfetest

二、部署 snmp_exporter

2.1 下载snmp_exporter

下载地址:https://github.com/prometheus/snmp_exporter/releases

下载完成后,上传至机器的 /usr/local 目录下,解压安装:

1
2
tar -zvxf snmp_exporter-0.15.0.linux-arm64.tar.gz
mv snmp_exporter-0.15.0.linux-arm64/ snmp_exporter

2.2 配置snmp_exporter

snmp_exporter 的配置文件需要通过 SNMP Exporter Config Generator 项目编译生成。

安装依赖

1
2
3
4
5
6
yum -y install git
yum -y install gcc gcc-g++ make net-snmp net-snmp-utils net-snmp-libs net-snmp-devel
go get github.com/prometheus/snmp_exporter/generator
cd ${GOPATH-$HOME/go}/src/github.com/prometheus/snmp_exporter/generator
go build
make mibs

修改generator.yml配置

1
vim generator.yml

modules.if_mib.auth字段配置如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
modules:
# Default IF-MIB interfaces table with ifIndex.
if_mib:
walk: [sysUpTime, interfaces, ifXTable]
version: 1
auth:
community: dfetest
lookups:
- source_indexes: [ifIndex]
lookup: ifAlias
- source_indexes: [ifIndex]
lookup: ifDescr
- source_indexes: [ifIndex]
# Use OID to avoid conflict with Netscaler NS-ROOT-MIB.
lookup: 1.3.6.1.2.1.31.1.1.1.1 # ifName
overrides:
ifAlias:
ignore: true # Lookup metric
ifDescr:
ignore: true # Lookup metric
ifName:
ignore: true # Lookup metric
ifType:
type: EnumAsInfo

生成snmp.yml

1
2
export MIBDIRS=mibs
./generator generate

将新生成的snmp.yml替换掉原snmp_exporter中的snmp.yml:

1
cp snmp.yml /usr/local/snmp_exporter

2.3 验证snmp_exporter

1
2
cd /usr/local/snmp_exporter
./snmp_exporter

snmp_exporter 服务端口在 9116,浏览器访问 http://192.168.56.200:9116,在 Target 输入框中填入交换机IP地址,点击 submit 按钮,验证数据是否正常采集。

2.4 设置开机自启

创建系统服务文件:

1
vim /etc/systemd/system/snmp_exporter.service
1
2
3
4
5
6
7
8
9
10
[Unit]
Description=node_exporter
After=network.target

[Service]
ExecStart=/usr/local/snmp_exporter/snmp_exporter
Restart=on-failure

[Install]
WantedBy=multi-user.target

启动服务并设置开机自启:

1
2
3
systemctl daemon-reload
systemctl enable snmp_exporter
systemctl start snmp_exporter

三、修改Prometheus配置

进入Prometheus安装文件夹,打开配置文件:

1
2
cd /usr/local/prometheus
vim prometheus.yml

在scrape_configs标签下添加以下内容:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
- job_name: 'snmp'
scrape_interval: 10s
static_configs:
- targets:
- 172.20.2.83 # 交换机IP地址
metrics_path: /snmp
# params:
# module: [if_mib]
relabel_configs:
- source_labels: [__address__]
target_label: __param_target
- source_labels: [__param_target]
target_label: instance
- target_label: __address__
replacement: 192.168.56.200:9116 # snmp_exporter 服务IP地址

完整prometheus.yml配置示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
# my global config
global:
scrape_interval: 15s
evaluation_interval: 15s

# Alertmanager configuration
alerting:
alertmanagers:
- static_configs:
- targets:

# Load rules once and periodically evaluate them according to the global 'evaluation_interval'.
rule_files:

# A scrape configuration containing exactly one endpoint to scrape:
scrape_configs:
- job_name: 'prometheus'
static_configs:
- targets: ['localhost:9090']

- job_name: 'Linux'
static_configs:
- targets: ['192.168.56.201:9100']
labels:
instance: Linux

- job_name: 'Windows'
static_configs:
- targets: ['192.168.56.1:9182']
labels:
instance: Windows

- job_name: 'snmp'
scrape_interval: 10s
static_configs:
- targets:
- 172.20.2.83 # 交换机IP地址
metrics_path: /snmp
# params:
# module: [if_mib]
relabel_configs:
- source_labels: [__address__]
target_label: __param_target
- source_labels: [__param_target]
target_label: instance
- target_label: __address__
replacement: 192.168.56.200:9116 # snmp_exporter 服务IP地址

重启Prometheus服务:

1
systemctl restart prometheus

浏览器访问 http://192.168.56.200:9090/targets 查看监控信息,确认snmp已加入。


四、配置Grafana

4.1 下载Dashboard

Grafana官方提供了很多dashboard页面。访问 https://grafana.com/grafana/dashboards 下载所需dashboard。

本文使用SNMP监控dashboard,Dashboard ID:10523

4.2 导入Dashboard

  1. 打开Grafana监控页面,进入dashboard管理页面
  2. 点击【Import】按钮
  3. 将Dashboard ID(10523)复制进去
  4. Grafana会自动识别,点击【change】按钮生成随机UID
  5. 在下方输入框选择Prometheus数据源
  6. 点击【Import】完成导入

导入成功后会自动打开Dashboard,即可看到交换机SNMP监控数据。


总结

组件 端口 说明
Prometheus 9090 监控平台
snmp_exporter 9116 SNMP数据采集
交换机 172.20.2.83 被监控目标

关键配置点:

  • generator.yml 中 community 需与交换机配置一致
  • prometheus.yml 中 relabel_configs 指向 snmp_exporter 地址
  • Grafana 通过 Dashboard ID 10523 导入SNMP监控面板

抽象工厂模式是GoF 23种经典创建型设计模式的核心成员,作为工厂方法模式的进阶版本,它专为解决多等级、多系列产品的创建问题而生。其核心价值在于为客户端提供一套创建“产品族”的统一接口,屏蔽具体产品的实现细节,实现对象创建与使用的解耦,在复杂系统设计中应用广泛。本文将从核心结构、多语言实现、优缺点、使用场景及总结五个维度,全面拆解抽象工厂模式,助力开发者快速掌握其设计思想与落地技巧。

一、核心结构与设计思想

抽象工厂模式在工厂方法模式的基础上,进一步强化了对“产品族”的管理能力,核心围绕4个角色构建,各角色职责清晰、协同工作,其设计核心是“分离产品族的抽象定义与具体实现”。

1.1 核心角色定义

  • 抽象工厂(Abstract Factory):定义创建多等级产品的抽象接口,包含多个创建不同类型产品的方法,通常通过抽象类或接口实现,是整个模式的核心契约。

  • 具体工厂(Concrete Factory):实现抽象工厂的所有抽象方法,负责创建某一特定产品族下的全部具体产品,确保同一工厂生产的产品具备兼容性和关联性。

  • 抽象产品(Abstract Product):定义某一等级产品的通用规范,描述产品的核心行为与特性,抽象工厂模式中会存在多个不同等级的抽象产品(如“电视机”“空调”)。

  • 具体产品(Concrete Product):实现对应抽象产品的接口,是抽象工厂模式的最终实例化对象,由特定具体工厂创建,与具体工厂形成“一对多”的关联关系。

1.2 核心概念辨析

理解抽象工厂模式的关键,是区分两个核心概念:

  • 产品族:由同一具体工厂生产、属于不同产品等级的一组关联产品(如海尔工厂生产的电视机+空调,同属海尔品牌,具备协同适配特性)。

  • 产品等级:同一类产品的不同实现(如所有品牌的电视机,均属于“电视机”这一产品等级)。

抽象工厂模式的核心目标,就是对产品族的创建进行标准化管理,让客户端无需关注产品的具体品牌和实现细节,仅通过抽象接口即可获取所需的一组关联产品。

二、多语言落地实现(统一场景:电器产品族)

为便于跨语言对比理解,本文以“电器生产”为统一场景:定义两个产品族(海尔、TCL),两个产品等级(电视机、空调),分别通过C#、Python、Golang、C++及纯C语言实现抽象工厂模式,贴合各语言的语法特性与最佳实践。

2.1 C# 实现(抽象类+继承,经典落地)

C#作为强类型面向对象语言,天然支持抽象类与接口,完美契合抽象工厂模式的经典设计,代码可读性高、类型安全,适合企业级系统开发。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
using System;

// 抽象产品1:电视机(定义电视机的通用行为)
public abstract class TV
{
public abstract void ShowInfo(); // 展示产品信息
}

// 抽象产品2:空调(定义空调的通用行为)
public abstract class AirConditioner
{
public abstract void ShowInfo(); // 展示产品信息
}

// 具体产品1-1:海尔电视机(实现电视机抽象接口)
public class HaierTV : TV
{
public override void ShowInfo() => Console.WriteLine("【海尔电视机】- 智能4K,节能护眼");
}

// 具体产品1-2:海尔空调(实现空调抽象接口)
public class HaierAirConditioner : AirConditioner
{
public override void ShowInfo() => Console.WriteLine("【海尔空调】- 一级能效,静音节能");
}

// 具体产品2-1:TCL电视机(实现电视机抽象接口)
public class TCLTV : TV
{
public override void ShowInfo() => Console.WriteLine("【TCL电视机】- 量子点屏幕,高刷清晰");
}

// 具体产品2-2:TCL空调(实现空调抽象接口)
public class TCLAirConditioner : AirConditioner
{
public override void ShowInfo() => Console.WriteLine("【TCL空调】- 快速制冷,智能控温");
}

// 抽象工厂:电器工厂(定义产品族的创建接口)
public abstract class ElectricApplianceFactory
{
public abstract TV CreateTV(); // 创建电视机
public abstract AirConditioner CreateAirConditioner(); // 创建空调
}

// 具体工厂1:海尔工厂(生产海尔产品族)
public class HaierFactory : ElectricApplianceFactory
{
public override TV CreateTV() => new HaierTV();
public override AirConditioner CreateAirConditioner() => new HaierAirConditioner();
}

// 具体工厂2:TCL工厂(生产TCL产品族)
public class TCLFactory : ElectricApplianceFactory
{
public override TV CreateTV() => new TCLTV();
public override AirConditioner CreateAirConditioner() => new TCLAirConditioner();
}

// 客户端调用(面向抽象编程,屏蔽具体实现)
class Client
{
static void Main(string[] args)
{
// 1. 使用海尔工厂,获取海尔产品族
ElectricApplianceFactory haierFactory = new HaierFactory();
haierFactory.CreateTV().ShowInfo();
haierFactory.CreateAirConditioner().ShowInfo();

// 2. 切换为TCL工厂,获取TCL产品族(无需修改其他代码)
ElectricApplianceFactory tclFactory = new TCLFactory();
tclFactory.CreateTV().ShowInfo();
tclFactory.CreateAirConditioner().ShowInfo();
}
}

2.2 Python 实现(abc模块+动态特性,简洁灵活)

Python无严格的抽象类语法,通过abc模块实现抽象接口,结合动态语言的灵活性,无需繁琐的类型声明,代码简洁易读,适合快速开发场景。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
from abc import ABC, abstractmethod

# 抽象产品1:电视机
class TV(ABC):
@abstractmethod
def show_info(self):
"""抽象方法:展示产品信息"""
pass

# 抽象产品2:空调
class AirConditioner(ABC):
@abstractmethod
def show_info(self):
"""抽象方法:展示产品信息"""
pass

# 具体产品1-1:海尔电视机
class HaierTV(TV):
def show_info(self):
print("【海尔电视机】- 智能4K,节能护眼")

# 具体产品1-2:海尔空调
class HaierAirConditioner(AirConditioner):
def show_info(self):
print("【海尔空调】- 一级能效,静音节能")

# 具体产品2-1:TCL电视机
class TCLTV(TV):
def show_info(self):
print("【TCL电视机】- 量子点屏幕,高刷清晰")

# 具体产品2-2:TCL空调
class TCLAirConditioner(AirConditioner):
def show_info(self):
print("【TCL空调】- 快速制冷,智能控温")

# 抽象工厂:电器工厂
class ElectricApplianceFactory(ABC):
@abstractmethod
def create_tv(self):
"""抽象方法:创建电视机"""
pass

@abstractmethod
def create_air_conditioner(self):
"""抽象方法:创建空调"""
pass

# 具体工厂1:海尔工厂
class HaierFactory(ElectricApplianceFactory):
def create_tv(self):
return HaierTV()

def create_air_conditioner(self):
return HaierAirConditioner()

# 具体工厂2:TCL工厂
class TCLFactory(ElectricApplianceFactory):
def create_tv(self):
return TCLTV()

def create_air_conditioner(self):
return TCLAirConditioner()

# 客户端调用
if __name__ == "__main__":
# 获取海尔产品族
haier_factory = HaierFactory()
haier_factory.create_tv().show_info()
haier_factory.create_air_conditioner().show_info()

# 切换为TCL产品族
tcl_factory = TCLFactory()
tcl_factory.create_tv().show_info()
tcl_factory.create_air_conditioner().show_info()

2.3 Golang 实现(接口+结构体,面向接口编程)

Golang无类和继承特性,核心是“面向接口编程”,通过接口模拟抽象工厂与抽象产品,结构体实现接口方法,贴合Go语言的极简设计理念,代码高效、无冗余。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
package main

import "fmt"

// 抽象产品1:电视机接口(定义电视机的行为规范)
type TV interface {
howInfo() // 展示产品信息
}

// 抽象产品2:空调接口(定义空调的行为规范)
type AirConditioner interface {
nfo() // 展示产品信息
}

// 具体产品1-1:海尔电视机(实现TV接口)
type HaierTV struct{}

func (h *HaierTV) ShowInfo() {
mt.Println("【海尔电视机】- 智能4K,节能护眼")
}

// 具体产品1-2:海尔空调(实现AirConditioner接口)
type HaierAirConditioner struct{}

func (h *HaierAirConditioner) ShowInfo() {
fmt.Println("【海尔空调】- 一级能效,静音节能")
}

// 具体产品2-1:TCL电视机(实现TV接口)
type TCLTV struct{}

func (t *TCLTV) ShowInfo() {
fmt.Println("【TCL电视机】- 量子点屏幕,高刷清晰")
}

// 具体产品2-2:TCL空调(实现AirConditioner接口)
type TCLAirConditioner struct{}

func (t *TCLAirConditioner) ShowInfo() {
fmt.Println("【TCL空调】- 快速制冷,智能控温")
}

// 抽象工厂:电器工厂接口(定义产品族创建规范)
type ElectricApplianceFactory interface {
reateTV() TV // 创建电视机
reateAirConditioner() AirConditioner // 创建空调
}

// 具体工厂1:海尔工厂(实现电器工厂接口)
type HaierFactory struct{}

func (h *HaierFactory) CreateTV() TV {
return &HaierTV{}
}

func (h *HaierFactory) CreateAirConditioner() AirConditioner {
eturn &HaierAirConditioner{}
}

// 具体工厂2:TCL工厂(实现电器工厂接口)
type TCLFactory struct{}

func (t *TCLFactory) CreateTV() TV {
return &TCLTV{}
}

func (t *TCLFactory) CreateAirConditioner() AirConditioner {
turn &TCLAirConditioner{}
}

// 客户端调用(依赖接口,不依赖具体实现)
func main() {
使用海尔工厂
r haierFactory ElectricApplianceFactory = &HaierFactory{}
haierFactory.CreateTV().ShowInfo()
aierFactory.CreateAirConditioner().ShowInfo()

切换为TCL工厂
tclFactory ElectricApplianceFactory = &TCLFactory{}
Factory.CreateTV().ShowInfo()
ctory.CreateAirConditioner().ShowInfo()
}
tclFa tcl var // h va // re r C C f ShowI S

2.4 C++ 实现(纯虚函数+继承,高性能落地)

C++通过纯虚函数定义抽象类(抽象工厂/抽象产品),子类继承并实现具体逻辑,需注意定义虚析构函数避免内存泄漏,适合高性能、底层开发场景,是抽象工厂模式的经典落地方式。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
#include <iostream>
using namespace std;

// 抽象产品1:电视机
class TV {
public:
virtual void ShowInfo() = 0; // 纯虚函数,定义抽象接口
virtual ~TV() = default; // 虚析构函数,避免内存泄漏
};

// 抽象产品2:空调
class AirConditioner {
public:
virtual void ShowInfo() = 0; // 纯虚函数,定义抽象接口
virtual ~AirConditioner() = default; // 虚析构函数
};

// 具体产品1-1:海尔电视机
class HaierTV : public TV {
public:
void ShowInfo() override {
cout << "【海尔电视机】- 智能4K,节能护眼" << endl;
}
};

// 具体产品1-2:海尔空调
class HaierAirConditioner : public AirConditioner {
public:
void ShowInfo() override {
cout << "【海尔空调】- 一级能效,静音节能" << endl;
}
};

// 具体产品2-1:TCL电视机
class TCLTV : public TV {
public:
void ShowInfo() override {
cout << "【TCL电视机】- 量子点屏幕,高刷清晰" << endl;
}
};

// 具体产品2-2:TCL空调
class TCLAirConditioner : public AirConditioner {
public:
void ShowInfo() override {
cout << "【TCL空调】- 快速制冷,智能控温" << endl;
}
};

// 抽象工厂:电器工厂
class ElectricApplianceFactory {
public:
virtual TV* CreateTV() = 0; // 抽象创建方法
virtual AirConditioner* CreateAirConditioner() = 0; // 抽象创建方法
virtual ~ElectricApplianceFactory() = default; // 虚析构函数
};

// 具体工厂1:海尔工厂
class HaierFactory : public ElectricApplianceFactory {
public:
TV* CreateTV() override {
return new HaierTV();
}
AirConditioner* CreateAirConditioner() override {
return new HaierAirConditioner();
}
};

// 具体工厂2:TCL工厂
class TCLFactory : public ElectricApplianceFactory {
public:
TV* CreateTV() override {
return new TCLTV();
}
AirConditioner* CreateAirConditioner() override {
return new TCLAirConditioner();
}
};

// 客户端调用
int main() {
// 1. 使用海尔工厂
ElectricApplianceFactory* haierFactory = new HaierFactory();
haierFactory->CreateTV()->ShowInfo();
haierFactory->CreateAirConditioner()->ShowInfo();

// 2. 切换为TCL工厂
ElectricApplianceFactory* tclFactory = new TCLFactory();
tclFactory->CreateTV()->ShowInfo();
tclFactory->CreateAirConditioner()->ShowInfo();

// 释放内存,避免泄漏
delete haierFactory;
delete tclFactory;
return 0;
}

2.5 纯C语言实现(结构体+函数指针,模拟面向对象)

纯C语言无面向对象特性,通过“结构体嵌套+函数指针”模拟抽象接口与继承,将产品行为和工厂创建逻辑封装为函数指针,实现类似多态的效果,适合底层嵌入式开发场景。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
#include <stdio.h>
#include <stdlib.h>

// 抽象产品1:电视机(结构体+函数指针模拟抽象接口)
typedef struct TV {
void (*ShowInfo)(struct TV*); // 展示产品信息的函数指针
} TV;

// 抽象产品2:空调(结构体+函数指针模拟抽象接口)
typedef struct AirConditioner {
void (*ShowInfo)(struct AirConditioner*); // 展示产品信息的函数指针
} AirConditioner;

// 具体产品1-1:海尔电视机(嵌套TV结构体,模拟继承)
typedef struct HaierTV {
TV tv;
} HaierTV;

// 海尔电视机的具体实现
void HaierTV_ShowInfo(TV* tv) {
printf("【海尔电视机】- 智能4K,节能护眼\n");
}

// 具体产品1-2:海尔空调(嵌套AirConditioner结构体,模拟继承)
typedef struct HaierAirConditioner {
AirConditioner ac;
} HaierAirConditioner;

// 海尔空调的具体实现
void HaierAirConditioner_ShowInfo(AirConditioner* ac) {
printf("【海尔空调】- 一级能效,静音节能\n");
}

// 具体产品2-1:TCL电视机(嵌套TV结构体,模拟继承)
typedef struct TCLTV {
TV tv;
} TCLTV;

// TCL电视机的具体实现
void TCLTV_ShowInfo(TV* tv) {
printf("【TCL电视机】- 量子点屏幕,高刷清晰\n");
}

// 具体产品2-2:TCL空调(嵌套AirConditioner结构体,模拟继承)
typedef struct TCLAirConditioner {
AirConditioner ac;
} TCLAirConditioner;

// TCL空调的具体实现
void TCLAirConditioner_ShowInfo(AirConditioner* ac) {
printf("【TCL空调】- 快速制冷,智能控温\n");
}

// 抽象工厂:电器工厂(结构体+函数指针模拟抽象接口)
typedef struct ElectricApplianceFactory {
TV* (*CreateTV)(struct ElectricApplianceFactory*); // 创建电视机
AirConditioner* (*CreateAirConditioner)(struct ElectricApplianceFactory*); // 创建空调
} ElectricApplianceFactory;

// 具体工厂1:海尔工厂(嵌套电器工厂结构体,模拟继承)
typedef struct HaierFactory {
ElectricApplianceFactory factory;
} HaierFactory;

// 海尔工厂创建电视机
TV* HaierFactory_CreateTV(ElectricApplianceFactory* factory) {
HaierTV* haierTV = (HaierTV*)malloc(sizeof(HaierTV));
haierTV->tv.ShowInfo = HaierTV_ShowInfo; // 绑定函数指针
return (TV*)haierTV;
}

// 海尔工厂创建空调
AirConditioner* HaierFactory_CreateAirConditioner(ElectricApplianceFactory* factory) {
HaierAirConditioner* haierAC = (HaierAirConditioner*)malloc(sizeof(HaierAirConditioner));
haierAC->ac.ShowInfo = HaierAirConditioner_ShowInfo; // 绑定函数指针
return (AirConditioner*)haierAC;
}

// 具体工厂2:TCL工厂(嵌套电器工厂结构体,模拟继承)
typedef struct TCLFactory {
ElectricApplianceFactory factory;
} TCLFactory;

// TCL工厂创建电视机
TV* TCLFactory_CreateTV(ElectricApplianceFactory* factory) {
TCLTV* tclTV = (TCLTV*)malloc(sizeof(TCLTV));
tclTV->tv.ShowInfo = TCLTV_ShowInfo; // 绑定函数指针
return (TV*)tclTV;
}

// TCL工厂创建空调
AirConditioner* TCLFactory_CreateAirConditioner(ElectricApplianceFactory* factory) {
TCLAirConditioner* tclAC = (TCLAirConditioner*)malloc(sizeof(TCLAirConditioner));
tclAC->ac.ShowInfo = TCLAirConditioner_ShowInfo; // 绑定函数指针
return (AirConditioner*)tclAC;
}

// 客户端调用
int main() {
// 1. 初始化海尔工厂,获取海尔产品族
HaierFactory haierFactory;
haierFactory.factory.CreateTV = HaierFactory_CreateTV;
haierFactory.factory.CreateAirConditioner = HaierFactory_CreateAirConditioner;

TV* haierTV = haierFactory.factory.CreateTV((ElectricApplianceFactory*)&haierFactory);
haierTV->ShowInfo(haierTV);
AirConditioner* haierAC = haierFactory.factory.CreateAirConditioner((ElectricApplianceFactory*)&haierFactory);
haierAC->ShowInfo(haierAC);

// 2. 初始化TCL工厂,获取TCL产品族
TCLFactory tclFactory;
tclFactory.factory.CreateTV = TCLFactory_CreateTV;
tclFactory.factory.CreateAirConditioner = TCLFactory_CreateAirConditioner;

TV* tclTV = tclFactory.factory.CreateTV((ElectricApplianceFactory*)&tclFactory);
tclTV->ShowInfo(tclTV);
AirConditioner* tclAC = tclFactory.factory.CreateAirConditioner((ElectricApplianceFactory*)&tclFactory);
tclAC->ShowInfo(tclAC);

// 释放内存,避免泄漏
free(haierTV);
free(haierAC);
free(tclTV);
free(tclAC);
return 0;
}

三、抽象工厂模式的优缺点

抽象工厂模式是为复杂产品族场景设计的,其优势与劣势均源于“产品族的标准化管理”,需结合实际场景权衡使用。

3.1 核心优点

  • 解耦创建与使用:客户端仅面向抽象接口编程,无需关注具体产品的创建逻辑、实现细节,降低代码耦合度,提升系统可维护性。

  • 统一管理产品族:同一具体工厂负责生产一组关联产品,确保产品间的兼容性,避免客户端因误用不同产品族的产品而出现问题。

  • 支持产品族扩展:新增产品族时,仅需新增具体工厂和对应具体产品,无需修改原有抽象工厂、已有工厂及客户端代码,完美契合开闭原则。

  • 切换产品族便捷:客户端切换产品族时,仅需替换具体工厂实例,无需修改其他业务逻辑,提升系统的灵活性和适配性。

3.2 主要缺点

  • 产品等级扩展困难:新增产品等级(如在电视机、空调外新增冰箱)时,需修改抽象工厂和所有具体工厂的接口,违反开闭原则,扩展成本高。

  • 系统复杂度提升:多产品族、多产品等级场景下,会产生大量的工厂类和产品类,增加代码量和维护成本,降低系统可读性。

  • 产品族约束严格:系统默认“一次仅消费一个产品族”,若需同时使用多个产品族的产品,需额外处理,灵活性受限。

四、使用场景

抽象工厂模式适合“多产品族、多产品等级,且产品族需统一管理”的场景,具体应用如下:

  • 跨环境/跨平台组件开发:如跨操作系统的UI组件(Windows/Linux/macOS下的按钮、输入框、弹窗),每个操作系统对应一个产品族,同一组件对应一个产品等级,通过抽象工厂统一创建,确保组件在不同环境下的兼容性。

  • 品牌化产品系列管理:如电器、汽车等品牌化产品,每个品牌对应一个产品族,每个产品类型(如电视机、空调)对应一个产品等级,通过抽象工厂实现品牌产品的标准化生产。

  • 数据源/框架切换场景:如数据库访问框架(SQL Server/MySQL/Oracle),每种数据库对应一个产品族,数据库连接、命令、适配器对应不同产品等级,切换数据源时仅需替换具体工厂。

  • 复杂产品关联场景:当系统中的产品存在强关联关系,需确保同一产品族的产品协同工作(如分布式系统中的服务注册、配置中心、日志组件),抽象工厂可统一管理这些关联产品的创建。

注意:若仅需创建单等级产品,优先使用工厂方法模式;若产品等级频繁变化,不建议使用抽象工厂模式;若产品族固定、产品等级稳定,抽象工厂模式是最优选择。

五、总结

抽象工厂模式的核心是“对产品族的抽象与封装”,它在工厂方法模式的基础上,进一步解决了多等级产品的创建与管理问题,其设计思想是“面向抽象编程,屏蔽具体实现”,最终实现系统的解耦与扩展。

从多语言实现来看,尽管各语言的语法特性差异显著,但核心逻辑高度一致:

  • 面向对象语言(C#、Python、Golang、C++):通过接口/抽象类定义规范,结合继承/结构体实现具体逻辑,利用多态特性实现产品族的灵活切换,贴合模式的经典设计。

  • 纯C语言:通过结构体嵌套+函数指针模拟面向对象的继承与多态,核心是封装行为与创建逻辑,满足底层开发的无面向对象特性限制的需求。

在实际开发中,选择抽象工厂模式的关键的是“判断系统是否存在稳定的产品族和产品等级”。其核心价值在于提升系统的可扩展性和可维护性,但需避免过度设计——若系统产品结构简单、无需扩展产品族,工厂方法模式或简单工厂模式更简洁高效。只有当系统需要管理多组关联产品、且产品族需灵活扩展时,抽象工厂模式才能发挥其最大价值。

简单工厂模式(Simple Factory Pattern)是设计模式中创建型模式的基础,它不属于GoF(Gang of Four)23种经典设计模式,但因其简洁易用的特性,成为实际开发中最常用的“准设计模式”。核心思想是通过一个工厂类封装对象的创建逻辑,客户端无需直接实例化具体类,只需通过工厂类传入参数即可获取对应实例,降低代码耦合度,提升扩展性。

本文将从简单工厂模式的核心原理出发,分别基于C#、Python、Golang、C++和纯C语言实现该模式,覆盖面向对象(OOP)和过程式编程场景,帮助开发者理解不同语言下的落地方式。

一、简单工厂模式核心结构

简单工厂模式通常包含三个核心角色:

  1. 产品抽象层:定义产品的公共接口/抽象类(OOP语言)或统一的数据结构与函数指针(过程式语言如C);

  2. 具体产品类:实现/继承抽象层,是实际被创建的对象;

  3. 工厂类:提供静态/普通方法,根据输入参数创建并返回具体产品实例。

二、多语言实现示例

场景说明

以“计算器”为例:定义四则运算(加法、减法)的产品抽象,通过工厂类根据“+”“-”参数创建对应运算实例,最终执行计算逻辑。

1. C# 实现(纯OOP)

C#作为典型的面向对象语言,通过接口定义产品抽象,工厂类封装创建逻辑:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
using System;

// 1. 产品抽象层:运算接口
public interface IOperation
{
double Calculate(double num1, double num2);
}

// 2. 具体产品类:加法运算
public class AddOperation : IOperation
{
public double Calculate(double num1, double num2)
{
return num1 + num2;
}
}

// 2. 具体产品类:减法运算
public class SubtractOperation : IOperation
{
public double Calculate(double num1, double num2)
{
return num1 - num2;
}
}

// 3. 工厂类:运算工厂
public class OperationFactory
{
public static IOperation CreateOperation(string oper)
{
return oper switch
{
"+" => new AddOperation(),
"-" => new SubtractOperation(),
_ => throw new ArgumentException("不支持的运算类型")
};
}
}

// 客户端调用
class Program
{
static void Main()
{
IOperation addOp = OperationFactory.CreateOperation("+");
Console.WriteLine("10 + 5 = " + addOp.Calculate(10, 5)); // 输出:15

IOperation subOp = OperationFactory.CreateOperation("-");
Console.WriteLine("10 - 5 = " + subOp.Calculate(10, 5)); // 输出:5
}
}

2. Python 实现(动态OOP)

Python无需显式定义接口,通过抽象基类(ABC)模拟产品抽象,工厂函数实现创建逻辑:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
from abc import ABC, abstractmethod

# 1. 产品抽象层:运算抽象类
class Operation(ABC):
@abstractmethod
def calculate(self, num1, num2):
pass

# 2. 具体产品类:加法运算
class AddOperation(Operation):
def calculate(self, num1, num2):
return num1 + num2

# 2. 具体产品类:减法运算
class SubtractOperation(Operation):
def calculate(self, num1, num2):
return num1 - num2

# 3. 工厂函数:运算工厂
def create_operation(oper):
if oper == "+":
return AddOperation()
elif oper == "-":
return SubtractOperation()
else:
raise ValueError("不支持的运算类型")

# 客户端调用
if __name__ == "__main__":
add_op = create_operation("+")
print(f"10 + 5 = {add_op.calculate(10, 5)}") # 输出:15

sub_op = create_operation("-")
print(f"10 - 5 = {sub_op.calculate(10, 5)}") # 输出:5

3. Golang 实现(基于接口的OOP)

Go语言无“类”和“继承”,通过接口实现产品抽象,工厂函数封装创建逻辑(Go推荐使用函数而非结构体作为工厂):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
package main

import (
"errors"
"fmt"
)

// 1. 产品抽象层:运算接口
type Operation interface {
Calculate(num1, num2 float64) float64
}

// 2. 具体产品类:加法运算(Go中用结构体模拟类)
type AddOperation struct{}

func (a *AddOperation) Calculate(num1, num2 float64) float64 {
return num1 + num2
}

// 2. 具体产品类:减法运算
type SubtractOperation struct{}

func (s *SubtractOperation) Calculate(num1, num2 float64) float64 {
return num1 - num2
}

// 3. 工厂函数:运算工厂
func CreateOperation(oper string) (Operation, error) {
switch oper {
case "+":
return &AddOperation{}, nil
case "-":
return &SubtractOperation{}, nil
default:
return nil, errors.New("不支持的运算类型")
}
}

// 客户端调用
func main() {
addOp, _ := CreateOperation("+")
fmt.Printf("10 + 5 = %.1f\n", addOp.Calculate(10, 5)) // 输出:15.0

subOp, _ := CreateOperation("-")
fmt.Printf("10 - 5 = %.1f\n", subOp.Calculate(10, 5)) // 输出:5.0
}

4. C++ 实现(经典OOP)

C++通过纯虚函数定义产品抽象类,工厂类提供静态方法创建具体产品:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
#include <iostream>
#include <stdexcept>
using namespace std;

// 1. 产品抽象层:运算抽象类
class Operation {
public:
virtual double calculate(double num1, double num2) = 0; // 纯虚函数
virtual ~Operation() = default; // 虚析构函数
};

// 2. 具体产品类:加法运算
class AddOperation : public Operation {
public:
double calculate(double num1, double num2) override {
return num1 + num2;
}
};

// 2. 具体产品类:减法运算
class SubtractOperation : public Operation {
public:
double calculate(double num1, double num2) override {
return num1 - num2;
}
};

// 3. 工厂类:运算工厂
class OperationFactory {
public:
static Operation* createOperation(string oper) {
if (oper == "+") {
return new AddOperation();
} else if (oper == "-") {
return new SubtractOperation();
} else {
throw invalid_argument("不支持的运算类型");
}
}
};

// 客户端调用
int main() {
Operation* addOp = OperationFactory::createOperation("+");
cout << "10 + 5 = " << addOp->calculate(10, 5) << endl; // 输出:15
delete addOp;

Operation* subOp = OperationFactory::createOperation("-");
cout << "10 - 5 = " << subOp->calculate(10, 5) << endl; // 输出:5
delete subOp;

return 0;
}

5. 纯C语言实现(过程式模拟)

C语言无面向对象特性,通过函数指针+结构体模拟产品抽象,工厂函数返回结构体指针(封装创建逻辑):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

// 1. 产品抽象层:运算结构体(包含函数指针)
typedef struct {
double (*calculate)(double num1, double num2); // 运算函数指针
} Operation;

// 2. 具体产品实现:加法运算函数
double add_calculate(double num1, double num2) {
return num1 + num2;
}

// 2. 具体产品实现:减法运算函数
double subtract_calculate(double num1, double num2) {
return num1 - num2;
}

// 3. 工厂函数:创建运算实例
Operation* create_operation(const char* oper) {
Operation* op = (Operation*)malloc(sizeof(Operation));
if (op == NULL) {
perror("malloc failed");
exit(EXIT_FAILURE);
}

if (strcmp(oper, "+") == 0) {
op->calculate = add_calculate;
} else if (strcmp(oper, "-") == 0) {
op->calculate = subtract_calculate;
} else {
free(op);
fprintf(stderr, "不支持的运算类型\n");
exit(EXIT_FAILURE);
}
return op;
}

// 客户端调用
int main() {
Operation* add_op = create_operation("+");
printf("10 + 5 = %.1f\n", add_op->calculate(10, 5)); // 输出:15.0
free(add_op);

Operation* sub_op = create_operation("-");
printf("10 - 5 = %.1f\n", sub_op->calculate(10, 5)); // 输出:5.0
free(sub_op);

return 0;
}

三、简单工厂模式的优缺点

优点

  1. 解耦:客户端无需关注产品创建细节,仅需通过工厂调用,符合“开闭原则”(扩展新产品时仅需新增具体产品类+修改工厂逻辑);

  2. 复用性:创建逻辑集中在工厂,避免重复代码;

  3. 易维护:产品实例的创建逻辑统一管理,修改时仅需调整工厂类。

缺点

  1. 工厂类职责过重:所有产品创建逻辑集中在工厂,新增产品需修改工厂代码,违反“开闭原则”(可通过工厂方法模式优化);

  2. 产品类型扩展受限:若产品类型过多,工厂类会变得臃肿,可读性和维护性下降;

  3. 难以支持复杂产品创建:无法处理依赖关系复杂的产品实例化。

四、适用场景

  1. 产品类型较少且相对固定,如工具类、简单业务组件;

  2. 客户端无需知道产品创建细节,仅需通过参数获取实例;

  3. 希望统一管理产品创建逻辑,降低客户端与具体产品的耦合。

五、总结

简单工厂模式是创建型模式的入门级实现,不同语言的落地方式虽有差异(OOP语言基于接口/抽象类,过程式语言基于函数指针+结构体),但核心思想一致:封装创建逻辑,简化客户端调用

在实际开发中,需根据语言特性和业务复杂度选择:OOP语言(C#/Python/Go/C++)可直接通过接口/抽象类实现,过程式语言(C)可通过函数指针模拟;若产品类型频繁扩展,建议升级为工厂方法模式或抽象工厂模式,进一步解耦创建逻辑。

工厂方法模式是GoF 23种经典创建型设计模式之一,核心价值在于解耦对象的创建与使用,通过抽象化设计满足“开闭原则”,让系统在不修改原有代码的前提下灵活扩展产品类型。本文将从模式核心结构入手,详解其工作原理,提供C#、Python、Golang、C++及纯C语言的落地实现,并分析优缺点与适用场景,帮助开发者快速掌握该模式的实际应用。

一、工厂方法模式的核心结构

工厂方法模式通过分层设计,将产品创建逻辑抽象化,核心包含4个角色,各角色职责清晰、分工明确,共同实现“创建与使用分离”的目标,具体结构如下:

1.1 核心角色定义

  • 抽象产品(Abstract Product):定义产品的统一规范,描述产品的核心行为与属性,是所有具体产品的父类(或接口)。例如“电子设备”抽象类,定义“开机”“关机”等通用方法。

  • 具体产品(Concrete Product):实现抽象产品的接口,是工厂方法模式的最终创建目标,与具体工厂一一对应。例如“手机”“电脑”,均继承自“电子设备”,并实现各自的开机、关机逻辑。

  • 抽象工厂(Abstract Factory):定义创建产品的抽象接口(仅声明创建方法,不实现具体逻辑),是所有具体工厂的父类(或接口),负责约束具体工厂的行为。

  • 具体工厂(Concrete Factory):继承或实现抽象工厂,重写创建产品的方法,负责具体产品的实例化,是连接抽象产品与具体产品的桥梁。

1.2 核心工作流程

  1. 客户端无需直接创建产品,仅需依赖抽象工厂;2. 客户端根据需求选择具体工厂;3. 具体工厂调用自身的创建方法,生成对应的具体产品;4. 客户端通过抽象产品接口使用产品,无需关注产品的具体实现细节。

这种流程设计的核心优势的是“扩展无侵入”——新增产品时,只需新增具体产品类和对应具体工厂类,无需修改抽象工厂、已有具体工厂及客户端代码,完美契合开闭原则。

二、多语言实现(统一场景:电子设备创建)

以下以“电子设备创建”为统一场景(抽象产品:电子设备;具体产品:手机、电脑;抽象工厂:电子设备工厂;具体工厂:手机工厂、电脑工厂),分别实现工厂方法模式,覆盖5种主流语言,兼顾语法特性与模式核心。

2.1 C# 实现(抽象类+继承)

C#作为强类型面向对象语言,通过抽象类+继承天然适配工厂方法模式,语法简洁且类型安全,适合企业级开发场景。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
using System;

// 1. 抽象产品:电子设备
public abstract class ElectronicDevice
{
// 抽象方法:开机
public abstract void PowerOn();
// 抽象方法:关机
public abstract void PowerOff();
}

// 2. 具体产品1:手机
public class MobilePhone : ElectronicDevice
{
public override void PowerOn()
{
Console.WriteLine("手机开机,启动操作系统...");
}

public override void PowerOff()
{
Console.WriteLine("手机关机,保存数据...");
}
}

// 2. 具体产品2:电脑
public class Computer : ElectronicDevice
{
public override void PowerOn()
{
Console.WriteLine("电脑开机,加载驱动程序...");
}

public override void PowerOff()
{
Console.WriteLine("电脑关机,关闭后台进程...");
}
}

// 3. 抽象工厂:电子设备工厂
public abstract class ElectronicDeviceFactory
{
// 抽象创建方法
public abstract ElectronicDevice CreateDevice();
}

// 4. 具体工厂1:手机工厂
public class MobilePhoneFactory : ElectronicDeviceFactory
{
public override ElectronicDevice CreateDevice()
{
Console.WriteLine("手机工厂:创建手机实例");
return new MobilePhone();
}
}

// 4. 具体工厂2:电脑工厂
public class ComputerFactory : ElectronicDeviceFactory
{
public override ElectronicDevice CreateDevice()
{
Console.WriteLine("电脑工厂:创建电脑实例");
return new Computer();
}
}

// 客户端调用
class Client
{
static void Main(string[] args)
{
// 1. 创建手机工厂,获取手机产品
ElectronicDeviceFactory mobileFactory = new MobilePhoneFactory();
ElectronicDevice mobile = mobileFactory.CreateDevice();
mobile.PowerOn();
mobile.PowerOff();

// 2. 创建电脑工厂,获取电脑产品
ElectronicDeviceFactory computerFactory = new ComputerFactory();
ElectronicDevice computer = computerFactory.CreateDevice();
computer.PowerOn();
computer.PowerOff();
}
}

2.2 Python 实现(abc模块+动态特性)

Python无严格的抽象类语法,通过abc模块实现抽象接口,结合动态语言的灵活性,简化工厂与产品的定义,代码简洁易读。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
from abc import ABC, abstractmethod

# 1. 抽象产品:电子设备
class ElectronicDevice(ABC):
@abstractmethod
def power_on(self):
"""抽象方法:开机"""
pass

@abstractmethod
def power_off(self):
"""抽象方法:关机"""
pass

# 2. 具体产品1:手机
class MobilePhone(ElectronicDevice):
def power_on(self):
print("手机开机,启动操作系统...")

def power_off(self):
print("手机关机,保存数据...")

# 2. 具体产品2:电脑
class Computer(ElectronicDevice):
def power_on(self):
print("电脑开机,加载驱动程序...")

def power_off(self):
print("电脑关机,关闭后台进程...")

# 3. 抽象工厂:电子设备工厂
class ElectronicDeviceFactory(ABC):
@abstractmethod
def create_device(self):
"""抽象创建方法"""
pass

# 4. 具体工厂1:手机工厂
class MobilePhoneFactory(ElectronicDeviceFactory):
def create_device(self):
print("手机工厂:创建手机实例")
return MobilePhone()

# 4. 具体工厂2:电脑工厂
class ComputerFactory(ElectronicDeviceFactory):
def create_device(self):
print("电脑工厂:创建电脑实例")
return Computer()

# 客户端调用
if __name__ == "__main__":
# 获取手机产品
mobile_factory = MobilePhoneFactory()
mobile = mobile_factory.create_device()
mobile.power_on()
mobile.power_off()

# 获取电脑产品
computer_factory = ComputerFactory()
computer = computer_factory.create_device()
computer.power_on()
computer.power_off()

2.3 Golang 实现(接口+结构体)

Golang无类继承特性,通过“接口+结构体”实现多态,核心是定义产品接口和工厂接口,结构体实现接口方法,贴合Go语言“面向接口编程”的设计理念。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
package main

import "fmt"

// 1. 抽象产品:电子设备接口
type ElectronicDevice interface {
PowerOn() // 开机方法
PowerOff() // 关机方法
}

// 2. 具体产品1:手机
type MobilePhone struct{}

func (m *MobilePhone) PowerOn() {
fmt.Println("手机开机,启动操作系统...")
}

func (m *MobilePhone) PowerOff() {
fmt.Println("手机关机,保存数据...")
}

// 2. 具体产品2:电脑
type Computer struct{}

func (c *Computer) PowerOn() {
fmt.Println("电脑开机,加载驱动程序...")
}

func (c *Computer) PowerOff() {
fmt.Println("电脑关机,关闭后台进程...")
}

// 3. 抽象工厂:电子设备工厂接口
type ElectronicDeviceFactory interface {
CreateDevice() ElectronicDevice // 创建产品方法
}

// 4. 具体工厂1:手机工厂
type MobilePhoneFactory struct{}

func (m *MobilePhoneFactory) CreateDevice() ElectronicDevice {
fmt.Println("手机工厂:创建手机实例")
return &MobilePhone{}
}

// 4. 具体工厂2:电脑工厂
type ComputerFactory struct{}

func (c *ComputerFactory) CreateDevice() ElectronicDevice {
fmt.Println("电脑工厂:创建电脑实例")
return &Computer{}
}

// 客户端调用
func main() {
// 获取手机产品
var mobileFactory ElectronicDeviceFactory = &MobilePhoneFactory{}
mobile := mobileFactory.CreateDevice()
mobile.PowerOn()
mobile.PowerOff()

// 获取电脑产品
var computerFactory ElectronicDeviceFactory = &ComputerFactory{}
computer := computerFactory.CreateDevice()
computer.PowerOn()
computer.PowerOff()
}

2.4 C++ 实现(纯虚函数+继承)

C++通过纯虚函数定义抽象接口(抽象产品、抽象工厂),结合继承实现具体产品与具体工厂,需注意虚析构函数的定义,避免内存泄漏,适合高性能、底层开发场景。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
#include <iostream>
using namespace std;

// 1. 抽象产品:电子设备
class ElectronicDevice {
public:
// 纯虚函数:开机
virtual void PowerOn() = 0;
// 纯虚函数:关机
virtual void PowerOff() = 0;
// 虚析构函数,避免内存泄漏
virtual ~ElectronicDevice() {}
};

// 2. 具体产品1:手机
class MobilePhone : public ElectronicDevice {
public:
void PowerOn() override {
cout << "手机开机,启动操作系统..." << endl;
}

void PowerOff() override {
cout << "手机关机,保存数据..." << endl;
}
};

// 2. 具体产品2:电脑
class Computer : public ElectronicDevice {
public:
void PowerOn() override {
cout << "电脑开机,加载驱动程序..." << endl;
}

void PowerOff() override {
cout << "电脑关机,关闭后台进程..." << endl;
}
};

// 3. 抽象工厂:电子设备工厂
class ElectronicDeviceFactory {
public:
// 纯虚创建方法
virtual ElectronicDevice* CreateDevice() = 0;
// 虚析构函数
virtual ~ElectronicDeviceFactory() {}
};

// 4. 具体工厂1:手机工厂
class MobilePhoneFactory : public ElectronicDeviceFactory {
public:
ElectronicDevice* CreateDevice() override {
cout << "手机工厂:创建手机实例" << endl;
return new MobilePhone();
}
};

// 4. 具体工厂2:电脑工厂
class ComputerFactory : public ElectronicDeviceFactory {
public:
ElectronicDevice* CreateDevice() override {
cout << "电脑工厂:创建电脑实例" << endl;
return new Computer();
}
};

// 客户端调用
int main() {
// 获取手机产品
ElectronicDeviceFactory* mobileFactory = new MobilePhoneFactory();
ElectronicDevice* mobile = mobileFactory->CreateDevice();
mobile->PowerOn();
mobile->PowerOff();

// 获取电脑产品
ElectronicDeviceFactory* computerFactory = new ComputerFactory();
ElectronicDevice* computer = computerFactory->CreateDevice();
computer->PowerOn();
computer->PowerOff();

// 释放内存,避免泄漏
delete mobile;
delete mobileFactory;
delete computer;
delete computerFactory;

return 0;
}

2.5 纯C语言实现(结构体+函数指针)

纯C语言无面向对象特性,通过“结构体嵌套+函数指针”模拟抽象接口与继承,核心是将产品行为、工厂创建逻辑封装为函数指针,实现类似多态的效果,适合底层嵌入式开发。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
#include <stdio.h>
#include <stdlib.h>

// 1. 抽象产品:电子设备(结构体+函数指针模拟抽象方法)
typedef struct _ElectronicDevice {
void (*PowerOn)(struct _ElectronicDevice*); // 开机函数指针
void (*PowerOff)(struct _ElectronicDevice*); // 关机函数指针
} ElectronicDevice;

// 2. 具体产品1:手机
typedef struct _MobilePhone {
ElectronicDevice base; // 嵌套基结构体,模拟继承
} MobilePhone;

// 手机的开机实现
void MobilePhone_PowerOn(ElectronicDevice* device) {
printf("手机开机,启动操作系统...\n");
}

// 手机的关机实现
void MobilePhone_PowerOff(ElectronicDevice* device) {
printf("手机关机,保存数据...\n");
}

// 2. 具体产品2:电脑
typedef struct _Computer {
ElectronicDevice base; // 嵌套基结构体,模拟继承
} Computer;

// 电脑的开机实现
void Computer_PowerOn(ElectronicDevice* device) {
printf("电脑开机,加载驱动程序...\n");
}

// 电脑的关机实现
void Computer_PowerOff(ElectronicDevice* device) {
printf("电脑关机,关闭后台进程...\n");
}

// 3. 抽象工厂:电子设备工厂(结构体+函数指针模拟创建方法)
typedef struct _ElectronicDeviceFactory {
ElectronicDevice* (*CreateDevice)(struct _ElectronicDeviceFactory*);
} ElectronicDeviceFactory;

// 4. 具体工厂1:手机工厂
typedef struct _MobilePhoneFactory {
ElectronicDeviceFactory base; // 嵌套基结构体,模拟继承
} MobilePhoneFactory;

// 手机工厂创建手机实例
ElectronicDevice* MobilePhoneFactory_CreateDevice(ElectronicDeviceFactory* factory) {
printf("手机工厂:创建手机实例\n");
MobilePhone* mobile = (MobilePhone*)malloc(sizeof(MobilePhone));
// 绑定函数指针(实现抽象方法)
mobile->base.PowerOn = MobilePhone_PowerOn;
mobile->base.PowerOff = MobilePhone_PowerOff;
return (ElectronicDevice*)mobile;
}

// 4. 具体工厂2:电脑工厂
typedef struct _ComputerFactory {
ElectronicDeviceFactory base; // 嵌套基结构体,模拟继承
} ComputerFactory;

// 电脑工厂创建电脑实例
ElectronicDevice* ComputerFactory_CreateDevice(ElectronicDeviceFactory* factory) {
printf("电脑工厂:创建电脑实例\n");
Computer* computer = (Computer*)malloc(sizeof(Computer));
// 绑定函数指针(实现抽象方法)
computer->base.PowerOn = Computer_PowerOn;
computer->base.PowerOff = Computer_PowerOff;
return (ElectronicDevice*)computer;
}

// 客户端调用
int main() {
// 1. 获取手机产品
MobilePhoneFactory mobileFactory;
mobileFactory.base.CreateDevice = MobilePhoneFactory_CreateDevice;
ElectronicDevice* mobile = mobileFactory.base.CreateDevice((ElectronicDeviceFactory*)&mobileFactory);
mobile->PowerOn(mobile);
mobile->PowerOff(mobile);

// 2. 获取电脑产品
ComputerFactory computerFactory;
computerFactory.base.CreateDevice = ComputerFactory_CreateDevice;
ElectronicDevice* computer = computerFactory.base.CreateDevice((ElectronicDeviceFactory*)&computerFactory);
computer->PowerOn(computer);
computer->PowerOff(computer);

// 释放内存
free(mobile);
free(computer);

return 0;
}

三、工厂方法模式的优缺点

工厂方法模式是在简单工厂模式基础上的优化,解决了简单工厂“扩展需修改代码”的核心问题,但同时也带来了一定的复杂度,需结合场景合理选择。

3.1 优点

  • 符合开闭原则:新增产品时,仅需新增具体产品类和对应具体工厂类,无需修改原有抽象工厂、已有工厂及客户端代码,降低扩展成本。

  • 解耦创建与使用:客户端仅依赖抽象工厂和抽象产品,无需了解产品的具体创建逻辑(如实例化细节、初始化步骤),降低代码耦合度。

  • 支持多态扩展:通过抽象接口实现多态,具体工厂可灵活返回不同的具体产品,客户端无需修改代码即可使用新的产品。

  • 责任单一:每个具体工厂仅负责创建一种具体产品,符合单一职责原则,便于代码维护和调试。

3.2 缺点

  • 增加系统复杂度:每新增一个产品,需同时新增具体产品类和具体工厂类,导致系统类数量增多,增加代码量和维护成本。

  • 层级冗余:相比简单工厂模式,多了抽象工厂和具体工厂的分层,对于简单场景(产品类型极少、无需扩展),显得过于繁琐。

  • 理解成本提升:需理解抽象接口、多态等概念,对于新手而言,上手难度高于简单工厂模式。

四、工厂方法模式的使用场景

工厂方法模式适合“产品类型需灵活扩展、需隐藏创建细节”的场景,具体应用如下:

  • 产品类型稳定且需扩展:如电商系统的支付方式(支付宝、微信支付、银行卡支付),新增支付方式时,仅需新增支付产品类和支付工厂类,无需修改原有支付逻辑。

  • 隐藏产品创建细节:如数据库连接池、日志管理器,客户端无需关心连接/日志实例的创建、初始化、销毁细节,仅通过工厂获取实例即可。

  • 框架/库设计:框架开发中,为了让用户能扩展自定义产品,通常会提供抽象工厂接口,用户通过实现具体工厂和产品,集成到框架中(如.NET的HandlerFactory、Spring的BeanFactory)。

  • 多环境适配:如不同环境(开发、测试、生产)的配置实例创建,通过不同的具体工厂,返回适配对应环境的配置产品,客户端无需修改代码即可切换环境。

注意:若产品类型极少(如仅1-2种)且无需扩展,建议使用简单工厂模式;若需支持多系列产品(如手机+电脑+平板,每种产品又有不同品牌),建议使用抽象工厂模式。

五、总结

工厂方法模式的核心是“抽象化创建逻辑,通过多态实现扩展”,其本质是将对象创建的责任委托给具体工厂,实现“创建与使用分离”,核心价值在于满足开闭原则,提升系统的灵活性和可维护性。

从多语言实现来看,尽管不同语言的语法差异显著,但核心思想完全一致:

  • 面向对象语言(C#、Python、Golang、C++):通过接口/抽象类定义规范,结合继承/结构体实现具体逻辑,利用多态特性实现扩展,贴合模式原生设计。

  • 纯C语言:通过结构体嵌套+函数指针模拟面向对象的继承和多态,核心是封装行为和创建逻辑,满足底层开发的需求。

在实际开发中,选择工厂方法模式的关键的是“判断产品是否需要扩展”:若产品固定不变,简单工厂模式更简洁;若产品需灵活扩展,工厂方法模式是更优选择。同时,需权衡系统复杂度与扩展性,避免过度设计——无需为了使用设计模式而强行引入分层,适合的场景才是最好的。

引言

在软件开发中,单例模式(Singleton Pattern) 是一种常见的设计模式,用于确保一个类只有一个实例,并提供一个全局访问点。它适用于需要严格控制资源访问的场景,例如数据库连接池、配置管理器或任务调度器等。本文将详细介绍单例模式的核心思想,并展示其在 **C#、Python、Golang 中的实现方式。

单例模式的主要特点包括:

  • 唯一性:类只有一个实例对象
  • 自创建:类自行创建自己的实例
  • 全局访问:提供一个全局访问点来获取该实例

特点

  • 唯一性:类自身负责创建和管理实例。
  • 延迟加载:实例通常在第一次使用时创建(懒汉式)。
  • 线程安全:在多线程环境中需确保实例的唯一性。
  • 不可克隆/序列化:避免通过克隆或反序列化创建新实例。

单例模式的实现方式

C# 实现

C# 中的单例模式通常通过 双重检查锁定(Double-Check Locking) 实现,以确保线程安全和延迟加载。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
public sealed class Singleton
{
// 使用 volatile 保证多线程下的可见性
private static volatile Singleton _instance;
private static readonly object _lock = new object();

// 私有构造函数
private Singleton() { }


public static Singleton GetInstance()
{
// 第一次检查,避免不必要的锁定
if (_instance == null)
{
// 锁定操作
lock (_lock)
{
// 第二次检查,确保多线程安全
if (_instance == null)
{
_instance = new Singleton();
}
}
}
return _instance;
}
}

饿汉式(立即加载)

1
2
3
4
5
6
7
8
9
10
11
12
13
public sealed class Singleton
{
// 静态初始化,CLR保证线程安全
private static readonly Singleton _instance = new Singleton();

// 私有构造函数
private Singleton() { }

public static Singleton GetInstance()
{
return _instance;
}
}

Python 实现

Python 的模块天然支持单例,但也可以通过类实现。以下是一个线程安全的懒汉式实现:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
import threading

class Singleton:
_instance_lock = threading.Lock() # 线程锁

def __init__(self):
# 初始化逻辑
pass

def __new__(cls, *args, **kwargs):
if not hasattr(Singleton, "_instance"):
with cls._instance_lock: # 确保线程安全
if not hasattr(Singleton, "_instance"):
Singleton._instance = super().__new__(cls)
return Singleton._instance

# 使用示例
s1 = Singleton()
s2 = Singleton()
print(s1 is s2) # 输出: True

饿汉式(模块级单例)

1
2
3
4
5
6
7
8
9
# singleton.py
class Singleton:
def __init__(self):
pass

instance = Singleton()

# 使用示例
from singleton import instance

装饰器实现

1
2
3
4
5
6
7
8
9
10
11
def singleton(cls): 
instances = {}
def wrapper(*args, **kwargs):
if cls not in instances:
instances[cls] = cls(*args, **kwargs)
return instances[cls]
return wrapper

@singleton
class MySingleton:
pass

Golang 实现

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
package main

import (
"sync"
)

type Singleton struct{}

var (
instance *Singleton
once sync.Once
)

func GetInstance() *Singleton {
// sync.Once 确保代码只执行一次,线程安全
once.Do(func() {
instance = &Singleton{}
})
return instance
}

// 使用示例
func main() {
s1 := GetInstance()
s2 := GetInstance()
println(s1 == s2) // 输出: true
}

饿汉式

1
2
3
4
5
6
7
8
9
package main

type Singleton struct{}

var instance = &Singleton{}

func GetInstance() *Singleton {
return instance
}

单例模式的优缺点

优点

  • 控制实例数量:确保全局唯一性,避免资源浪费。
  • 灵活扩展:可通过子类化或组合模式扩展功能。
  • 全局访问:简化了对共享资源的访问。

缺点

  • 违反单一职责原则:类负责管理自己的实例,增加了耦合。
  • 测试困难:全局状态可能导致单元测试难以隔离。
  • 生命周期管理:实例与程序生命周期一致,可能占用过多内存。.

应用场景

  • 资源管理器:如文件系统、数据库连接池。
  • 配置中心:全局配置对象,避免重复加载配置。
  • 缓存服务:单点缓存,减少内存开销。
  • 日志记录器:统一日志输出,避免多线程冲突。

总结

单例模式是一种简单但强大的设计模式,适用于需要严格控制实例数量的场景。不同编程语言的实现方式各有特色:

  • C# 通过 lock 和 volatile 保证线程安全。
  • Python 可利用模块的天然单例特性。
  • Golang 使用 sync.Once 实现原子初始化。
  • C/C++ 通过静态局部变量或互斥锁实现线程安全。

实现要点总结

  1. 私有构造函数:防止外部直接实例化
  2. 静态实例变量:保存唯一的实例
  3. 全局访问点:提供获取实例的静态方法
  4. 线程安全:在多线程环境下需要考虑线程安全问题

选择建议

  • 懒汉式:适用于实例创建开销较大,且可能不被使用的场景
  • 饿汉式:适用于实例创建开销小,且一定会被使用的场景
  • 双重检查锁定:适用于需要兼顾性能和线程安全的场景

在实际开发中,需根据语言特性和具体需求选择合适的实现方式,同时注意避免过度使用单例模式,以免引入全局状态带来的复杂性。

面向对象的设计原则

写代码也是有原则的,我们之所以使用设计模式,主要是为了适应变化,提高代码复用率,使软件更具有可维护性和可扩展性。如果我们能更好的理解这些设计原则,对我们理解面向对象的设计模式也是有帮助的,因为这些模式的产生是基于这些原则的。这些规则是:单一职责原则(SRP)、开放封闭原则(OCP)、里氏代替原则(LSP)、依赖倒置原则(DIP)、接口隔离原则(ISP)、合成复用原则(CRP)和迪米特原则(LoD)。下面我们就分别介绍这几种设计原则。

  1. 单一职责原则(SRP):

    1. SRP(Single Responsibilities Principle)的定义:就一个类而言,应该仅有一个引起它变化的原因。简而言之,就是功能要单一。
    2. 如果一个类承担的职责过多,就等于把这些职责耦合在一起,一个职责的变化可能会削弱或者抑制这个类完成其它职责的能力。这种耦合会导致脆弱的设计,当变化发生时,设计会遭受到意想不到的破坏。(敏捷软件开发)
    3. 软件设计真正要做的许多内容,就是发现职责并把那些职责相互分离。

    小结:单一职责原则(SRP)可以看做是低耦合、高内聚在面向对象原则上的引申,将职责定义为引起变化的原因,以提高内聚性来减少引起变化的原因。责任过多,引起它变化的原因就越多,这样就会导致职责依赖,大大损伤其内聚性和耦合度。

  2. 开放关闭原则(OCP)

    1. OCP(Open-Close Principle)的定义:就是说软件实体(类,方法等等)应该可以扩展(扩展可以理解为增加),但是不能在原来的方法或者类上修改,也可以这样说,对增加代码开放,对修改代码关闭。
    2. OCP的两个特征: 对于扩展(增加)是开放的,因为它不影响原来的,这是新增加的。对于修改是封闭的,如果总是修改,逻辑会越来越复杂。

    小结:开放封闭原则(OCP)是面向对象设计的核心思想。遵循这个原则可以为我们面向对象的设计带来巨大的好处:可维护(维护成本小,做管理简单,影响最小)、可扩展(有新需求,增加就好)、可复用(不耦合,可以使用以前代码)、灵活性好(维护方便、简单)。开发人员应该仅对程序中出现频繁变化的那些部分做出抽象,但是不能过激,对应用程序中的每个部分都刻意地进行抽象同样也不是一个好主意。拒绝不成熟的抽象和抽象本身一样重要。

  3. 里氏代替原则(LSP)

    1. LSP(Liskov Substitution Principle)的定义:子类型必须能够替换掉它们的父类型。更直白的说,LSP是实现面向接口编程的基础。

    小结:任何基类可以出现的地方,子类一定可以出现,所以我们可以实现面向接口编程。 LSP是继承复用的基石,只有当子类可以替换掉基类,软件的功能不受到影响时,基类才能真正被复用,而子类也能够在基类的基础上增加新的行为。里氏代换原则是对“开-闭”原则的补充。实现“开-闭”原则的关键步骤就是抽象化。而基类与子类的继承关系就是抽象化的具体实现,所以里氏代换原则是对实现抽象化的具体步骤的规范。

  4. 依赖倒置原则(DIP)

    1. DIP(Dependence Inversion Principle)的定义:抽象不应该依赖细节,细节应该依赖于抽象。简单说就是,我们要针对接口编程,而不要针对实现编程。
    2. 高层模块不应该依赖低层模块,两个都应该依赖抽象,因为抽象是稳定的。抽象不应该依赖具体(细节),具体(细节)应该依赖抽象。

    小结:依赖倒置原则其实可以说是面向对象设计的标志,如果在我们编码的时候考虑的是面向接口编程,而不是简单的功能实现,体现了抽象的稳定性,只有这样才符合面向对象的设计。

  5. 接口隔离原则(ISP)

    1. 接口隔离原则(Interface Segregation Principle, ISP)指的是使用多个专门的接口比使用单一的总接口要好。也就是说不要让一个单一的接口承担过多的职责,而应把每个职责分离到多个专门的接口中,进行接口分离。过于臃肿的接口是对接口的一种污染。
    2. 使用多个专门的接口比使用单一的总接口要好。
    3. 一个类对另外一个类的依赖性应当是建立在最小的接口上的。
    4. 一个接口代表一个角色,不应当将不同的角色都交给一个接口。没有关系的接口合并在一起,形成一个臃肿的大接口,这是对角色和接口的污染。
    5. “不应该强迫客户依赖于它们不用的方法。接口属于客户,不属于它所在的类层次结构。”这个说得很明白了,再通俗点说,不要强迫客户使用它们不用的方法,如果强迫用户使用它们不使用的方法,那么这些客户就会面临由于这些不使用的方法的改变所带来的改变。

    小结:接口隔离原则(ISP)告诉我们,在做接口设计的时候,要尽量设计的接口功能单一,功能单一,使它变化的因素就少,这样就更稳定,其实这体现了高内聚,低耦合的原则,这样做也避免接口的污染。

  6. 组合复用原则(CRP)

    1. 组合复用原则(Composite Reuse Principle, CRP)就是在一个新的对象里面使用一些已有的对象,使之成为新对象的一部分。新对象通过向这些对象的委派达到复用已用功能的目的。简单地说,就是要尽量使用合成/聚合,尽量不要使用继承。
    2. 要使用好组合复用原则,首先需要区分”Has—A”和“Is—A”的关系。 “Is—A”是指一个类是另一个类的“一种”,是属于的关系,而“Has—A”则不同,它表示某一个角色具有某一项责任。导致错误的使用继承而不是聚合的常见的原因是错误地把“Has—A”当成“Is—A”.例如:鸡是动物,这就是“Is-A”的表现,某人有一个手枪,People类型里面包含一个Gun类型,这就是“Has-A”的表现。

    小结:组合/聚合复用原则可以使系统更加灵活,类与类之间的耦合度降低,一个类的变化对其他类造成的影响相对较少,因此一般首选使用组合/聚合来实现复用;其次才考虑继承,在使用继承时,需要严格遵循里氏替换原则,有效使用继承会有助于对问题的理解,降低复杂度,而滥用继承反而会增加系统构建和维护的难度以及系统的复杂度,因此需要慎重使用继承复用。

  7. 迪米特法则(Law of Demeter)

    1. 迪米特法则(Law of Demeter,LoD)又叫最少知识原则(Least Knowledge Principle,LKP),指的是一个对象应当对其他对象有尽可能少的了解。也就是说,一个模块或对象应尽量少的与其他实体之间发生相互作用,使得系统功能模块相对独立,这样当一个模块修改时,影响的模块就会越少,扩展起来更加容易。
    2. 关于迪米特法则其他的一些表述有:只与你直接的朋友们通信;不要跟“陌生人”说话。
    3. 外观模式(Facade Pattern)和中介者模式(Mediator Pattern)就使用了迪米特法则。

    小结:迪米特法则的初衷是降低类之间的耦合,实现类型之间的高内聚,低耦合,这样可以解耦。但是凡事都有度,过分的使用迪米特原则,会产生大量这样的中介和传递类,导致系统复杂度变大。所以在采用迪米特法则时要反复权衡,既做到结构清晰,又要高内聚低耦合。

0%