PLC结构化文本设计模式——适配器模式(Adapter Pattern)
PLC Structured Text Design Patterns
PLC结构化文本设计模式——适配器模式(Adapter Pattern)
介绍
适配器模式(Adapter Pattern)充当两个不兼容接口之间的桥梁,属于结构型设计模式。它通过一个中间件(适配器)将一个类的接口转换成客户期望的另一个接口,使原本不能一起工作的类能够协同工作。适配器模式是一种软件设计模式,旨在解决不同接口之间的兼容性问题。适配器通过继承或依赖现有对象,并实现所需的目标接口。——Java 适配器模式|菜鸟教程
使用场景
- 需要使用现有类,但其接口不符合系统需求。
- 希望创建一个可复用的类,与多个不相关的类(包括未来可能引入的类)一起工作,这些类可能没有统一的接口。
- 通过接口转换,将一个类集成到另一个类系中。
生活中经典的例子,手机适配器或电脑适配器,连接手机或电脑端的接口为USB,连接充电插座端是两孔/三孔,充电就通过中间的适配器。
优缺点
-
优点
- 促进了类之间的协同工作,即使它们没有直接的关联。
- 提高了类的复用性。
- 增加了类的透明度。
- 提供了良好的灵活性。
-
缺点
- 过度使用适配器可能导致系统结构混乱,难以理解和维护。
- 由于只能继承一个类,因此只能适配一个类,且目标类必须是抽象的。
伪代码
以socket通讯和串口通讯为例,设计适配器用以适配客户端接口I_Communication。
INTERFACE I_Interface EXTENDS __SYSTEM.IQueryInterface
串口通讯接口,接口的属性成员和方法成员与客户端接口I_Communication不一致,因此需要进行适配。
INTERFACE I_SerialCom EXTENDS I_Interface
PROPERTY BaudRate : INT
Get()
------
PROPERTY DataBits : INT
Get()
------
PROPERTY IsConnected : BOOL
Get()
------
PROPERTY Parity : INT
Get()
------
PROPERTY PortName : STRING
Get()
------
PROPERTY StopBits : INT
Get()
------
METHOD Close : BOOL
VAR_INPUT
END_VAR
------
METHOD Open : BOOL
VAR_INPUT
END_VAR
------
METHOD SendData : STRING
VAR_INPUT
data : STRING;
END_VAR
Socket通讯接口,接口的属性成员和方法成员与客户端接口I_Communication不一致,因此需要进行适配。
INTERFACE I_Socket EXTENDS I_Interface
METHOD Connect : BOOL
VAR_INPUT
END_VAR
------
METHOD Disconnect : BOOL
VAR_INPUT
END_VAR
------
METHOD SendMessage : STRING
VAR_INPUT
message : STRING;
END_VAR
------
PROPERTY IpAddress : STRING
Get()
------
PROPERTY IsConnected : BOOL
Get()
------
PROPERTY Port : INT
Get()
客户端需要系统通用接口,直接工作在业务中。前面的I_SerialCom和I_Socket接口需要适配I_Communication接口。
INTERFACE I_Communication EXTENDS I_Interface
METHOD Connect : BOOL
VAR_INPUT
END_VAR
------
METHOD Disconnect : BOOL
VAR_INPUT
END_VAR
------
METHOD Send : STRING
VAR_INPUT
sContent : STRING;
END_VAR
------
PROPERTY IsConnected : BOOL
Get()
FB_SerialCom串口通讯,实现I_SerialCom接口。
FUNCTION_BLOCK FB_SerialCom IMPLEMENTS I_SerialCom
VAR
_IsConnected : BOOL := FALSE;
_BaudRate : INT;
_DataBits : INT;
_Parity : INT;
_PortName : STRING;
_StopBits : INT;
END_VAR
------
PROPERTY BaudRate : INT
Get:
BaudRate := THIS^._BaudRate;
------
PROPERTY DataBits : INT
Get:
DataBits := THIS^._DataBits;
------
PROPERTY IsConnected : BOOL
Get:
IsConnected := THIS^._IsConnected;
------
PROPERTY Parity : INT
Get:
Parity := THIS^._Parity;
------
PROPERTY PortName : STRING
Get:
PortName := THIS^._PortName;
------
PROPERTY StopBits : INT
Get:
StopBits := THIS^._StopBits;
------
METHOD FB_init : BOOL
VAR_INPUT
bInitRetains : BOOL; // if TRUE, the retain variables are initialized (warm start / cold start)
bInCopyCode : BOOL; // if TRUE, the instance afterwards gets moved into the copy code (online change)
portName : STRING; // 端口号
baudRate : INT; // 波特率
parity : INT; // 校验位
dataBits : INT; // 数据位
stopBits : INT; // 停止位
END_VAR
THIS^._PortName := portName;
THIS^._BaudRate := baudRate;
THIS^._Parity := parity;
THIS^._DataBits := dataBits;
THIS^._StopBits := stopBits;
------
METHOD Open : BOOL
VAR_INPUT
END_VAR
ADSLOGSTR(msgCtrlMask :=ADSLOG_MSGTYPE_LOG, msgFmtStr :='Serial port com port name:%s', strArg := THIS^._PortName);
ADSLOGSTR(msgCtrlMask :=ADSLOG_MSGTYPE_LOG, msgFmtStr :='Serial port com baud rate:%s', strArg := TO_STRING(THIS^._BaudRate));
ADSLOGSTR(msgCtrlMask :=ADSLOG_MSGTYPE_LOG, msgFmtStr :='Serial port com parity:%s', strArg := TO_STRING(THIS^._Parity));
ADSLOGSTR(msgCtrlMask :=ADSLOG_MSGTYPE_LOG, msgFmtStr :='Serial port com data bits:%s', strArg := TO_STRING(THIS^._DataBits));
ADSLOGSTR(msgCtrlMask :=ADSLOG_MSGTYPE_LOG, msgFmtStr :='Serial port com stop bits:%s', strArg := TO_STRING(THIS^._StopBits));
// 打开串口逻辑
// ************
// 打开串口逻辑
THIS^._IsConnected := TRUE;
ADSLOGSTR(msgCtrlMask :=ADSLOG_MSGTYPE_LOG, msgFmtStr :='Serial port com state:%s', strArg := 'Opened');
------
METHOD SendData : STRING
VAR_INPUT
data : STRING;
END_VAR
// 串口发送数据逻辑
// ******************
// 串口发送数据逻辑
ADSLOGSTR(msgCtrlMask :=ADSLOG_MSGTYPE_LOG, msgFmtStr :='Serial port com send data:%s', strArg := data);
------
METHOD Close : BOOL
// 关闭串口逻辑
// ***********
// 关闭串口逻辑
THIS^._IsConnected := FALSE;
ADSLOGSTR(msgCtrlMask :=ADSLOG_MSGTYPE_LOG, msgFmtStr :='Serial port com state:%s', strArg := 'Closed');
FB_Socket通讯实体类,实现I_Socket接口
FUNCTION_BLOCK FB_Socket IMPLEMENTS I_Socket
VAR
_isConnect : BOOL;
_ipAddress : STRING;
_port : INT;
END_VAR
------
PROPERTY IpAddress : STRING
Get:
IpAddress := THIS^._ipAddress;
------
PROPERTY Port : INT
Get:
Port := THIS^._port;
------
PROPERTY IsConnected : BOOL
Get:
IsConnected := THIS^._isConnect;
------
METHOD FB_init : BOOL
VAR_INPUT
bInitRetains : BOOL; // if TRUE, the retain variables are initialized (warm start / cold start)
bInCopyCode : BOOL; // if TRUE, the instance afterwards gets moved into the copy code (online change)
ipAddress : STRING; // IP地址
port : INT; // 端口号
END_VAR
THIS^._ipAddress := ipAddress;
THIS^._port := port;
------
METHOD Connect : BOOL
VAR_INPUT
END_VAR
ADSLOGSTR(msgCtrlMask :=ADSLOG_MSGTYPE_LOG, msgFmtStr :='Socket ip address:%s', strArg := THIS^._ipAddress);
ADSLOGSTR(msgCtrlMask :=ADSLOG_MSGTYPE_LOG, msgFmtStr :='Socket port:%s', strArg := TO_STRING(THIS^._port));
// socket连接逻辑
// **************
// socket连接逻辑
THIS^._isConnect := TRUE;
ADSLOGSTR(msgCtrlMask :=ADSLOG_MSGTYPE_LOG, msgFmtStr :='Socket state:%s', strArg := 'Connected');
------
METHOD SendMessage : STRING
VAR_INPUT
message : STRING;
END_VAR
// socket发送数据逻辑
// ******************
// socket发送数据逻辑
ADSLOGSTR(msgCtrlMask :=ADSLOG_MSGTYPE_LOG, msgFmtStr :='Socket send message:%s', strArg := message);
------
METHOD Disconnect : BOOL
// socket断开连接逻辑
// **************
// socket断开连接逻辑
THIS^._isConnect := FALSE;
ADSLOGSTR(msgCtrlMask :=ADSLOG_MSGTYPE_LOG, msgFmtStr :='Socket state:%s', strArg := 'DisConnected');
FUNCTION_BLOCK FB_SerialComAdapter IMPLEMENTS I_Communication
VAR
_iSerialCom : I_SerialCom;
END_VAR
------
PROPERTY IsConnected : BOOL
Get:
IsConnected := THIS^._iSerialCom.IsConnected;
------
METHOD FB_init : BOOL
VAR_INPUT
bInitRetains : BOOL; // if TRUE, the retain variables are initialized (warm start / cold start)
bInCopyCode : BOOL; // if TRUE, the instance afterwards gets moved into the copy code (online change)
iSerialCom : I_SerialCom; // 串口通讯
END_VAR
THIS^._iSerialCom := iSerialCom;
------
METHOD Connect : BOOL
THIS^._iSerialCom.Open();
------
METHOD Send : STRING
VAR_INPUT
sContent : STRING;
END_VAR
THIS^._iSerialCom.SendData(sContent);
------
METHOD Disconnect : BOOL
THIS^._iSerialCom.Close();
Socket通讯适配器FB_SocketAdapter,实现I_Communication客户端接口
FUNCTION_BLOCK FB_SocketAdapter IMPLEMENTS I_Communication
VAR
_iSocket : I_Socket;
END_VAR
------
PROPERTY IsConnected : BOOL
Get:
IsConnected := THIS^._iSocket.IsConnected;
------
METHOD FB_init : BOOL
VAR_INPUT
bInitRetains : BOOL; // if TRUE, the retain variables are initialized (warm start / cold start)
bInCopyCode : BOOL; // if TRUE, the instance afterwards gets moved into the copy code (online change)
iSocket : I_Socket; // Socket通讯
END_VAR
THIS^._iSocket := iSocket;
------
METHOD Connect : BOOL
THIS^._iSocket.Connect();
------
METHOD Send : STRING
VAR_INPUT
sContent : STRING;
END_VAR
THIS^._iSocket.SendMessage(sContent);
------
METHOD Disconnect : BOOL
THIS^._iSocket.Disconnect();
客户端主程序MAIN运行测试,声明fbSerialCom和fbSocket两个与客户端不同的接口通讯实例,并初始化连接参数。实例化FB_SerialComAdapter和FB_SocketAdapter初始化分别传入fbSerialCom和fbSocket实例。客户端根据实际需求使用I_Communication接口接收适配器实例,执行Connect、Send和Disconnect方法测试接口。
PROGRAM MAIN
VAR
fbSerialCom : FB_SerialCom('COM1',9600,0,8,1);
fbSocket : FB_Socket('192.168.0.1',801);
fbSerialComAdapter : FB_SerialComAdapter(fbSerialCom);
fbSocketAdapter : FB_SocketAdapter(fbSocket);
iCommunication : I_Communication;
bTest : BOOL;
END_VAR
IF bTest THEN
iCommunication := fbSerialComAdapter;
iCommunication.Connect();
iCommunication.Send('this is serial com data');
iCommunication.Disconnect();
iCommunication := fbSocketAdapter;
iCommunication.Connect();
iCommunication.Send('this is socket message');
iCommunication.Disconnect();
bTest := FALSE;
END_IF
日志输出结果:
MSG | 'PlcTask' (350): Serial port com port name:COM1
MSG | 'PlcTask' (350): Serial port com baud rate:9600
MSG | 'PlcTask' (350): Serial port com parity:0
MSG | 'PlcTask' (350): Serial port com data bits:8
MSG | 'PlcTask' (350): Serial port com stop bits:1
MSG | 'PlcTask' (350): Serial port com send data:this is serial com data
MSG | 'PlcTask' (350): Serial port com state:Closed
MSG | 'PlcTask' (350): Socket ip address:192.168.0.1
MSG | 'PlcTask' (350): Socket port:801
MSG | 'PlcTask' (350): Socket state:Connected
MSG | 'PlcTask' (350): Socket send message:this is socket message
MSG | 'PlcTask' (350): Socket state:DisConnected
日志输出结果显示,客户端接口I_Communication通过适配器FB_SerialComAdapter和FB_SocketAdapter均可以正常工作,接口测试成功。

浙公网安备 33010602011771号