PLC结构化文本设计模式——适配器模式(Adapter Pattern)

PLC Structured Text Design Patterns

PLC结构化文本设计模式——适配器模式(Adapter Pattern)

介绍

适配器模式(Adapter Pattern)充当两个不兼容接口之间的桥梁,属于结构型设计模式。它通过一个中间件(适配器)将一个类的接口转换成客户期望的另一个接口,使原本不能一起工作的类能够协同工作。适配器模式是一种软件设计模式,旨在解决不同接口之间的兼容性问题。适配器通过继承或依赖现有对象,并实现所需的目标接口。——Java 适配器模式|菜鸟教程

使用场景

  • 需要使用现有类,但其接口不符合系统需求。
  • 希望创建一个可复用的类,与多个不相关的类(包括未来可能引入的类)一起工作,这些类可能没有统一的接口。
  • 通过接口转换,将一个类集成到另一个类系中。

生活中经典的例子,手机适配器或电脑适配器,连接手机或电脑端的接口为USB,连接充电插座端是两孔/三孔,充电就通过中间的适配器。

优缺点

  • 优点

    • 促进了类之间的协同工作,即使它们没有直接的关联。
    • 提高了类的复用性。
    • 增加了类的透明度。
    • 提供了良好的灵活性。
  • 缺点

    • 过度使用适配器可能导致系统结构混乱,难以理解和维护。
    • 由于只能继承一个类,因此只能适配一个类,且目标类必须是抽象的。

    Java 适配器模式|菜鸟教程

伪代码

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_SerialComI_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运行测试,声明fbSerialComfbSocket两个与客户端不同的接口通讯实例,并初始化连接参数。实例化FB_SerialComAdapterFB_SocketAdapter初始化分别传入fbSerialComfbSocket实例。客户端根据实际需求使用I_Communication接口接收适配器实例,执行ConnectSendDisconnect方法测试接口。

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_SerialComAdapterFB_SocketAdapter均可以正常工作,接口测试成功。

posted @ 2025-09-16 13:32  J_Sheng  阅读(33)  评论(0)    收藏  举报