PLC结构化文本设计模式——工厂方法模式(Factory Method Pattern)

PLC Structured Text Design Patterns

PLC结构化文本设计模式——工厂方法模式(Factory Method Pattern)

介绍

本章先后分别介绍简单工厂模式(Simple Factory Pattern)工厂方法模式(Factory Method Pattern)

    1. 简单工厂模式(Simple Factory Pattern)

    该模式不属于经典的23种设计模式,独立的工厂类用来创建不同的对象,根据传入的参数生成目标对象实例,返回的对象一般会有一个共同的父类或统一的接口。简单工厂模式是学习其它工厂模式的基础。

    1. 工厂方法模式(Factory Method Pattern)

    定义一个用于创建对象的接口,让子类决定将哪一个类实例化。工厂方法模式让一个类的实例化延迟到其子类。工厂方法模式又简称为工厂模式,也可称为多态工厂模式,它是一种创建型模式。

使用场景

  • 工厂类负责创建的对象比较少,由于创建的对象较少,不会造成工厂方法中的业务逻辑太过复杂。
  • 客户端只需要知道传入工厂类的参数,对于如何创建对象并不关心
  • 在不同的条件下创建不同的实例,比如:自动化设备根据不同的状况生成不同的报警信息、MES交互时根据需求生成本地和中控的生产信息等。

优缺点

    1. 优点

    调用者只需要知道对象的名称即可创建对象。

    扩展性高,如果需要增加新产品,只需扩展一个工厂类即可。

    屏蔽了产品的具体实现,调用者只关心产品的接口。

    1. 缺点

    每次增加一个产品时,都需要增加一个具体类和对应的工厂,使系统中类的数量成倍增加,增加了系统的复杂度和具体类的依赖。

伪代码

  • 简单工厂模式

创建基础接口,后续所有接口均继承此接口

INTERFACE I_Interface EXTENDS __system.IQueryInterface

气缸接口包含三个方法和两个属性,方法MoveToRestPosition气缸运动到休息位(原位)、方法MoveToWorkPosition气缸运动到工作位、方法ResetMove复位气缸。

INTERFACE I_Cylinder EXTENDS I_Interface

METHOD MoveToRestPosition : HRESULT
VAR_INPUT
END_VAR

METHOD MoveToWorkPosition : HRESULT
VAR_INPUT
END_VAR

METHOD ResetMove : HRESULT
VAR_INPUT
END_VAR

PROPERTY IsAtRestPosition : BOOL
Get()

PROPERTY IsAtWorkPosition : BOOL
Get()

枚举气缸种类。

TYPE E_CylinderType :
(
	Unknown,
	FeedbackRest,
	FeedbackWork,
	FeedbackWorkAndRest,
	NoFeedback
);
END_TYPE

实现只有一个Rest反馈信号的气缸类。

{attribute 'enable_dynamic_creation'} 
FUNCTION_BLOCK FB_Cylinder_FeedbackRest IMPLEMENTS I_Cylinder
VAR
	bInRestSensor : BOOL; // 实际气缸反馈信号
	bMoveToWorkSignal : BOOL; // 实际输出信号
	bMoveToRestSignal : BOOL; // 实际输出信号
END_VAR
------
PROPERTY IsAtRestPosition : BOOL
Get:
    IsAtRestPosition := bInRestSensor;
------
PROPERTY IsAtWorkPosition : BOOL
Get:
    IsAtWorkPosition := bInRestSensor = FALSE;
------
METHOD MoveToRestPosition : HRESULT

bMoveToRestSignal := TRUE;
bMoveToWorkSignal := FALSE;
ADSLOGSTR(msgCtrlMask :=ADSLOG_MSGTYPE_LOG, msgFmtStr :='[FB_Cylinder_FeedbackRest]:Move To Rest Position', strArg := '');
------
METHOD MoveToWorkPosition : HRESULT

bMoveToRestSignal := FALSE;
bMoveToWorkSignal := TRUE;
ADSLOGSTR(msgCtrlMask :=ADSLOG_MSGTYPE_MSGBOX, msgFmtStr :='[FB_Cylinder_FeedbackRest]:Move To Work Position', strArg := '');
------
METHOD ResetMove : HRESULT

bMoveToRestSignal := FALSE;
bMoveToWorkSignal := FALSE;

实现只有一个Work反馈信号的气缸类。

{attribute 'enable_dynamic_creation'} 
FUNCTION_BLOCK FB_Cylinder_FeedbackWork IMPLEMENTS I_Cylinder
VAR
	bInWorkSensor : BOOL; // 实际气缸反馈信号
	bMoveToWorkSignal : BOOL; // 实际输出信号
	bMoveToRestSignal : BOOL; // 实际输出信号
END_VAR
------
PROPERTY IsAtRestPosition : BOOL
Get:
    IsAtRestPosition := bInWorkSensor = FALSE;
------
PROPERTY IsAtWorkPosition : BOOL
Get:
    IsAtWorkPosition := bInWorkSensor;
------
METHOD MoveToRestPosition : HRESULT

bMoveToWorkSignal := FALSE;
bMoveToRestSignal := TRUE;
ADSLOGSTR(msgCtrlMask :=ADSLOG_MSGTYPE_LOG, msgFmtStr :='[FB_Cylinder_FeedbackWork]:Move To Rest Position', strArg := '');
------
METHOD MoveToWorkPosition : HRESULT

bMoveToWorkSignal := TRUE;
bMoveToRestSignal := FALSE;
ADSLOGSTR(msgCtrlMask :=ADSLOG_MSGTYPE_LOG, msgFmtStr :='[FB_Cylinder_FeedbackWork]:Move To Work Position', strArg := '');
------
METHOD ResetMove : HRESULT

bMoveToWorkSignal := FALSE;
bMoveToRestSignal := FALSE;

实现有两个WorkRest反馈信号的气缸类。

{attribute 'enable_dynamic_creation'} 
FUNCTION_BLOCK FB_Cylinder_FeedbackWorkAndRest IMPLEMENTS I_Cylinder
VAR
	bInWorkSensor : BOOL; // 实际气缸反馈信号
	bInRestSensor : BOOL; // 实际气缸反馈信号
	bMoveToWorkSignal : BOOL; // 实际输出信号
	bMoveToRestSignal : BOOL; // 实际输出信号
END_VAR
------
PROPERTY IsAtRestPosition : BOOL
Get:
    IsAtRestPosition := bInRestSensor;
------
PROPERTY IsAtWorkPosition : BOOL
Get:
    IsAtWorkPosition := bInWorkSensor;
------
METHOD MoveToRestPosition : HRESULT

bMoveToWorkSignal := FALSE;
bMoveToRestSignal := TRUE;
ADSLOGSTR(msgCtrlMask :=ADSLOG_MSGTYPE_LOG, msgFmtStr :='[FB_Cylinder_FeedbackWorkAndRest]:Move To Rest Position', strArg := '');
------
METHOD MoveToWorkPosition : HRESULT

bMoveToWorkSignal := TRUE;
bMoveToRestSignal := FALSE;
ADSLOGSTR(msgCtrlMask :=ADSLOG_MSGTYPE_LOG, msgFmtStr :='[FB_Cylinder_FeedbackWorkAndRest]:Move To Work Position', strArg := '');
------
METHOD ResetMove : HRESULT

bMoveToWorkSignal := FALSE;
bMoveToRestSignal := FALSE;

实现无反馈信号的气缸类。

{attribute 'enable_dynamic_creation'} 
FUNCTION_BLOCK FB_Cylinder_NoFeedback IMPLEMENTS I_Cylinder
VAR
	bMoveToWorkSignal : BOOL; // 实际输出信号
	bMoveToRestSignal : BOOL; // 实际输出信号
END_VAR
------
PROPERTY IsAtRestPosition : BOOL
Get:
    IsAtRestPosition := bMoveToRestSignal= TRUE AND bMoveToWorkSignal = FALSE;
------
PROPERTY IsAtWorkPosition : BOOL
Get:
    IsAtWorkPosition := bMoveToRestSignal= FALSE AND bMoveToWorkSignal = TRUE;
------
METHOD MoveToRestPosition : HRESULT

bMoveToWorkSignal := FALSE;
bMoveToRestSignal := TRUE;
ADSLOGSTR(msgCtrlMask :=ADSLOG_MSGTYPE_LOG, msgFmtStr :='[FB_Cylinder_NoFeedback]:Move To Rest Position', strArg := '');
-----
METHOD MoveToWorkPosition : HRESULT

bMoveToWorkSignal := TRUE;
bMoveToRestSignal := FALSE;
ADSLOGSTR(msgCtrlMask :=ADSLOG_MSGTYPE_LOG, msgFmtStr :='[FB_Cylinder_NoFeedback]:Move To Work Position', strArg := '');
-----
METHOD ResetMove : HRESULT

bMoveToWorkSignal := FALSE;
bMoveToRestSignal := FALSE;

创建简单工厂类,该类主要两个方法GetCylinderObject返回生成的气缸对象实例,方法ReleaseMemory释放创建对象的内存。

(* 气缸简单工厂 *)
FUNCTION_BLOCK FB_CylinderSimpleFactory
VAR
	// 只有Rest信号的气缸
	pCylinder_FeedbackRest : POINTER TO FB_Cylinder_FeedbackRest;
	// 只有Work信号的气缸
	pCylinder_FeedbackWork : POINTER TO FB_Cylinder_FeedbackWork;
	// Work和Rest信号的气缸
	pCylinder_FeedbackWorkAndRest : POINTER TO FB_Cylinder_FeedbackWorkAndRest;
	// 没有信号反馈的气缸
	pCylinder_NoFeedback : POINTER TO FB_Cylinder_NoFeedback;
	
	iCylinder : I_Cylinder;
END_VAR
------
METHOD GetCylinderObject : I_Cylinder
VAR_INPUT
	cylinderType : E_CylinderType;
END_VAR

CASE cylinderType OF
	E_CylinderType.FeedbackRest:
		pCylinder_FeedbackRest := __NEW(FB_Cylinder_FeedbackRest);
		
		IF pCylinder_FeedbackRest <> 0 THEN
			GetCylinderObject := pCylinder_FeedbackRest^;
		END_IF
	E_CylinderType.FeedbackWork:
		pCylinder_FeedbackWork := __NEW(FB_Cylinder_FeedbackWork);	
		IF pCylinder_FeedbackWork <> 0 THEN
			GetCylinderObject := pCylinder_FeedbackWork^;
		END_IF
	E_CylinderType.FeedbackWorkAndRest:
		pCylinder_FeedbackWorkAndRest := __NEW(FB_Cylinder_FeedbackWorkAndRest);	
		IF pCylinder_FeedbackWorkAndRest <> 0 THEN
			GetCylinderObject := pCylinder_FeedbackWorkAndRest^;
		END_IF
	E_CylinderType.NoFeedback:
		pCylinder_NoFeedback := __NEW(FB_Cylinder_NoFeedback);	
		IF pCylinder_NoFeedback <> 0 THEN
			GetCylinderObject := pCylinder_NoFeedback^;
		END_IF	
END_CASE
------
METHOD ReleaseMemory : HRESULT
VAR_INPUT
END_VAR

IF (pCylinder_FeedbackRest <> 0) THEN
	__DELETE(pCylinder_FeedbackRest);
	pCylinder_FeedbackRest := 0;
END_IF

IF (pCylinder_FeedbackWork <> 0) THEN
	__DELETE(pCylinder_FeedbackWork);
	pCylinder_FeedbackWork := 0;
END_IF

IF (pCylinder_FeedbackWorkAndRest <> 0) THEN
	__DELETE(pCylinder_FeedbackWorkAndRest);
	pCylinder_FeedbackWorkAndRest := 0;
END_IF

IF (pCylinder_NoFeedback <> 0) THEN
	__DELETE(pCylinder_NoFeedback);
	pCylinder_NoFeedback := 0;
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 (pCylinder_FeedbackRest <> 0) THEN
	__DELETE(pCylinder_FeedbackRest);
	pCylinder_FeedbackRest := 0;
END_IF

IF (pCylinder_FeedbackWork <> 0) THEN
	__DELETE(pCylinder_FeedbackWork);
	pCylinder_FeedbackWork := 0;
END_IF

IF (pCylinder_FeedbackWorkAndRest <> 0) THEN
	__DELETE(pCylinder_FeedbackWorkAndRest);
	pCylinder_FeedbackWorkAndRest := 0;
END_IF

IF (pCylinder_NoFeedback <> 0) THEN
	__DELETE(pCylinder_NoFeedback);
	pCylinder_NoFeedback := 0;
END_IF	

Main主程序中实例化简单工厂,声明itfCylinder接口变量接收简单工厂创建的气缸实例。

PROGRAM MAIN
VAR
	// 简单工厂测试
	fbCylinderSimpleFactory : FB_CylinderSimpleFactory;
	itfCylinder : I_Cylinder;
	eCylinderType : E_CylinderType := E_CylinderType.Unknown;
	bTest : BOOL;
END_VAR

(* 简单工厂 *)
IF bTest THEN
	bTest := FALSE;
	itfCylinder := fbCylinderSimpleFactory.GetCylinderObject(eCylinderType);
	IF	itfCylinder <> 0 THEN
		itfCylinder.MoveToWorkPosition();
		itfCylinder.MoveToRestPosition();
	END_IF
	fbCylinderSimpleFactory.ReleaseMemory();
END_IF

运行在线更改eCylinderType值并写入,输入日志。

MSG | 'PlcTask' (350): [FB_Cylinder_FeedbackRest]:Move To Work Position
MSG | 'PlcTask' (350): [FB_Cylinder_FeedbackRest]:Move To Rest Position
MSG | 'PlcTask' (350): [FB_Cylinder_FeedbackRest]:Move To Work Position
MSG | 'PlcTask' (350): [FB_Cylinder_FeedbackRest]:Move To Rest Position

MSG |'PlcTask' (350): [FB_Cylinder_FeedbackWork]:Move To Work Position
MSG |'PlcTask' (350): [FB_Cylinder_FeedbackWork]:Move To Rest Position
MSG |'PlcTask' (350): [FB_Cylinder_FeedbackWork]:Move To Work Position
MSG |'PlcTask' (350): [FB_Cylinder_FeedbackWork]:Move To Rest Position

MSG |'PlcTask' (350): [FB_Cylinder_FeedbackWorkAndRest]:Move To Work Position
MSG |'PlcTask' (350): [FB_Cylinder_FeedbackWorkAndRest]:Move To Work Position
MSG |'PlcTask' (350): [FB_Cylinder_FeedbackWorkAndRest]:Move To Rest Position
MSG |'PlcTask' (350): [FB_Cylinder_FeedbackWorkAndRest]:Move To Rest Position

MSG |'PlcTask' (350): [FB_Cylinder_NoFeedback]:Move To Work Position
MSG |'PlcTask' (350): [FB_Cylinder_NoFeedback]:Move To Work Position
MSG |'PlcTask' (350): [FB_Cylinder_NoFeedback]:Move To Rest Position
MSG |'PlcTask' (350): [FB_Cylinder_NoFeedback]:Move To Rest Position

理论上日志只输出Move To Work PositionMove To Rest Position两条结果,上面实际上多输出了一条,经过测试官方的ADSLOGSTR函数本来就会输出两条相同的信息。

  • 工厂方法模式

简单工厂模式将产品的类型均置于工厂内部,由消费者根据参数选择生成目标产品实例。若新增产品种类,如:气缸输出控制由两个变成一个,即一个输出信号控制气缸伸缩。此时就需要新增气缸种类并修改简单工厂内部逻辑。不符合开闭原则,对扩展开放,对修改关闭。同时若产品种类非常多,也会造成工厂内部过于庞大,不易维护。

这时工厂方法模式可以很好解决这个问题,防止工厂成员爆炸以及后续方便扩展,以下示例是对上述简单工厂的修改。

创建一个抽象工厂类,包含两个抽象方法成员,GetCylinderObject获取气缸对象,ReleaseMemory释放创建对象内存。

FUNCTION_BLOCK ABSTRACT FB_CylinderAbstractFactory
VAR
END_VAR
------
METHOD ABSTRACT GetCylinderObject : I_Cylinder
VAR_INPUT
END_VAR
------
METHOD ABSTRACT ReleaseMemory : HRESULT
VAR_INPUT
END_VAR

FB_CylinderFeedbackRestFactory继承于FB_CylinderAbstractFactory抽象工厂类,并实现两个抽象方法GetCylinderObjectReleaseMemory。从代码可以看出FB_CylinderFeedbackRestFactory工厂类只生产FB_Cylinder_FeedbackRest类型的气缸。

FUNCTION_BLOCK FB_CylinderFeedbackRestFactory EXTENDS FB_CylinderAbstractFactory
VAR
	pCylinder_FeedbackRest : POINTER TO FB_Cylinder_FeedbackRest;
END_VAR
------
METHOD  GetCylinderObject : I_Cylinder
VAR_INPUT
END_VAR

pCylinder_FeedbackRest := __NEW(FB_Cylinder_FeedbackRest);
IF pCylinder_FeedbackRest <> 0 THEN
	GetCylinderObject := pCylinder_FeedbackRest^;
END_IF
------
METHOD  ReleaseMemory : HRESULT
VAR_INPUT
END_VAR

IF (pCylinder_FeedbackRest <> 0) THEN
	__DELETE(pCylinder_FeedbackRest);
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 (pCylinder_FeedbackRest <> 0) THEN
	__DELETE(pCylinder_FeedbackRest);
	pCylinder_FeedbackRest := 0;
END_IF

解释同上

FUNCTION_BLOCK FB_CylinderFeedbackWorkFactory EXTENDS FB_CylinderAbstractFactory
VAR
	pCylinder_FeedbackWork : POINTER TO FB_Cylinder_FeedbackWork;
END_VAR
------
METHOD  GetCylinderObject : I_Cylinder
VAR_INPUT
END_VAR

pCylinder_FeedbackWork := __NEW(FB_Cylinder_FeedbackWork);	
IF pCylinder_FeedbackWork <> 0 THEN
	GetCylinderObject := pCylinder_FeedbackWork^;
END_IF
------
METHOD  ReleaseMemory : HRESULT
VAR_INPUT
END_VAR

IF (pCylinder_FeedbackWork <> 0) THEN
	__DELETE(pCylinder_FeedbackWork);
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 (pCylinder_FeedbackWork <> 0) THEN
	__DELETE(pCylinder_FeedbackWork);
END_IF

解释同上

FUNCTION_BLOCK FB_CylinderFeedbackWorkAndRestFactory EXTENDS FB_CylinderAbstractFactory
VAR
	pCylinder_FeedbackWorkAndRest : POINTER TO FB_Cylinder_FeedbackWorkAndRest;
END_VAR
------
METHOD  GetCylinderObject : I_Cylinder
VAR_INPUT
END_VAR

pCylinder_FeedbackWorkAndRest := __NEW(FB_Cylinder_FeedbackWorkAndRest);	
IF pCylinder_FeedbackWorkAndRest <> 0 THEN
	GetCylinderObject := pCylinder_FeedbackWorkAndRest^;
END_IF
------
METHOD  ReleaseMemory : HRESULT
VAR_INPUT
END_VAR

IF (pCylinder_FeedbackWorkAndRest <> 0) THEN
	__DELETE(pCylinder_FeedbackWorkAndRest);
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 (pCylinder_FeedbackWorkAndRest <> 0) THEN
	__DELETE(pCylinder_FeedbackWorkAndRest);
END_IF

解释同上

FUNCTION_BLOCK FB_CylinderNoFeedbackFactory EXTENDS FB_CylinderAbstractFactory
VAR
	pCylinder_NoFeedback : POINTER TO FB_Cylinder_NoFeedback;
END_VAR
------
METHOD  GetCylinderObject : I_Cylinder
VAR_INPUT
END_VAR

pCylinder_NoFeedback := __NEW(FB_Cylinder_NoFeedback);	
IF pCylinder_NoFeedback <> 0 THEN
	GetCylinderObject := pCylinder_NoFeedback^;
END_IF
------
METHOD  ReleaseMemory : HRESULT
VAR_INPUT
END_VAR

IF (pCylinder_NoFeedback <> 0) THEN
	__DELETE(pCylinder_NoFeedback);
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 (pCylinder_NoFeedback <> 0) THEN
	__DELETE(pCylinder_NoFeedback);
END_IF

在主程序中声明生产各种类型气缸的工厂,并创建其抽象工厂的引用。

PROGRAM MAIN
VAR
	itfCylinder : I_Cylinder;
	eCylinderType : E_CylinderType := E_CylinderType.Unknown;
	bTest : BOOL;

	refCylinderAbstractFactory : REFERENCE TO FB_CylinderAbstractFactory;
	fbCylinderFeedbackRestFactory : FB_CylinderFeedbackRestFactory;
	fbCylinderFeedbackWorkFactory : FB_CylinderFeedbackWorkFactory;
	fbCylinderFeedbackWorkAndRestFactory : FB_CylinderFeedbackWorkAndRestFactory;
	fbCylinderNoFeedbackFactory : FB_CylinderNoFeedbackFactory;
END_VAR

IF bTest THEN
	bTest := FALSE;
	// 抽象工厂引用接收目标工厂类型实例
	IF	eCylinderType = E_CylinderType.FeedbackRest THEN
		refCylinderAbstractFactory REF= fbCylinderFeedbackRestFactory;
	ELSIF eCylinderType = E_CylinderType.FeedbackWork THEN
		refCylinderAbstractFactory REF= fbCylinderFeedbackWorkFactory;
	ELSIF eCylinderType = E_CylinderType.FeedbackWorkAndRest THEN
		refCylinderAbstractFactory REF= fbCylinderFeedbackWorkAndRestFactory;	
	ELSIF eCylinderType = E_CylinderType.NoFeedback THEN
		refCylinderAbstractFactory REF= fbCylinderNoFeedbackFactory;		
	ELSE
		//
	END_IF
	IF	__ISVALIDREF(refCylinderAbstractFactory) THEN
		itfCylinder := refCylinderAbstractFactory.GetCylinderObject();
	END_IF
	IF	itfCylinder <> 0 THEN
		itfCylinder.MoveToWorkPosition();
		itfCylinder.MoveToRestPosition();
	END_IF	
	IF	__ISVALIDREF(refCylinderAbstractFactory) THEN
		// 释放内存
		refCylinderAbstractFactory.ReleaseMemory();
	END_IF
END_IF

由于PLC无法像高级语言那样,声明抽象类型接收子类实例。所以这里使用REFERENCE引用类型来接收子类实例。也可以采用接口,自行实现吧。

运行在线更改eCylinderType值并写入,输入日志。输出结果与简单工厂模式一致。

MSG | 'PlcTask' (350): [FB_Cylinder_FeedbackRest]:Move To Work Position
MSG | 'PlcTask' (350): [FB_Cylinder_FeedbackRest]:Move To Rest Position
MSG | 'PlcTask' (350): [FB_Cylinder_FeedbackRest]:Move To Work Position
MSG | 'PlcTask' (350): [FB_Cylinder_FeedbackRest]:Move To Rest Position

MSG |'PlcTask' (350): [FB_Cylinder_FeedbackWork]:Move To Work Position
MSG |'PlcTask' (350): [FB_Cylinder_FeedbackWork]:Move To Rest Position
MSG |'PlcTask' (350): [FB_Cylinder_FeedbackWork]:Move To Work Position
MSG |'PlcTask' (350): [FB_Cylinder_FeedbackWork]:Move To Rest Position

MSG |'PlcTask' (350): [FB_Cylinder_FeedbackWorkAndRest]:Move To Work Position
MSG |'PlcTask' (350): [FB_Cylinder_FeedbackWorkAndRest]:Move To Work Position
MSG |'PlcTask' (350): [FB_Cylinder_FeedbackWorkAndRest]:Move To Rest Position
MSG |'PlcTask' (350): [FB_Cylinder_FeedbackWorkAndRest]:Move To Rest Position

MSG |'PlcTask' (350): [FB_Cylinder_NoFeedback]:Move To Work Position
MSG |'PlcTask' (350): [FB_Cylinder_NoFeedback]:Move To Work Position
MSG |'PlcTask' (350): [FB_Cylinder_NoFeedback]:Move To Rest Position
MSG |'PlcTask' (350): [FB_Cylinder_NoFeedback]:Move To Rest Position

与简单工厂不同的是,新增气缸类型只需要创建相应的工厂类即可。符合单一职责原则开闭原则,工厂只生产一种产品,将工厂与其它类型产品解耦,新增产品不影响已存在的工厂类。

posted @ 2025-09-12 15:32  J_Sheng  阅读(21)  评论(0)    收藏  举报