设计模式学习(二)工厂模式——抽象工厂模式
创始人
2024-12-28 07:37:46
0次

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

  • 背景
  • 抽象工厂模式
  • 优点与缺点
  • 参考文章

背景

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

我们先使用工厂方法模式去设计(以Basler相机为例),类图如下:
在这里插入图片描述

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

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去管理各自对应平台下的相机的创建过程。

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

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。

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

客户端代码如下:

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; } 

完整代码如下:

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),那么除了要增加HuarayCamera,WindowsHuarayCamera,LinuxHuarayCamera三个产品类之外(这是必要的),还要修改CameraFactory,LinuxCameraFactory和WindowsCameraFactory这三个工厂类,违反了开闭原则。
  • 客户端违法开闭原则:客户端在开始的时候都要CameraFactory* camera_factory = new LinuxCameraFactory();,若是要更换为Windows平台,则还需手动修改实例化的类型,违反了开闭原则。而且如果客户端不止一个,则每一个客户端都需要手动修改,效率低。

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

参考文章

1.《大话设计模式》

相关内容

热门资讯

一分钟了解开挂工具!aapok... 一分钟了解开挂工具!aapoker辅助功能开透视工具,一直真的是有挂(揭秘有挂)一分钟了解开挂工具!...
一起来讨论开挂!八戒大厅辅助透... 一起来讨论开挂!八戒大厅辅助透视挂,天天酒都存在有外挂,本来今日头条1.八戒大厅 选牌创建新账号,点...
专业讨论开挂工具!德普之星辅助... 专业讨论开挂工具!德普之星辅助功能开透视工具,一直有挂(真实有挂)1、玩家可以在德普之星透视最简单三...
揭秘真相开挂!友友麻将辅助透视... 揭秘真相开挂!友友麻将辅助透视挂,顺欣茶楼是有外挂,果然有挂技术1、用户打开应用后不用登录就可以直接...
出现新变化辅助!越乡游义乌麻将... 出现新变化辅助!越乡游义乌麻将辅助透视挂,雀友会潮汕麻将真的是有外挂,确实有挂功能1、点击下载安装,...
盘点几款开挂插件!微扑克辅助功... 盘点几款开挂插件!微扑克辅助功能开透视工具,原来是有挂(存在有挂)暗藏猫腻,小编详细说明微扑克破解器...
最终开挂!洛阳杠兹辅助透视挂,... 最终开挂!洛阳杠兹辅助透视挂,边锋老友内蒙古麻将是有外挂,一直有挂教程小薇(辅助器软件下载)致您一封...
今日公布透视挂攻略!智星德州扑... 今日公布透视挂攻略!智星德州扑克辅助功能开透视工具,一直有挂(确实有挂)1、进入到智星德州扑克是否有...
此事引发广泛关注开挂!非凡娱乐... 此事引发广泛关注开挂!非凡娱乐辅助透视挂,凑一桌游戏确实有外挂,好像有挂实锤凑一桌游戏破解侠是真的助...
三分钟了解开挂脚本!wepok... 三分钟了解开挂脚本!wepoker辅助功能开透视工具,一直是有挂(有挂辅助)1、wepoker模拟器...