PLC结构化文本设计模式——抽象工厂模式(Abstract Factory Pattern)
PLC Structured Text Design Patterns
PLC结构化文本设计模式——抽象工厂模式(Abstract Factory Pattern)
介绍
工厂方法模式解决了简单工厂模式因新增产品种类而不得不修改/新增工厂内部代码的问题,但是每增加一种产品都需要增加一个工厂类,而且每个工厂类只负责创建一种产品,导致系统中存在大量的工厂类,从而增加系统开销。如何解决上述问题?本章将会介绍抽象工厂模式,将相关产品分类组合成一个产品族,由同一个工厂来统一生产。
抽象工厂模式(Abstract Factory Pattern) 是围绕一个超级工厂创建其他工厂。该超级工厂又称为其他工厂的工厂。这种类型的设计模式属于创建型模式,它提供了一种创建对象的最佳方式。——Java 抽象工厂模式|菜鸟教程
在抽象工厂模式中,接口是负责创建一个相关对象的工厂,不需要显式指定它们的类。每个生成的工厂都能按照工厂模式提供对象。——Java 抽象工厂模式|菜鸟教程
抽象工厂模式提供了一种创建一系列相关或相互依赖对象的接口,而无需指定具体实现类。通过使用抽象工厂模式,可以将客户端与具体产品的创建过程解耦,使得客户端可以通过工厂接口来创建一族产品。——Java 抽象工厂模式|菜鸟教程
使用场景
在一个产品族中定义多个产品,由具体工厂实现创建这些产品的方法。——Java 抽象工厂模式|菜鸟教程
其实比较抽象,PLC中不太好举例,自行体会。举个生活中的例子吧:设备上的鼠标、键盘、显示器,品牌商有戴尔、双飞燕、罗技等。(戴尔/双飞燕/罗技)它们都有各自的工厂每个工厂生产鼠标、键盘、显示器这三类产品。
优缺点
-
优点
确保同一产品族的对象一起工作。客户端不需要知道每个对象的具体类,简化了代码。——Java 抽象工厂模式|菜鸟教程
-
缺点
扩展产品族非常困难。增加一个新的产品族需要修改抽象工厂和所有具体工厂的代码。——Java 抽象工厂模式|菜鸟教程
伪代码
创建基接口,后续所有接口均基于此扩展。
INTERFACE I_Interface EXTENDS __SYSTEM.IQueryInterface
创建传感器接口,继承基接口。
INTERFACE I_Sensor EXTENDS I_Interface
METHOD ReadData : LREAL
VAR_INPUT
END_VAR
创建控制器接口,继承基接口。
INTERFACE I_Controller EXTENDS I_Interface
METHOD Execute : HRESULT
VAR_INPUT
END_VAR
创建压力控制器实体类,实现控制器接口。
{attribute 'enable_dynamic_creation'}
FUNCTION_BLOCK FB_PressureController IMPLEMENTS I_Controller
VAR
END_VAR
------
METHOD Execute : HRESULT
ADSLOGSTR(msgCtrlMask :=ADSLOG_MSGTYPE_LOG, msgFmtStr :='[FB_PressureController]:Execute', strArg := '');
创建压力传感器实体类,实现传感器接口。
{attribute 'enable_dynamic_creation'}
FUNCTION_BLOCK FB_PressureSensor IMPLEMENTS I_Sensor
VAR
END_VAR
------
METHOD ReadData : LREAL
ADSLOGSTR(msgCtrlMask :=ADSLOG_MSGTYPE_LOG, msgFmtStr :='[FB_PressureSensor]:ReadData', strArg := '');
创建温度控制器实体类,实现控制器接口
{attribute 'enable_dynamic_creation'}
FUNCTION_BLOCK FB_TemperatureController IMPLEMENTS I_Controller
VAR
END_VAR
------
METHOD Execute : HRESULT
ADSLOGSTR(msgCtrlMask :=ADSLOG_MSGTYPE_LOG, msgFmtStr :='[FB_TemperatureController]:Execute', strArg := '');
创建温度传感器实体类,实现传感器接口。
{attribute 'enable_dynamic_creation'}
FUNCTION_BLOCK FB_TemperatureSensor IMPLEMENTS I_Sensor
VAR
END_VAR
------
METHOD ReadData : LREAL
ADSLOGSTR(msgCtrlMask :=ADSLOG_MSGTYPE_LOG, msgFmtStr :='[FB_TemperatureSensor]:ReadData', strArg := '');
创建抽象工厂类,包含三个抽象方法,CreateController生成控制器实例,CreateSensor生成传感器实例,ReleaseMemory释放创建对象的内存。
FUNCTION_BLOCK ABSTRACT FB_EquipmentAbstractFactory
VAR
END_VAR
------
METHOD ABSTRACT CreateController : I_Controller
VAR_INPUT
END_VAR
------
METHOD ABSTRACT CreateSensor : I_Sensor
VAR_INPUT
END_VAR
------
METHOD ABSTRACT ReleaseMemory : HRESULT
VAR_INPUT
END_VAR
创建压力设备工厂实体类,继承设备抽象工厂类,主要实现抽象类的三个抽象方法。
FUNCTION_BLOCK FB_PressureEquipmentFactory EXTENDS FB_EquipmentAbstractFactory
VAR
pPressureController : POINTER TO FB_PressureController;
pPressureSensor : POINTER TO FB_PressureSensor;
END_VAR
------
METHOD CreateController : I_Controller
VAR_INPUT
END_VAR
pPressureController := __NEW(FB_PressureController);
IF pPressureController <> 0 THEN
CreateController := pPressureController^;
END_IF
------
METHOD CreateSensor : I_Sensor
VAR_INPUT
END_VAR
pPressureSensor := __NEW(FB_PressureSensor);
IF pPressureSensor <> 0 THEN
CreateSensor := pPressureSensor^;
END_IF
------
METHOD ReleaseMemory : HRESULT
VAR_INPUT
END_VAR
IF pPressureController <> 0 THEN
__DELETE(pPressureController);
END_IF
IF pPressureSensor <> 0 THEN
__DELETE(pPressureSensor);
END_IF
------
METHOD FB_exit : BOOL
VAR_INPUT
bInCopyCode : BOOL; // if TRUE, the exit method is called for exiting an instance that is copied afterwards (online change).
END_VAR
IF pPressureController <> 0 THEN
__DELETE(pPressureController);
END_IF
IF pPressureSensor <> 0 THEN
__DELETE(pPressureSensor);
END_IF
创建温度设备工厂实体类,继承设备抽象工厂类,主要实现抽象类的三个抽象方法。
FUNCTION_BLOCK FB_TemperatureEquipmentFactory EXTENDS FB_EquipmentAbstractFactory
VAR
pTemperatureController : POINTER TO FB_TemperatureController;
pTemperatureSensor : POINTER TO FB_TemperatureSensor;
END_VAR
------
METHOD CreateController : I_Controller
VAR_INPUT
END_VAR
pTemperatureController := __NEW(FB_TemperatureController);
IF pTemperatureController <> 0 THEN
CreateController := pTemperatureController^;
END_IF
------
METHOD CreateSensor : I_Sensor
VAR_INPUT
END_VAR
pTemperatureSensor := __NEW(FB_TemperatureSensor);
IF pTemperatureSensor <> 0 THEN
CreateSensor := pTemperatureSensor^;
END_IF
------
METHOD ReleaseMemory : HRESULT
VAR_INPUT
END_VAR
IF pTemperatureController <> 0 THEN
__DELETE(pTemperatureController);
END_IF
IF pTemperatureSensor <> 0 THEN
__DELETE(pTemperatureSensor);
END_IF
前面章节应该已经介绍过了,实体类声明指针类型的原因。主要需要使用
__New()操作符来创建对象,它的返回值是指针。
PROGRAM MAIN
VAR
bTest : BOOL;
fbEquipmentAbstractFactory : REFERENCE TO FB_EquipmentAbstractFactory;
fbPressureEquipmentFactory : FB_PressureEquipmentFactory;
fbTemperatureEquipmentFactory : FB_TemperatureEquipmentFactory;
iController : I_Controller;
iSensor : I_Sensor;
END_VAR
IF bTest THEN
// 测试压力设备工厂
fbEquipmentAbstractFactory REF= fbPressureEquipmentFactory;
iController := fbEquipmentAbstractFactory.CreateController();
iSensor := fbEquipmentAbstractFactory.CreateSensor();
IF iController <> 0 THEN
iController.Execute();
END_IF
IF iSensor <> 0 THEN
iSensor.ReadData();
END_IF
// 释放内存
fbEquipmentAbstractFactory.ReleaseMemory();
// 测试温度设备工厂
fbEquipmentAbstractFactory REF= fbTemperatureEquipmentFactory;
iController := fbEquipmentAbstractFactory.CreateController();
iSensor := fbEquipmentAbstractFactory.CreateSensor();
IF iController <> 0 THEN
iController.Execute();
END_IF
IF iSensor <> 0 THEN
iSensor.ReadData();
END_IF
// 释放内存
fbEquipmentAbstractFactory.ReleaseMemory();
bTest := FALSE;
END_IF
这里其实还可以再创建个超级工厂,生产FB_PressureEquipmentFactory和FB_TemperatureEquipmentFactory这两个工厂,称为工厂的工厂,自行实现。
主程序运行,输出以下结果。
MSG |'PlcTask' (350): [FB_PressureController]:Execute
MSG |'PlcTask' (350): [FB_PressureSensor]:ReadData
MSG |'PlcTask' (350): [FB_TemperatureController]:Execute
MSG |'PlcTask' (350): [FB_TemperatureSensor]:ReadData
程序中fbEquipmentAbstractFactory引用类型,用于接收FB_PressureEquipmentFactory和FB_TemperatureEquipmentFactory工厂实例,实际项目中可以根据业务/配置自行选择用哪个工厂创建对象实例。
抽象工厂模式相对工厂方法模式,一定程度上降低了工厂类的创建,将创建的种类封装在工厂类中,但同时若产品族扩展/增加就需要修改抽象工厂类和对应的实体工厂类,拓展较为困难。

浙公网安备 33010602011771号