工作流和背包模式虽然不在23种常用设计模式中,但是在对任务编排处理类的业务代码使用起来是非常有用的。
下面给大家介绍下工作流模式:
例如,我之前有个项目需要对模型进行转换,因为不同配置的模型需要使用的转换方法不同,且单个模型需要经历多次的执行转换脚本,那就可以把每个脚本抽离出来封装为工作流中的一个字节点,通过对节点编排适应不同的转换任务,代码流程清晰,转换流程通过配置文件进行配置。
背包模式呢,其实并不算是一种标准的设计模式,逻辑上可以理解为借鉴现实中"背包"的特性:可以装载不同类型的物品,并方便地进行取出或使用。在软件开发中,配合工作流模式,可以非常方便为工作流节点的执行提供需要的参数,这个也是我在非23种常用设计模式外比较喜欢的一种模式,例如在执行某个任务需要大量的组装参数等模式的代码上,我比较喜欢封装到统一的一个类中处理,后续的任务就把这个类从上至下传递,所有需要的参数都从类中直接获取,不需要在业务代码用到的地方才再去处理参数,而是预处理好参数,需要就去取。相当于把后续处理的多数参数都揣到兜里,需要就掏出来。
给大家一个简单的 工作流、背包、工厂、适配器模式的整合demo:
适配器模式的核心目的是将一个接口转换为客户期望的另一个接口,从而兼容不同接口的实现。这在代码中也有所体现:
工厂模式职责:
• WorkflowNodeFactory 提供了一个中央注册表,用于将 type 和实际适配器类(Class)关联起来。
• 工厂方法 createNode 根据类型创建实例并注入配置。
• 工厂屏蔽了对象创建的细节,外部调用者不需要知道具体的适配器实现类。
• 适配器职责:PaymentServiceAdapter、MessageQueueAdapter 和 CustomLoggingAdapter 都实现了统一的接口 WorkflowAdapter,屏蔽了每个模块的差异。
• 比如,PaymentServiceAdapter 适配了支付模块的内部逻辑。
• MessageQueueAdapter 适配了消息队列的逻辑。
• 统一接口:
• 这些适配器共同实现 WorkflowAdapter 接口,工作流引擎调用时无需关心具体的适配器实现,只需要依赖接口即可。
• 每个适配器从外部来看都实现了统一的 execute 方法,但内部适配了不同的逻辑和数据。
项目结构:
src/
├── adapters/
│ ├── WorkflowAdapter.java
│ ├── ConfigurableAdapter.java
│ ├── PaymentServiceAdapter.java
│ ├── MessageQueueAdapter.java
│ ├── CustomLoggingAdapter.java
├── core/
│ ├── WorkflowNodeFactory.java
│ ├── WorkflowConfigLoader.java
│ ├── ConfigurableWorkflow.java
│ ├── Backpack.java
├── main/
│ ├── WorkflowTest.java
resources/
├── workflow-config.yaml
1.WorkflowAdapter 接口 (工作流子节点实现的接口类):
java
package adapters;
import core.Backpack;
public interface WorkflowAdapter {
void execute(Backpack context);
}
2. ConfigurableAdapter 接口
java
package adapters;
import java.util.Map;
public interface ConfigurableAdapter {
void setConfig(Map<String, Object> config);
}
3. PaymentServiceAdapter 测试子节点1
java
package adapters;
import core.Backpack;
import java.util.Map;
public class PaymentServiceAdapter implements WorkflowAdapter, ConfigurableAdapter {
private String orderIdKey;
private String amountKey;
@Override
public void setConfig(Map<String, Object> config) {
this.orderIdKey = (String) config.get("orderIdKey");
this.amountKey = (String) config.get("amountKey");
}
@Override
public void execute(Backpack context) {
System.out.println("Executing Payment Service...");
String orderId = context.get(orderIdKey, String.class);
Double amount = context.get(amountKey, Double.class);
System.out.println("Processing payment for Order ID: " + orderId + ", Amount: " + amount);
context.put("paymentSuccess", true);
}
}
4. MessageQueueAdapter 测试子节点2
java
package adapters;
import core.Backpack;
import java.util.Map;
public class MessageQueueAdapter implements WorkflowAdapter, ConfigurableAdapter {
private String messageKey;
@Override
public void setConfig(Map<String, Object> config) {
this.messageKey = (String) config.get("messageKey");
}
@Override
public void execute(Backpack context) {
System.out.println("Executing Message Queue Adapter...");
String message = context.get(messageKey, String.class);
System.out.println("Sending message to queue: " + message);
context.put("messageSent", true);
}
}
5. CustomLoggingAdapter 测试子节点3
java
package adapters;
import core.Backpack;
import java.util.Map;
public class CustomLoggingAdapter implements WorkflowAdapter, ConfigurableAdapter {
private String logMessage;
@Override
public void setConfig(Map<String, Object> config) {
this.logMessage = (String) config.get("logMessage");
}
@Override
public void execute(Backpack context) {
System.out.println("Executing Custom Logging Adapter...");
System.out.println(logMessage);
}
}
6. Backpack 背包模式简单实现类
java
package core;
import java.util.HashMap;
import java.util.Map;
public class Backpack {
private final Map<String, Object> data = new HashMap<>();
public <T> void put(String key, T value) {
data.put(key, value);
}
public <T> T get(String key, Class<T> type) {
return type.cast(data.get(key));
}
@Override
public String toString() {
return "Backpack{" +
"data=" + data +
'}';
}
}
7. WorkflowNodeFactory 初始化工作流子节点工厂类
java
package core;
import adapters.WorkflowAdapter;
import adapters.ConfigurableAdapter;
import adapters.PaymentServiceAdapter;
import adapters.MessageQueueAdapter;
import adapters.CustomLoggingAdapter;
import java.util.HashMap;
import java.util.Map;
public class WorkflowNodeFactory {
private static final Map<String, Class<? extends WorkflowAdapter>> adapterRegistry = new HashMap<>();
static {
adapterRegistry.put("PaymentServiceAdapter", PaymentServiceAdapter.class);
adapterRegistry.put("MessageQueueAdapter", MessageQueueAdapter.class);
adapterRegistry.put("CustomLoggingAdapter", CustomLoggingAdapter.class);
}
public static WorkflowAdapter createNode(String type, Map<String, Object> config) {
Class<? extends WorkflowAdapter> adapterClass = adapterRegistry.get(type);
if (adapterClass == null) {
throw new IllegalArgumentException("Unknown adapter type: " + type);
}
try {
WorkflowAdapter adapter = adapterClass.getDeclaredConstructor().newInstance();
if (adapter instanceof ConfigurableAdapter) {
((ConfigurableAdapter) adapter).setConfig(config);
}
return adapter;
} catch (Exception e) {
throw new RuntimeException("Failed to create adapter for type: " + type, e);
}
}
}
8. WorkflowConfigLoader 工作流加载初始化类
java
package core;
import org.yaml.snakeyaml.Yaml;
import java.io.InputStream;
import java.util.List;
import java.util.Map;
public class WorkflowConfigLoader {
public static List<Map<String, Object>> loadWorkflowConfig(String filePath) {
Yaml yaml = new Yaml();
try (InputStream input = WorkflowConfigLoader.class.getResourceAsStream(filePath)) {
Map<String, Object> config = yaml.load(input);
return (List<Map<String, Object>>) config.get("workflow");
} catch (Exception e) {
throw new RuntimeException("Failed to load workflow configuration", e);
}
}
}
9. ConfigurableWorkflow 读取工作流配置类
java
package core;
import adapters.WorkflowAdapter;
import java.util.List;
import java.util.Map;
public class ConfigurableWorkflow {
private List<WorkflowAdapter> nodes;
public ConfigurableWorkflow(String configFilePath) {
List<Map<String, Object>> configList = WorkflowConfigLoader.loadWorkflowConfig(configFilePath);
nodes = configList.stream()
.map(config -> {
String type = (String) config.get("type");
Map<String, Object> nodeConfig = (Map<String, Object>) config.get("config");
return WorkflowNodeFactory.createNode(type, nodeConfig);
})
.toList();
}
public void execute(Backpack context) {
for (WorkflowAdapter node : nodes) {
node.execute(context);
}
}
}
10. WorkflowTest 测试类
java
package main;
import core.Backpack;
import core.ConfigurableWorkflow;
public class WorkflowTest {
public static void main(String[] args) {
ConfigurableWorkflow workflow = new ConfigurableWorkflow("/workflow-config.yaml");
Backpack context = new Backpack();
context.put("orderId", "ORDER123");
context.put("amount", 199.99);
context.put("notificationMessage", "Order ORDER123 has been processed!");
workflow.execute(context);
System.out.println("Final Context Data: " + context);
}
}
11. workflow-config.yaml
java
workflow:
- type: PaymentServiceAdapter
config:
orderIdKey: "orderId"
amountKey: "amount"
- type: MessageQueueAdapter
config:
messageKey: "notificationMessage"
- type: CustomLoggingAdapter
config:
logMessage: "Workflow completed successfully."
maven库引入:
java
<dependency>
<groupId>org.yaml</groupId>
<artifactId>snakeyaml</artifactId>
<version>2.0</version>
</dependency>