背景
现在我需要开发一个相机操作模块,它可能在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
下运行。即对于抽象产品BaslerCamera
和SickCamera
,要么实例化LinuxBaslerCamera
和LinuxSickCamera
,要么实例化WindowsBaslerCamera
和WindowsSickCamera
。
可以说不同的相机被划分在Linux相机和Window相机这两个产品族下,因此我们不需要为每一个品牌的相机都去实现一组对应的工厂类,而是只使用两个工厂WindowsCameraFactory
和LinuxCameraFactory
去管理各自对应平台下的相机的创建过程。
那么工厂类的代码就会变成这样:
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(); } };
|
这就引出了抽象工厂模式
抽象工厂模式
抽象工厂模式,提供一个创建一系列相关或相互依赖对象的接口,而无需指定他们具体的类
AbstractProductA
和AbstractProductB
是两个抽象产品,之所以为抽象,是因为他们可能有多种不同的实现,就刚才的例子来说,抽象产品就是BaslerCamera
和SickCamera
。ProductA1
,ProductA2
,ProductB1
,ProductB2
就是对两个抽象产品的具体分类的实现,对应例子中的LinuxBaslerCamera
,WindowsBaslerCamera
,LinuxSickCamera
,WindowsSickCamera
。
AbstractFactory
是一个抽象工厂基类,对应例子中的CameraFactory
,它里面应该包含产品族中每个产品创建的抽象方法。ConcreteFactory1
和ConcreteFactory2
是具体工厂,对应例子中的LinuxCameraFactory
和WindowsCameraFactory
。
对于客户端,通常是在代码中创建一个具体工厂的实例(这个实例就对应着一个产品族),使用这个工厂实例再创建产品族内具体的产品对象。
客户端代码如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| int main() {
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() { 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),那么除了要增加
HuarayCamera
,WindowsHuarayCamera
,LinuxHuarayCamera
三个产品类之外(这是必要的),还要修改CameraFactory
,LinuxCameraFactory
和WindowsCameraFactory
这三个工厂类,违反了开闭原则。
- 客户端违法开闭原则:客户端在开始的时候都要
CameraFactory* camera_factory = new LinuxCameraFactory();
,若是要更换为Windows平台,则还需手动修改实例化的类型,违反了开闭原则。而且如果客户端不止一个,则每一个客户端都需要手动修改,效率低。
对于抽象工厂模式的改进方法,将在下一篇文章中讨论。
参考文章
1.《大话设计模式》