设计模式学习(二)工厂模式——抽象工厂模式

paw5zx Lv4

背景

现在我需要开发一个相机操作模块,它可能在Windows下运行,也可能在Linux下运行。由于在厂家提供的SDK中,Windows下的SDK和Linux下的SDK是有区别的,因此对于一个品牌的相机,我们要创建两个类去封装这两个不同平台下的API。

我们先使用工厂方法模式去设计(以Basler相机为例),类图如下:

对应的代码(就不用智能指针了,要不然类图不好画):

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
class BaslerCamera
{
public:
virtual ~BaslerCamera() = default;
virtual bool OpenCamera() = 0;
};

class LinuxBaslerCamera : public BaslerCamera
{
public:
~LinuxBaslerCamera() override = default;
bool OpenCamera() override
{
return true;
}
};

class WindowsBaslerCamera : public BaslerCamera
{
public:
~WindowsBaslerCamera() override = default;
bool OpenCamera() override
{
return true;
}
};

class CameraFactory
{
public:
virtual ~CameraFactory() = default;
virtual BaslerCamera* CreateBaslerCamera() = 0;
};

class LinuxCameraFactory : public CameraFactory
{
public:
BaslerCamera* CreateBaslerCamera() override
{
return new LinuxBaslerCamera();
}
};

class WindowsCameraFactory : public CameraFactory
{
public:
BaslerCamera* CreateBaslerCamera() override
{
return new WindowsBaslerCamera();
}
};

//客户端
int main()
{
//如果更换平台,客户端代码只需要修改这一处
CameraFactory* cameraFactory = new LinuxCameraFactory();

BaslerCamera* camera = cameraFactory->CreateBaslerCamera();

camera->OpenCamera();

return 0;
}

现在若新增了一个品牌的相机:Sick,那么按照工厂方法模式的设计思路,就会为其创建出对应的抽象工厂类和具体工厂类(具体代码略)。

但是进一步分析可以发现,对于这个模块,它要么在Windows下运行,要么在Linux下运行。即对于抽象产品BaslerCameraSickCamera,要么实例化LinuxBaslerCameraLinuxSickCamera,要么实例化WindowsBaslerCameraWindowsSickCamera

可以说不同的相机被划分在Linux相机和Window相机这两个产品族下,因此我们不需要为每一个品牌的相机都去实现一组对应的工厂类,而是只使用两个工厂WindowsCameraFactoryLinuxCameraFactory去管理各自对应平台下的相机的创建过程。

那么工厂类的代码就会变成这样:

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
class CameraFactory
{
public:
virtual ~CameraFactory() = default;
virtual BaslerCamera* CreateBaslerCamera() = 0;
virtual SickCamera* CreateSickCamera() = 0;
};

class LinuxCameraFactory : public CameraFactory
{
public:
BaslerCamera* CreateBaslerCamera() override
{
return new LinuxBaslerCamera();
}

SickCamera* CreateSickCamera() override
{
return new LinuxSickCamera();
}
};

class WindowsCameraFactory : public CameraFactory
{
public:
BaslerCamera* CreateBaslerCamera() override
{
return new WindowsBaslerCamera();
}

SickCamera* CreateSickCamera() override
{
return new WindowsSickCamera();
}
};

这就引出了抽象工厂模式

抽象工厂模式

抽象工厂模式,提供一个创建一系列相关或相互依赖对象的接口,而无需指定他们具体的类

AbstractProductAAbstractProductB是两个抽象产品,之所以为抽象,是因为他们可能有多种不同的实现,就刚才的例子来说,抽象产品就是BaslerCameraSickCameraProductA1ProductA2ProductB1ProductB2就是对两个抽象产品的具体分类的实现,对应例子中的LinuxBaslerCameraWindowsBaslerCameraLinuxSickCameraWindowsSickCamera

AbstractFactory是一个抽象工厂基类,对应例子中的CameraFactory,它里面应该包含产品族中每个产品创建的抽象方法。ConcreteFactory1ConcreteFactory2是具体工厂,对应例子中的LinuxCameraFactoryWindowsCameraFactory

对于客户端,通常是在代码中创建一个具体工厂的实例(这个实例就对应着一个产品族),使用这个工厂实例再创建产品族内具体的产品对象。

客户端代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
int main()
{
/*
若在windows平台,只需将本句改为:
CameraFactory* cameraFactory = new WindowsCameraFactory();
*/
CameraFactory* camera_factory = new LinuxCameraFactory();

BaslerCamera* basler_camera = camera_factory->CreateBaslerCamera();
basler_camera->OpenCamera();

SickCamera* sick_camera = camera_factory->CreateSickCamera();
sick_camera->OpenCamera();

return 0;
}

完整代码如下:

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
class BaslerCamera
{
public:
virtual ~BaslerCamera() = default;
virtual bool OpenCamera() = 0;
};

class LinuxBaslerCamera : public BaslerCamera
{
public:
~LinuxBaslerCamera() override = default;
bool OpenCamera() override
{
return true;
}
};

class WindowsBaslerCamera : public BaslerCamera
{
public:
~WindowsBaslerCamera() override = default;
bool OpenCamera() override
{
return true;
}
};

class SickCamera
{
public:
virtual ~SickCamera() = default;
virtual bool OpenCamera() = 0;
};

class LinuxSickCamera : public SickCamera
{
public:
~LinuxSickCamera() override = default;
bool OpenCamera() override
{
return true;
}
};

class WindowsSickCamera : public SickCamera
{
public:
~WindowsSickCamera() override = default;
bool OpenCamera() override
{
return true;
}
};


class CameraFactory
{
public:
virtual ~CameraFactory() = default;
virtual BaslerCamera* CreateBaslerCamera() = 0;
virtual SickCamera* CreateSickCamera() = 0;
};

class LinuxCameraFactory : public CameraFactory
{
public:
BaslerCamera* CreateBaslerCamera() override
{
return new LinuxBaslerCamera();
}

SickCamera* CreateSickCamera() override
{
return new LinuxSickCamera();
}
};

class WindowsCameraFactory : public CameraFactory
{
public:
BaslerCamera* CreateBaslerCamera() override
{
return new WindowsBaslerCamera();
}

SickCamera* CreateSickCamera() override
{
return new WindowsSickCamera();
}
};

int main()
{
//若在windows平台,只需将本句改为CameraFactory* cameraFactory = new WindowsCameraFactory();
CameraFactory* camera_factory = new LinuxCameraFactory();

BaslerCamera* basler_camera = camera_factory->CreateBaslerCamera();
basler_camera->OpenCamera();

SickCamera* sick_camera = camera_factory->CreateSickCamera();
sick_camera->OpenCamera();

return 0;
}

优点与缺点

优点:

  • 易于更改产品族:工厂的实例化过程在一个客户端只需要出现一次,修改方便

缺点:

  • 提供方违反开闭原则:如果现在在每个产品族内新增一个品牌相机(如Huaray),那么除了要增加HuarayCameraWindowsHuarayCameraLinuxHuarayCamera三个产品类之外(这是必要的),还要修改CameraFactoryLinuxCameraFactoryWindowsCameraFactory这三个工厂类,违反了开闭原则。
  • 客户端违法开闭原则:客户端在开始的时候都要CameraFactory* camera_factory = new LinuxCameraFactory();,若是要更换为Windows平台,则还需手动修改实例化的类型,违反了开闭原则。而且如果客户端不止一个,则每一个客户端都需要手动修改,效率低。

对于抽象工厂模式的改进方法,将在下一篇文章中讨论。

参考文章

1.《大话设计模式》

  • 标题: 设计模式学习(二)工厂模式——抽象工厂模式
  • 作者: paw5zx
  • 创建于 : 2024-07-05 17:56:00
  • 更新于 : 2024-08-22 13:51:53
  • 链接: https://paw5zx.github.io/design-pattern-2-abstract-factory/
  • 版权声明: 本文章采用 CC BY-NC-SA 4.0 进行许可。
评论
目录
设计模式学习(二)工厂模式——抽象工厂模式