diff --git a/ContentGrabbingJi-framework-api/src/main/java/net/lamgc/cgj/bot/framework/message/AbstractBotCode.java b/ContentGrabbingJi-framework-api/src/main/java/net/lamgc/cgj/bot/framework/message/AbstractBotCode.java
new file mode 100644
index 0000000..37b7e39
--- /dev/null
+++ b/ContentGrabbingJi-framework-api/src/main/java/net/lamgc/cgj/bot/framework/message/AbstractBotCode.java
@@ -0,0 +1,117 @@
+/*
+ * Copyright (C) 2020 LamGC
+ *
+ * ContentGrabbingJi is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as
+ * published by the Free Software Foundation, either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * ContentGrabbingJi is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see .
+ */
+
+package net.lamgc.cgj.bot.framework.message;
+
+import net.lamgc.cgj.bot.framework.util.CollectionUtils;
+
+import java.util.*;
+
+/**
+ * 可用于快速实现的抽象功能码.
+ * @author LamGC
+ * @see BotCode
+ */
+public abstract class AbstractBotCode implements BotCode {
+
+ private String functionName;
+ private final Map functionProperties = new Hashtable<>();
+
+ public AbstractBotCode() {}
+
+ /**
+ * 将其他实现的 BotCode 转换成该实现的 BotCode.
+ * @param botCode 待转换的 BotCode.
+ */
+ public AbstractBotCode(BotCode botCode) {
+ this(botCode.getFunctionName(), CollectionUtils.toMap(botCode.getPropertiesKeys(), botCode::getProperty));
+ }
+
+ /**
+ * 根据给定的功能名和参数 Map 构造 BotCode.
+ * @param functionName 功能名
+ * @param functionProperties 参数集 Map. 如果不需要可传入 null.
+ */
+ public AbstractBotCode(String functionName, Map functionProperties) {
+ this.functionName = functionName;
+ if(functionProperties != null) {
+ this.functionProperties.putAll(functionProperties);
+ }
+ }
+
+ @Override
+ public String toString() {
+ StringBuilder mapString = new StringBuilder(functionProperties.getClass().getSimpleName() + "{");
+ functionProperties.forEach((key, value) -> mapString.append(key).append("='").append(value).append("', "));
+ return "AbstractBotCode{" +
+ "Platform=" + getPlatform() + ", " +
+ "functionName='" + functionName + '\'' +
+ ", functionProperties=" + mapString.substring(0, mapString.length() - 2) +
+ '}';
+ }
+
+ /**
+ * 取功能函数名.
+ * @return 返回功能函数名.
+ */
+ @Override
+ public String getFunctionName() {
+ return functionName;
+ }
+
+ /**
+ * 设置功能函数名
+ * @param functionName 新的功能函数名.
+ */
+ @Override
+ public void setFunctionName(String functionName) {
+ this.functionName = functionName;
+ }
+
+ /**
+ * 设置功能参数
+ * @param key 参数名
+ * @param value 参数值, 如果参数值为 {@code null} 则删除该参数.
+ * @throws NullPointerException 当 key 为 null 时抛出.
+ */
+ @Override
+ public void setProperty(String key, String value) {
+ Objects.requireNonNull(key);
+ if(value == null) {
+ functionProperties.remove(key);
+ return;
+ }
+ functionProperties.put(key, value);
+ }
+
+ /**
+ * 获取功能参数
+ * @param key 参数名
+ * @return 如果存在, 返回参数名, 否则返回 {@code null}.
+ * @throws NullPointerException 当 key 为 null 时抛出.
+ */
+ @Override
+ public String getProperty(String key) {
+ return functionProperties.get(Objects.requireNonNull(key));
+ }
+
+ @Override
+ public Set getPropertiesKeys() {
+ return Collections.unmodifiableSet(functionProperties.keySet());
+ }
+
+}
diff --git a/ContentGrabbingJi-framework-api/src/main/java/net/lamgc/cgj/bot/framework/message/BotCode.java b/ContentGrabbingJi-framework-api/src/main/java/net/lamgc/cgj/bot/framework/message/BotCode.java
index f3db467..275bf24 100644
--- a/ContentGrabbingJi-framework-api/src/main/java/net/lamgc/cgj/bot/framework/message/BotCode.java
+++ b/ContentGrabbingJi-framework-api/src/main/java/net/lamgc/cgj/bot/framework/message/BotCode.java
@@ -18,9 +18,6 @@
package net.lamgc.cgj.bot.framework.message;
import net.lamgc.cgj.bot.framework.Platform;
-import net.lamgc.cgj.bot.framework.message.exception.BuildBotCodeException;
-import net.lamgc.cgj.bot.framework.message.exception.InvalidBotCodeException;
-import net.lamgc.cgj.bot.framework.message.exception.UnsupportedBotCodeException;
import java.util.Set;
@@ -36,23 +33,6 @@ public interface BotCode {
*/
Platform getPlatform();
- /**
- * 转换为平台或框架可识别并处理的BotCode字符串形式.
- * @return 返回转换后的结果.
- * @throws UnsupportedBotCodeException 当框架不支持该 BotCode 时抛出.
- * @throws BuildBotCodeException 当 BotCode 无法构造出字符串形式时抛出, 包含原因.
- */
- String toBotCodeString() throws UnsupportedBotCodeException, BuildBotCodeException;
-
- /**
- * 从 BotCode 字符串转换成 BotCode 对象.
- * @param botCodeString 传入的 BotCode 字符串.
- * @throws InvalidBotCodeException 当传入的 BotCode 字符串无法转换成该实现对应的 BotCode 对象时可抛出该异常,
- * 务必在异常中清晰说明异常原因.
- * @throws UnsupportedBotCodeException 当框架不支持该 BotCode 时抛出.
- */
- void fromBotCodeString(String botCodeString) throws InvalidBotCodeException, UnsupportedBotCodeException;
-
/**
* 取功能函数名.
* @return 返回功能函数名.
diff --git a/ContentGrabbingJi-framework-api/src/main/java/net/lamgc/cgj/bot/framework/message/BotCodeConverter.java b/ContentGrabbingJi-framework-api/src/main/java/net/lamgc/cgj/bot/framework/message/BotCodeConverter.java
new file mode 100644
index 0000000..7d41633
--- /dev/null
+++ b/ContentGrabbingJi-framework-api/src/main/java/net/lamgc/cgj/bot/framework/message/BotCodeConverter.java
@@ -0,0 +1,48 @@
+/*
+ * Copyright (C) 2020 LamGC
+ *
+ * ContentGrabbingJi is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as
+ * published by the Free Software Foundation, either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * ContentGrabbingJi is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see .
+ */
+
+package net.lamgc.cgj.bot.framework.message;
+
+import net.lamgc.cgj.bot.framework.message.exception.BuildBotCodeException;
+import net.lamgc.cgj.bot.framework.message.exception.InvalidBotCodeException;
+import net.lamgc.cgj.bot.framework.message.exception.UnsupportedBotCodeException;
+
+/**
+ * BotCode 转换器.
+ * @author LamGC
+ */
+public interface BotCodeConverter {
+
+ /**
+ * 转换为平台或框架可识别并处理的 BotCode 字符串形式.
+ * @param botCode BotCode 对象.
+ * @return 返回转换后的结果.
+ * @throws UnsupportedBotCodeException 当框架不支持该 BotCode 时抛出.
+ * @throws BuildBotCodeException 当 BotCode 无法构造出字符串形式时抛出, 包含原因.
+ */
+ String toBotCodeString(BotCode botCode) throws UnsupportedBotCodeException, BuildBotCodeException;
+
+ /**
+ * 从 BotCode 字符串转换成 BotCode 对象.
+ * @param botCodeString 传入的 BotCode 字符串.
+ * @throws InvalidBotCodeException 当传入的 BotCode 字符串无法转换成该实现对应的 BotCode 对象时可抛出该异常,
+ * 务必在异常中清晰说明异常原因.
+ * @throws UnsupportedBotCodeException 当框架不支持该 BotCode 时抛出.
+ */
+ void fromBotCodeString(String botCodeString) throws InvalidBotCodeException, UnsupportedBotCodeException;
+
+}