Compare commits
11 Commits
dd1da27b7c
...
25e546e024
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
25e546e024 | ||
|
|
d10845eb7e | ||
|
|
a6c22cd132 | ||
|
|
d81b7beb05 | ||
|
|
3f52da2575 | ||
|
|
86ce1f5d80 | ||
|
|
3cbc35e558 | ||
|
|
89404411f1 | ||
|
|
f226ad20d1 | ||
|
|
9347b5f4e4 | ||
| e20286c47d |
8
.gitignore
vendored
Normal file
8
.gitignore
vendored
Normal file
@@ -0,0 +1,8 @@
|
||||
.idea
|
||||
.classpath
|
||||
.project
|
||||
*.iml
|
||||
target/
|
||||
.DS_Store
|
||||
.gitattributes
|
||||
log/
|
||||
2
.idea/Design-pattern.iml
generated
2
.idea/Design-pattern.iml
generated
@@ -1,2 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<module type="JAVA_MODULE" version="4" />
|
||||
1
.idea/compiler.xml
generated
1
.idea/compiler.xml
generated
@@ -2,6 +2,7 @@
|
||||
<project version="4">
|
||||
<component name="CompilerConfiguration">
|
||||
<annotationProcessing>
|
||||
<profile default="true" name="Default" enabled="true" />
|
||||
<profile name="Maven default annotation processors profile" enabled="true">
|
||||
<sourceOutputDir name="target/generated-sources/annotations" />
|
||||
<sourceTestOutputDir name="target/generated-test-sources/test-annotations" />
|
||||
|
||||
5
.idea/jarRepositories.xml
generated
5
.idea/jarRepositories.xml
generated
@@ -6,6 +6,11 @@
|
||||
<option name="name" value="Central Repository" />
|
||||
<option name="url" value="https://repo.maven.apache.org/maven2" />
|
||||
</remote-repository>
|
||||
<remote-repository>
|
||||
<option name="id" value="central" />
|
||||
<option name="name" value="Central Repository" />
|
||||
<option name="url" value="http://maven.aliyun.com/nexus/content/groups/public/" />
|
||||
</remote-repository>
|
||||
<remote-repository>
|
||||
<option name="id" value="central" />
|
||||
<option name="name" value="Maven Central repository" />
|
||||
|
||||
2
.idea/misc.xml
generated
2
.idea/misc.xml
generated
@@ -11,7 +11,7 @@
|
||||
</list>
|
||||
</option>
|
||||
</component>
|
||||
<component name="ProjectRootManager" version="2" languageLevel="JDK_1_8" project-jdk-name="1.8" project-jdk-type="JavaSDK">
|
||||
<component name="ProjectRootManager" version="2" languageLevel="JDK_17" project-jdk-name="17" project-jdk-type="JavaSDK">
|
||||
<output url="file://$PROJECT_DIR$/out" />
|
||||
</component>
|
||||
</project>
|
||||
11
pom.xml
11
pom.xml
@@ -12,8 +12,8 @@
|
||||
|
||||
<properties>
|
||||
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
||||
<maven.compiler.source>1.8</maven.compiler.source>
|
||||
<maven.compiler.target>1.8</maven.compiler.target>
|
||||
<maven.compiler.source>17</maven.compiler.source>
|
||||
<maven.compiler.target>17</maven.compiler.target>
|
||||
<org.springframework.version>5.1.0.RELEASE</org.springframework.version>
|
||||
</properties>
|
||||
|
||||
@@ -148,6 +148,13 @@
|
||||
<version>8.0.16</version>
|
||||
</dependency>
|
||||
|
||||
<!-- https://mvnrepository.com/artifact/com.alibaba/fastjson -->
|
||||
<dependency>
|
||||
<groupId>com.alibaba</groupId>
|
||||
<artifactId>fastjson</artifactId>
|
||||
<version>1.2.79</version>
|
||||
</dependency>
|
||||
|
||||
</dependencies>
|
||||
|
||||
<build>
|
||||
|
||||
@@ -0,0 +1,12 @@
|
||||
package top.fjy8018.designpattern.pattern.behavior.strategy.spring;
|
||||
|
||||
/**
|
||||
* @author F嘉阳
|
||||
* @date 2021-12-27 21:37
|
||||
*/
|
||||
public class CommonPairResponse<T, R> {
|
||||
|
||||
public static <T, R> CommonPairResponse<T, R> success(String s, Object o) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,45 @@
|
||||
package top.fjy8018.designpattern.pattern.behavior.strategy.spring;
|
||||
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
/**
|
||||
* HSF 模式的提交
|
||||
*
|
||||
* @author F嘉阳
|
||||
* @date 2021-12-27 21:43
|
||||
*/
|
||||
@Slf4j
|
||||
@Component
|
||||
public class FormHsfSubmitHandler implements FormSubmitHandler<Serializable> {
|
||||
/**
|
||||
* 获得提交类型(返回值也可以使用已经存在的枚举类)
|
||||
*
|
||||
* @return 提交类型
|
||||
*/
|
||||
@Override
|
||||
public String getSubmitType() {
|
||||
return "hsf";
|
||||
}
|
||||
|
||||
/**
|
||||
* 处理表单提交请求
|
||||
*
|
||||
* @param request 请求
|
||||
* @return 响应,left 为返回给前端的提示信息,right 为业务值
|
||||
*/
|
||||
@Override
|
||||
public CommonPairResponse<String, Serializable> handleSubmit(FormSubmitRequest request) {
|
||||
log.info("HSF 模式提交:userId={}, formInput={}", request.getUserId(), request.getFormInput());
|
||||
// 进行 HSF 泛化调用,获得业务方返回的提示信息和业务数据
|
||||
CommonPairResponse<String, Serializable> response = hsfSubmitData(request);
|
||||
|
||||
return response;
|
||||
}
|
||||
|
||||
private CommonPairResponse<String, Serializable> hsfSubmitData(FormSubmitRequest request) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,43 @@
|
||||
package top.fjy8018.designpattern.pattern.behavior.strategy.spring;
|
||||
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
/**
|
||||
* 模型输入时的提交
|
||||
*
|
||||
* @author F嘉阳
|
||||
* @date 2021-12-27 21:40
|
||||
*/
|
||||
@Slf4j
|
||||
@Component
|
||||
public class FormModelSubmitHandler implements FormSubmitHandler<Long> {
|
||||
/**
|
||||
* 获得提交类型(返回值也可以使用已经存在的枚举类)
|
||||
*
|
||||
* @return 提交类型
|
||||
*/
|
||||
@Override
|
||||
public String getSubmitType() {
|
||||
return "model";
|
||||
}
|
||||
|
||||
/**
|
||||
* 处理表单提交请求
|
||||
*
|
||||
* @param request 请求
|
||||
* @return 响应,left 为返回给前端的提示信息,right 为业务值
|
||||
*/
|
||||
@Override
|
||||
public CommonPairResponse<String, Long> handleSubmit(FormSubmitRequest request) {
|
||||
log.info("模型提交:userId={}, formInput={}", request.getUserId(), request.getFormInput());
|
||||
// 模型创建成功后获得模型的 id
|
||||
Long modelId = createModel(request);
|
||||
return CommonPairResponse.success("模型提交成功!", modelId);
|
||||
}
|
||||
|
||||
private Long createModel(FormSubmitRequest request) {
|
||||
// 创建模型的逻辑
|
||||
return 123L;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,39 @@
|
||||
package top.fjy8018.designpattern.pattern.behavior.strategy.spring;
|
||||
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
/**
|
||||
* 预览表单时的提交
|
||||
*
|
||||
* @author F嘉阳
|
||||
* @date 2021-12-27 21:39
|
||||
*/
|
||||
@Slf4j
|
||||
@Component
|
||||
public class FormPreviewSubmitHandler implements FormSubmitHandler<Serializable> {
|
||||
/**
|
||||
* 获得提交类型(返回值也可以使用已经存在的枚举类)
|
||||
*
|
||||
* @return 提交类型
|
||||
*/
|
||||
@Override
|
||||
public String getSubmitType() {
|
||||
return "preview";
|
||||
}
|
||||
|
||||
/**
|
||||
* 处理表单提交请求
|
||||
*
|
||||
* @param request 请求
|
||||
* @return 响应,left 为返回给前端的提示信息,right 为业务值
|
||||
*/
|
||||
@Override
|
||||
public CommonPairResponse<String, Serializable> handleSubmit(FormSubmitRequest request) {
|
||||
log.info("预览模式提交:userId={}, formInput={}", request.getUserId(), request.getFormInput());
|
||||
|
||||
return CommonPairResponse.success("预览模式提交数据成功!", null);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
package top.fjy8018.designpattern.pattern.behavior.strategy.spring;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
/**
|
||||
* 表单提交处理器
|
||||
*
|
||||
* @author F嘉阳
|
||||
* @date 2021-12-27 21:36
|
||||
*/
|
||||
public interface FormSubmitHandler<R extends Serializable> {
|
||||
/**
|
||||
* 获得提交类型(返回值也可以使用已经存在的枚举类)
|
||||
*
|
||||
* @return 提交类型
|
||||
*/
|
||||
String getSubmitType();
|
||||
|
||||
/**
|
||||
* 处理表单提交请求
|
||||
*
|
||||
* @param request 请求
|
||||
* @return 响应,left 为返回给前端的提示信息,right 为业务值
|
||||
*/
|
||||
CommonPairResponse<String, R> handleSubmit(FormSubmitRequest request);
|
||||
}
|
||||
@@ -0,0 +1,57 @@
|
||||
package top.fjy8018.designpattern.pattern.behavior.strategy.spring;
|
||||
|
||||
import org.checkerframework.checker.nullness.qual.NonNull;
|
||||
import org.springframework.beans.factory.InitializingBean;
|
||||
import org.springframework.context.ApplicationContext;
|
||||
import org.springframework.context.ApplicationContextAware;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* 策略的简单工厂
|
||||
* 让 FormSubmitHandlerFactory 实现 InitializingBean 接口,在 afterPropertiesSet
|
||||
* 方法中,基于 Spring 容器将所有 FormSubmitHandler 自动注册到 FORM_SUBMIT_HANDLER_MAP,
|
||||
* 从而 Spring 容器启动完成后, getHandler 方法可以直接通过 submitType
|
||||
* 来获取对应的表单提交处理器
|
||||
* <p>
|
||||
* Factory 只负责获取 Handler,Handler 只负责处理具体的提交,Service 只负责逻辑编排,
|
||||
* 从而达到功能上的 “低耦合高内聚”。
|
||||
*
|
||||
* @author F嘉阳
|
||||
* @date 2021-12-27 21:44
|
||||
*/
|
||||
@Component
|
||||
public class FormSubmitHandlerFactory implements InitializingBean, ApplicationContextAware {
|
||||
|
||||
private static final Map<String, FormSubmitHandler<Serializable>> FORM_SUBMIT_HANDLER_MAP = new HashMap<>(8);
|
||||
|
||||
private ApplicationContext appContext;
|
||||
|
||||
/**
|
||||
* 根据提交类型获取对应的处理器
|
||||
*
|
||||
* @param submitType 提交类型
|
||||
* @return 提交类型对应的处理器
|
||||
*/
|
||||
public FormSubmitHandler<Serializable> getHandler(String submitType) {
|
||||
return FORM_SUBMIT_HANDLER_MAP.get(submitType);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void afterPropertiesSet() {
|
||||
// 将 Spring 容器中所有的 FormSubmitHandler 注册到 FORM_SUBMIT_HANDLER_MAP
|
||||
appContext.getBeansOfType(FormSubmitHandler.class)
|
||||
.values()
|
||||
.forEach(handler -> FORM_SUBMIT_HANDLER_MAP.put(handler.getSubmitType(), handler));
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setApplicationContext(@NonNull ApplicationContext applicationContext) {
|
||||
appContext = applicationContext;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,39 @@
|
||||
package top.fjy8018.designpattern.pattern.behavior.strategy.spring;
|
||||
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* 表单提交的请求
|
||||
* FormSubmitHandler 的 getSubmitType 方法用来获取表单的提交类型(即策略类
|
||||
* 型),用于根据客户端传递的参数直接获取到对应的策略实现;客户端传递的相关参数都被
|
||||
* 封装为 FormSubmitRequest,传递给 handleSubmit 进行处理。
|
||||
*
|
||||
* @author F嘉阳
|
||||
* @date 2021-12-27 21:37
|
||||
*/
|
||||
@Getter
|
||||
@Setter
|
||||
public class FormSubmitRequest {
|
||||
|
||||
/**
|
||||
* 提交类型
|
||||
*
|
||||
* @see FormSubmitHandler#getSubmitType()
|
||||
*/
|
||||
private String submitType;
|
||||
|
||||
/**
|
||||
* 用户 id
|
||||
*/
|
||||
private Long userId;
|
||||
|
||||
/**
|
||||
* 表单提交的值
|
||||
*/
|
||||
private Map<String, Object> formInput;
|
||||
|
||||
// 其他属性
|
||||
}
|
||||
@@ -0,0 +1,109 @@
|
||||
package top.fjy8018.designpattern.pattern.behavior.templatemethod.spring.after;
|
||||
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import top.fjy8018.designpattern.pattern.behavior.templatemethod.spring.bean.*;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 表单项转换的操作流程,即如下的 convert 方法(使用 final 修饰,确保子类不可修改操作流程)
|
||||
*
|
||||
* @author F嘉阳
|
||||
* @date 2022/1/26 09:50
|
||||
*/
|
||||
public abstract class AbstractFormItemConverter {
|
||||
/**
|
||||
* 子类可处理的表单项类型
|
||||
*/
|
||||
public abstract ComponentTypeEnum getType();
|
||||
|
||||
/**
|
||||
* 将输入的配置转变为表单项的操作流程
|
||||
*
|
||||
* @param config 前端输入的配置
|
||||
* @return 表单项
|
||||
*/
|
||||
public final FormItem convert(FormItemConfig config) {
|
||||
FormItem item = createItem(config);
|
||||
// 表单项创建完成之后,子类如果需要特殊处理,可覆写该方法
|
||||
afterItemCreate(item, config);
|
||||
|
||||
FormComponentProps props = createComponentProps(config);
|
||||
item.setComponentProps(props);
|
||||
// 组件属性创建完成之后,子类如果需要特殊处理,可覆写该方法
|
||||
afterPropsCreate(props, config);
|
||||
|
||||
List<FormItemRule> rules = createRules(config);
|
||||
item.setRules(rules);
|
||||
// 约束规则创建完成之后,子类如果需要特殊处理,可覆写该方法
|
||||
afterRulesCreate(rules, config);
|
||||
|
||||
return item;
|
||||
}
|
||||
|
||||
/**
|
||||
* 共用逻辑:创建表单项、设置通用的表单项属性
|
||||
*/
|
||||
private FormItem createItem(FormItemConfig config) {
|
||||
FormItem formItem = new FormItem();
|
||||
|
||||
formItem.setCode(config.getCode());
|
||||
formItem.setTitle(config.getTitle());
|
||||
formItem.setComponent(config.getComponent());
|
||||
|
||||
return formItem;
|
||||
}
|
||||
|
||||
/**
|
||||
* 表单项创建完成之后,子类如果需要特殊处理,可覆写该方法
|
||||
*/
|
||||
protected void afterItemCreate(FormItem item, FormItemConfig config) {
|
||||
}
|
||||
|
||||
/**
|
||||
* 共用逻辑:创建组件属性、设置通用的组件属性
|
||||
*/
|
||||
private FormComponentProps createComponentProps(FormItemConfig config) {
|
||||
FormComponentProps props = new FormComponentProps();
|
||||
|
||||
if (config.isReadOnly()) {
|
||||
props.setReadOnly(true);
|
||||
}
|
||||
|
||||
if (StringUtils.isNotBlank(config.getPlaceholder())) {
|
||||
props.setPlaceholder(config.getPlaceholder());
|
||||
}
|
||||
|
||||
return props;
|
||||
}
|
||||
|
||||
/**
|
||||
* 组件属性创建完成之后,子类如果需要特殊处理,可覆写该方法
|
||||
*/
|
||||
protected void afterPropsCreate(FormComponentProps props, FormItemConfig config) {
|
||||
}
|
||||
|
||||
/**
|
||||
* 共用逻辑:创建约束规则、设置通用的约束规则
|
||||
*/
|
||||
private List<FormItemRule> createRules(FormItemConfig config) {
|
||||
List<FormItemRule> rules = new ArrayList<>(4);
|
||||
|
||||
if (config.isRequired()) {
|
||||
FormItemRule requiredRule = new FormItemRule();
|
||||
requiredRule.setRequired(true);
|
||||
requiredRule.setMessage("请输入" + config.getTitle());
|
||||
|
||||
rules.add(requiredRule);
|
||||
}
|
||||
|
||||
return rules;
|
||||
}
|
||||
|
||||
/**
|
||||
* 约束规则创建完成之后,子类如果需要特殊处理,可覆写该方法
|
||||
*/
|
||||
protected void afterRulesCreate(List<FormItemRule> rules, FormItemConfig config) {
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,46 @@
|
||||
package top.fjy8018.designpattern.pattern.behavior.templatemethod.spring.after;
|
||||
|
||||
import org.springframework.stereotype.Component;
|
||||
import top.fjy8018.designpattern.pattern.behavior.templatemethod.spring.bean.FormItemConfig;
|
||||
import top.fjy8018.designpattern.pattern.behavior.templatemethod.spring.bean.FormItemRule;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 通用文本类转换器
|
||||
*
|
||||
* @author F嘉阳
|
||||
* @date 2022/1/26 09:54
|
||||
*/
|
||||
@Component
|
||||
public abstract class AbstractTextConverter extends AbstractFormItemConverter {
|
||||
|
||||
/**
|
||||
* 约束规则创建完成之后,子类如果需要特殊处理,可覆写该方法
|
||||
*
|
||||
* @param rules
|
||||
* @param config
|
||||
*/
|
||||
@Override
|
||||
protected void afterRulesCreate(List<FormItemRule> rules, FormItemConfig config) {
|
||||
Integer minLength = config.getMinLength();
|
||||
|
||||
if (minLength != null && minLength > 0) {
|
||||
FormItemRule minRule = new FormItemRule();
|
||||
minRule.setMin(minLength);
|
||||
minRule.setMessage("请至少输入 " + minLength + " 个字");
|
||||
|
||||
rules.add(minRule);
|
||||
}
|
||||
|
||||
Integer maxLength = config.getMaxLength();
|
||||
|
||||
if (maxLength != null && maxLength > 0) {
|
||||
FormItemRule maxRule = new FormItemRule();
|
||||
maxRule.setMax(maxLength);
|
||||
maxRule.setMessage("请最多输入 " + maxLength + " 个字");
|
||||
|
||||
rules.add(maxRule);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
package top.fjy8018.designpattern.pattern.behavior.templatemethod.spring.after;
|
||||
|
||||
import org.springframework.stereotype.Component;
|
||||
import top.fjy8018.designpattern.pattern.behavior.templatemethod.spring.bean.ComponentTypeEnum;
|
||||
import top.fjy8018.designpattern.pattern.behavior.templatemethod.spring.bean.FormComponentProps;
|
||||
import top.fjy8018.designpattern.pattern.behavior.templatemethod.spring.bean.FormItemConfig;
|
||||
|
||||
/**
|
||||
* 下拉选择框的转换器
|
||||
*
|
||||
* @author F嘉阳
|
||||
* @date 2022/1/26 09:51
|
||||
*/
|
||||
@Component
|
||||
public class DropdownSelectConverter extends AbstractFormItemConverter {
|
||||
/**
|
||||
* 子类可处理的表单项类型
|
||||
*/
|
||||
@Override
|
||||
public ComponentTypeEnum getType() {
|
||||
return ComponentTypeEnum.DROPDOWN_SELECT;
|
||||
}
|
||||
|
||||
/**
|
||||
* 组件属性创建完成之后,子类如果需要特殊处理,可覆写该方法
|
||||
*
|
||||
* @param props
|
||||
* @param config
|
||||
*/
|
||||
@Override
|
||||
protected void afterPropsCreate(FormComponentProps props, FormItemConfig config) {
|
||||
props.setAutoWidth(false);
|
||||
|
||||
if (config.isMultiple()) {
|
||||
props.setMode("multiple");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
package top.fjy8018.designpattern.pattern.behavior.templatemethod.spring.after;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Component;
|
||||
import top.fjy8018.designpattern.pattern.behavior.templatemethod.spring.bean.ComponentTypeEnum;
|
||||
|
||||
import java.util.EnumMap;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 简单工厂
|
||||
*
|
||||
* @author F嘉阳
|
||||
* @date 2022/1/26 09:56
|
||||
*/
|
||||
@Component
|
||||
public class FormItemConverterFactory {
|
||||
|
||||
private static final EnumMap<ComponentTypeEnum, AbstractFormItemConverter> CONVERTER_MAP = new EnumMap<>(ComponentTypeEnum.class);
|
||||
|
||||
/**
|
||||
* 根据表单项类型获得对应的转换器
|
||||
*
|
||||
* @param type 表单项类型
|
||||
* @return 表单项转换器
|
||||
*/
|
||||
public AbstractFormItemConverter getConverter(ComponentTypeEnum type) {
|
||||
return CONVERTER_MAP.get(type);
|
||||
}
|
||||
|
||||
@Autowired
|
||||
public void setConverters(List<AbstractFormItemConverter> converters) {
|
||||
for (final AbstractFormItemConverter converter : converters) {
|
||||
CONVERTER_MAP.put(converter.getType(), converter);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,46 @@
|
||||
package top.fjy8018.designpattern.pattern.behavior.templatemethod.spring.after;
|
||||
|
||||
import org.springframework.stereotype.Component;
|
||||
import top.fjy8018.designpattern.pattern.behavior.templatemethod.spring.bean.ComponentTypeEnum;
|
||||
import top.fjy8018.designpattern.pattern.behavior.templatemethod.spring.bean.FormComponentProps;
|
||||
import top.fjy8018.designpattern.pattern.behavior.templatemethod.spring.bean.FormItem;
|
||||
import top.fjy8018.designpattern.pattern.behavior.templatemethod.spring.bean.FormItemConfig;
|
||||
|
||||
/**
|
||||
* 模糊搜索框的转换器
|
||||
*
|
||||
* @author F嘉阳
|
||||
* @date 2022/1/26 09:53
|
||||
*/
|
||||
@Component
|
||||
public class FuzzySearchConverter extends AbstractFormItemConverter {
|
||||
/**
|
||||
* 子类可处理的表单项类型
|
||||
*/
|
||||
@Override
|
||||
public ComponentTypeEnum getType() {
|
||||
return ComponentTypeEnum.FUZZY_SEARCH;
|
||||
}
|
||||
|
||||
/**
|
||||
* 表单项创建完成之后,子类如果需要特殊处理,可覆写该方法
|
||||
*
|
||||
* @param item
|
||||
* @param config
|
||||
*/
|
||||
@Override
|
||||
protected void afterItemCreate(FormItem item, FormItemConfig config) {
|
||||
item.setFuzzySearch(true);
|
||||
}
|
||||
|
||||
/**
|
||||
* 组件属性创建完成之后,子类如果需要特殊处理,可覆写该方法
|
||||
*
|
||||
* @param props
|
||||
* @param config
|
||||
*/
|
||||
@Override
|
||||
protected void afterPropsCreate(FormComponentProps props, FormItemConfig config) {
|
||||
props.setAutoWidth(false);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,61 @@
|
||||
package top.fjy8018.designpattern.pattern.behavior.templatemethod.spring.after;
|
||||
|
||||
import org.springframework.stereotype.Component;
|
||||
import top.fjy8018.designpattern.pattern.behavior.templatemethod.spring.bean.ComponentTypeEnum;
|
||||
import top.fjy8018.designpattern.pattern.behavior.templatemethod.spring.bean.FormItemConfig;
|
||||
import top.fjy8018.designpattern.pattern.behavior.templatemethod.spring.bean.FormItemRule;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 此时要加入一种新的表单项 —— 数字选择器(NUMBER_PICKER),
|
||||
* 它有着特殊的约束条件:最小值和最大值,输入到 FormItemConfig 时分别为 minNumer 和 maxNumber
|
||||
* <p>
|
||||
* 只需要添加对应的枚举和实现对应的 FormItemConverter,并不需要修改任何逻辑代码,
|
||||
* 因为 Spring 启动时会自动帮我们处理好 NUMBER_PICKER 和 NumberPickerConverter 的关联关系 —— 完美符合 “开闭原则”
|
||||
*
|
||||
* @author F嘉阳
|
||||
* @date 2022/1/26 10:13
|
||||
*/
|
||||
@Component
|
||||
public class NumberPickerConverter extends AbstractFormItemConverter {
|
||||
|
||||
/**
|
||||
* 子类可处理的表单项类型
|
||||
*/
|
||||
@Override
|
||||
public ComponentTypeEnum getType() {
|
||||
return ComponentTypeEnum.NUMBER_PICKER;
|
||||
}
|
||||
|
||||
/**
|
||||
* 约束规则创建完成之后,子类如果需要特殊处理,可覆写该方法
|
||||
*
|
||||
* @param rules
|
||||
* @param config
|
||||
*/
|
||||
@Override
|
||||
protected void afterRulesCreate(List<FormItemRule> rules, FormItemConfig config) {
|
||||
Integer minNumber = config.getMinNumber();
|
||||
// 处理最小值
|
||||
if (minNumber != null) {
|
||||
FormItemRule minNumRule = new FormItemRule();
|
||||
|
||||
minNumRule.setMinimum(minNumber);
|
||||
minNumRule.setMessage("输入数字不能小于 " + minNumber);
|
||||
|
||||
rules.add(minNumRule);
|
||||
}
|
||||
|
||||
Integer maxNumber = config.getMaxNumber();
|
||||
// 处理最大值
|
||||
if (maxNumber != null) {
|
||||
FormItemRule maxNumRule = new FormItemRule();
|
||||
|
||||
maxNumRule.setMaximum(maxNumber);
|
||||
maxNumRule.setMessage("输入数字不能大于 " + maxNumber);
|
||||
|
||||
rules.add(maxNumRule);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
package top.fjy8018.designpattern.pattern.behavior.templatemethod.spring.after;
|
||||
|
||||
import org.springframework.stereotype.Component;
|
||||
import top.fjy8018.designpattern.pattern.behavior.templatemethod.spring.bean.ComponentTypeEnum;
|
||||
|
||||
/**
|
||||
* 多行文本框的转换器
|
||||
*
|
||||
* @author F嘉阳
|
||||
* @date 2022/1/26 09:56
|
||||
*/
|
||||
@Component
|
||||
public class TextAreaConvertor extends AbstractTextConverter {
|
||||
|
||||
/**
|
||||
* 子类可处理的表单项类型
|
||||
*/
|
||||
@Override
|
||||
public ComponentTypeEnum getType() {
|
||||
return ComponentTypeEnum.TEXT_AREA;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
package top.fjy8018.designpattern.pattern.behavior.templatemethod.spring.after;
|
||||
|
||||
import org.springframework.stereotype.Component;
|
||||
import top.fjy8018.designpattern.pattern.behavior.templatemethod.spring.bean.ComponentTypeEnum;
|
||||
|
||||
/**
|
||||
* 单行文本框的转换器
|
||||
*
|
||||
* @author F嘉阳
|
||||
* @date 2022/1/26 09:55
|
||||
*/
|
||||
@Component
|
||||
public class TextInputConverter extends AbstractTextConverter {
|
||||
|
||||
/**
|
||||
* 子类可处理的表单项类型
|
||||
*/
|
||||
@Override
|
||||
public ComponentTypeEnum getType() {
|
||||
return ComponentTypeEnum.TEXT_INPUT;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
package top.fjy8018.designpattern.pattern.behavior.templatemethod.spring.bean;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Getter;
|
||||
|
||||
/**
|
||||
* TODO:
|
||||
*
|
||||
* @author F嘉阳
|
||||
* @date 2022/1/26 09:43
|
||||
*/
|
||||
@Getter
|
||||
@AllArgsConstructor
|
||||
public enum ComponentTypeEnum {
|
||||
DROPDOWN_SELECT,
|
||||
FUZZY_SEARCH,
|
||||
TEXT_INPUT,
|
||||
TEXT_AREA,
|
||||
NUMBER_PICKER;
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
package top.fjy8018.designpattern.pattern.behavior.templatemethod.spring.bean;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
/**
|
||||
* TODO:
|
||||
*
|
||||
* @author F嘉阳
|
||||
* @date 2022/1/26 09:40
|
||||
*/
|
||||
@Data
|
||||
public class FormComponentProps {
|
||||
|
||||
private boolean readOnly;
|
||||
|
||||
private boolean autoWidth;
|
||||
|
||||
private String mode;
|
||||
|
||||
private String placeholder;
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
package top.fjy8018.designpattern.pattern.behavior.templatemethod.spring.bean;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* TODO:
|
||||
*
|
||||
* @author F嘉阳
|
||||
* @date 2022/1/26 09:39
|
||||
*/
|
||||
@Data
|
||||
public class FormItem {
|
||||
|
||||
private String title;
|
||||
|
||||
private String code;
|
||||
|
||||
private String component;
|
||||
|
||||
private FormComponentProps componentProps;
|
||||
|
||||
private boolean fuzzySearch;
|
||||
|
||||
private List<FormItemRule> rules;
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
package top.fjy8018.designpattern.pattern.behavior.templatemethod.spring.bean;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
/**
|
||||
* TODO:
|
||||
*
|
||||
* @author F嘉阳
|
||||
* @date 2022/1/26 09:39
|
||||
*/
|
||||
@Data
|
||||
public class FormItemConfig {
|
||||
|
||||
private String title;
|
||||
|
||||
private String code;
|
||||
|
||||
private String component;
|
||||
|
||||
private boolean readOnly;
|
||||
|
||||
private ComponentTypeEnum type;
|
||||
|
||||
private boolean multiple;
|
||||
|
||||
private boolean required;
|
||||
|
||||
private Integer minLength;
|
||||
|
||||
private Integer maxLength;
|
||||
|
||||
private String placeholder;
|
||||
|
||||
private Integer minNumber;
|
||||
|
||||
private Integer maxNumber;
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
package top.fjy8018.designpattern.pattern.behavior.templatemethod.spring.bean;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
/**
|
||||
* TODO:
|
||||
*
|
||||
* @author F嘉阳
|
||||
* @date 2022/1/26 09:46
|
||||
*/
|
||||
@Data
|
||||
public class FormItemRule {
|
||||
|
||||
private boolean required;
|
||||
|
||||
private String message;
|
||||
|
||||
private Integer min;
|
||||
|
||||
private Integer max;
|
||||
|
||||
private Integer minimum;
|
||||
|
||||
private Integer maximum;
|
||||
}
|
||||
@@ -0,0 +1,104 @@
|
||||
package top.fjy8018.designpattern.pattern.behavior.templatemethod.spring.before;
|
||||
|
||||
import top.fjy8018.designpattern.pattern.behavior.templatemethod.spring.bean.*;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 原始逻辑
|
||||
* <p>
|
||||
* 代码违反了 开闭原则(对扩展开放,对修改关闭):如果此时需要添加一种新的表单项(包含特殊的组件属性),那么不可避免的要修改 convert 方法来进行新表单项的特殊处理。
|
||||
* <p>
|
||||
* 观察上面的代码,将配置转变为表单项 这个操作,满足以下流程:
|
||||
* 创建表单项,并设置通用的表单项属性,然后再对不同表单项的特殊属性进行处理
|
||||
* 创建组件属性,处理通用的组件属性,然后再对不同组件的特殊属性进行处理
|
||||
* 创建约束规则,处理通用的约束规则,然后再对不同表单项的特性约束规则进行处理
|
||||
*
|
||||
* @author F嘉阳
|
||||
* @date 2022/1/26 09:38
|
||||
*/
|
||||
public class FormItemConverter {
|
||||
/**
|
||||
* 将输入的配置转变为表单项
|
||||
*
|
||||
* @param config 前端输入的配置
|
||||
* @return 表单项
|
||||
*/
|
||||
public FormItem convert(FormItemConfig config) {
|
||||
FormItem formItem = new FormItem();
|
||||
|
||||
// 公共的表单项属性
|
||||
formItem.setTitle(config.getTitle());
|
||||
formItem.setCode(config.getCode());
|
||||
formItem.setComponent(config.getComponent());
|
||||
|
||||
// 创建表单组件的属性
|
||||
FormComponentProps props = new FormComponentProps();
|
||||
formItem.setComponentProps(props);
|
||||
|
||||
// 公共的组件属性
|
||||
if (config.isReadOnly()) {
|
||||
props.setReadOnly(true);
|
||||
}
|
||||
|
||||
ComponentTypeEnum type = config.getType();
|
||||
|
||||
// 下拉选择框的特殊属性处理
|
||||
if (type == ComponentTypeEnum.DROPDOWN_SELECT) {
|
||||
props.setAutoWidth(false);
|
||||
|
||||
if (config.isMultiple()) {
|
||||
props.setMode("multiple");
|
||||
}
|
||||
}
|
||||
|
||||
// 模糊搜索框的特殊属性处理
|
||||
if (type == ComponentTypeEnum.FUZZY_SEARCH) {
|
||||
formItem.setFuzzySearch(true);
|
||||
props.setAutoWidth(false);
|
||||
}
|
||||
|
||||
// ... 其他组件的特殊处理
|
||||
|
||||
// 创建约束规则
|
||||
List<FormItemRule> rules = new ArrayList<>(2);
|
||||
formItem.setRules(rules);
|
||||
|
||||
// 每个表单项都可有的约束规则
|
||||
if (config.isRequired()) {
|
||||
FormItemRule requiredRule = new FormItemRule();
|
||||
requiredRule.setRequired(true);
|
||||
requiredRule.setMessage("请输入" + config.getTitle());
|
||||
|
||||
rules.add(requiredRule);
|
||||
}
|
||||
|
||||
// 文本输入框才有的规则
|
||||
if (type == ComponentTypeEnum.TEXT_INPUT || type == ComponentTypeEnum.TEXT_AREA) {
|
||||
Integer minLength = config.getMinLength();
|
||||
|
||||
if (minLength != null && minLength > 0) {
|
||||
FormItemRule minRule = new FormItemRule();
|
||||
minRule.setMin(minLength);
|
||||
minRule.setMessage("请至少输入 " + minLength + " 个字");
|
||||
|
||||
rules.add(minRule);
|
||||
}
|
||||
|
||||
Integer maxLength = config.getMaxLength();
|
||||
|
||||
if (maxLength != null && maxLength > 0) {
|
||||
FormItemRule maxRule = new FormItemRule();
|
||||
maxRule.setMax(maxLength);
|
||||
maxRule.setMessage("请最多输入 " + maxLength + " 个字");
|
||||
|
||||
rules.add(maxRule);
|
||||
}
|
||||
}
|
||||
|
||||
// ... 其他约束规则
|
||||
|
||||
return formItem;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
package top.fjy8018.designpattern.pattern.behavior.visitor.spring.after;
|
||||
|
||||
import top.fjy8018.designpattern.pattern.behavior.visitor.spring.bean.Building;
|
||||
import top.fjy8018.designpattern.pattern.behavior.visitor.spring.bean.Factory;
|
||||
import top.fjy8018.designpattern.pattern.behavior.visitor.spring.bean.Node;
|
||||
import top.fjy8018.designpattern.pattern.behavior.visitor.spring.bean.School;
|
||||
|
||||
/**
|
||||
* TODO:
|
||||
*
|
||||
* @author F嘉阳
|
||||
* @date 2022/1/26 10:31
|
||||
*/
|
||||
public class DrawVisitor implements Visitor {
|
||||
@Override
|
||||
public void visit(Node node) {
|
||||
System.out.println("draw node");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(Factory factory) {
|
||||
System.out.println("draw factory");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(Building building) {
|
||||
System.out.println("draw building");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(School school) {
|
||||
System.out.println("draw school");
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
package top.fjy8018.designpattern.pattern.behavior.visitor.spring.after;
|
||||
|
||||
import top.fjy8018.designpattern.pattern.behavior.visitor.spring.bean.Building;
|
||||
import top.fjy8018.designpattern.pattern.behavior.visitor.spring.bean.Factory;
|
||||
import top.fjy8018.designpattern.pattern.behavior.visitor.spring.bean.Node;
|
||||
import top.fjy8018.designpattern.pattern.behavior.visitor.spring.bean.School;
|
||||
|
||||
/**
|
||||
* Visitor Pattern
|
||||
*
|
||||
* @author F嘉阳
|
||||
* @date 2022/1/26 10:31
|
||||
*/
|
||||
public interface Visitor {
|
||||
|
||||
void visit(Node node);
|
||||
|
||||
void visit(Factory factory);
|
||||
|
||||
void visit(Building building);
|
||||
|
||||
void visit(School school);
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
package top.fjy8018.designpattern.pattern.behavior.visitor.spring.bean;
|
||||
|
||||
import top.fjy8018.designpattern.pattern.behavior.visitor.spring.after.Visitor;
|
||||
|
||||
/**
|
||||
* TODO:
|
||||
*
|
||||
* @author F嘉阳
|
||||
* @date 2022/1/26 10:18
|
||||
*/
|
||||
public class Building implements Node {
|
||||
@Override
|
||||
public String getName() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getDescription() {
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* 调用方知道visit的参数就是Building类型的,并且知道Visitor::visit(Building)方法确实存在,
|
||||
* 因此会直接调用Visitor::visit(Building)方法
|
||||
*/
|
||||
@Override
|
||||
public void accept(Visitor v) {
|
||||
v.visit(this);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
package top.fjy8018.designpattern.pattern.behavior.visitor.spring.bean;
|
||||
|
||||
import top.fjy8018.designpattern.pattern.behavior.visitor.spring.after.Visitor;
|
||||
|
||||
/**
|
||||
* TODO:
|
||||
*
|
||||
* @author F嘉阳
|
||||
* @date 2022/1/26 10:18
|
||||
*/
|
||||
public class Factory implements Node {
|
||||
@Override
|
||||
public String getName() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getDescription() {
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* 调用方知道visit的参数就是Factory类型的,并且知道Visitor::visit(Factory)方法确实存在,
|
||||
* 因此会直接调用Visitor::visit(Factory)方法
|
||||
*/
|
||||
@Override
|
||||
public void accept(Visitor v) {
|
||||
v.visit(this);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
package top.fjy8018.designpattern.pattern.behavior.visitor.spring.bean;
|
||||
|
||||
import top.fjy8018.designpattern.pattern.behavior.visitor.spring.after.Visitor;
|
||||
|
||||
/**
|
||||
* 地图节点
|
||||
*
|
||||
* @author F嘉阳
|
||||
* @date 2022/1/26 10:17
|
||||
*/
|
||||
public interface Node {
|
||||
|
||||
String getName();
|
||||
|
||||
String getDescription();
|
||||
|
||||
void accept(Visitor v);
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
package top.fjy8018.designpattern.pattern.behavior.visitor.spring.bean;
|
||||
|
||||
import top.fjy8018.designpattern.pattern.behavior.visitor.spring.after.Visitor;
|
||||
|
||||
/**
|
||||
* TODO:
|
||||
*
|
||||
* @author F嘉阳
|
||||
* @date 2022/1/26 10:18
|
||||
*/
|
||||
public class School implements Node {
|
||||
@Override
|
||||
public String getName() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getDescription() {
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* 调用方知道visit的参数就是School类型的,并且知道Visitor::visit(School)方法确实存在,
|
||||
* 因此会直接调用Visitor::visit(School)方法
|
||||
*/
|
||||
@Override
|
||||
public void accept(Visitor v) {
|
||||
v.visit(this);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,33 @@
|
||||
package top.fjy8018.designpattern.pattern.behavior.visitor.spring.before;
|
||||
|
||||
import top.fjy8018.designpattern.pattern.behavior.visitor.spring.bean.Building;
|
||||
import top.fjy8018.designpattern.pattern.behavior.visitor.spring.bean.Factory;
|
||||
import top.fjy8018.designpattern.pattern.behavior.visitor.spring.bean.Node;
|
||||
import top.fjy8018.designpattern.pattern.behavior.visitor.spring.bean.School;
|
||||
|
||||
/**
|
||||
* 新需求:需要加入绘制Node功能
|
||||
* Node接口作为衔接组件的桥梁,应该尽可能保持稳定,不应频繁更改。
|
||||
* 定义一个新的类DrawService,把所有的draw逻辑都写在这里面
|
||||
*
|
||||
* @author F嘉阳
|
||||
* @date 2022/1/26 10:18
|
||||
*/
|
||||
public class DrawService {
|
||||
|
||||
public void draw(Building building) {
|
||||
System.out.println("draw building");
|
||||
}
|
||||
|
||||
public void draw(Factory factory) {
|
||||
System.out.println("draw factory");
|
||||
}
|
||||
|
||||
public void draw(School school) {
|
||||
System.out.println("draw school");
|
||||
}
|
||||
|
||||
public void draw(Node node) {
|
||||
System.out.println("draw node");
|
||||
}
|
||||
}
|
||||
@@ -1,8 +1,5 @@
|
||||
package top.fjy8018.designpattern.pattern.creational.factorymethod;
|
||||
|
||||
import sun.misc.Launcher;
|
||||
|
||||
import java.util.Collection;
|
||||
|
||||
/**
|
||||
* 定义一个创建产品对象的工厂接口,将实际创建工作推迟到子类当中
|
||||
|
||||
@@ -0,0 +1,27 @@
|
||||
package top.fjy8018.designpattern.pattern.creational.factorymethod.spring.after;
|
||||
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import top.fjy8018.designpattern.pattern.creational.factorymethod.spring.bean.FormDataHandler;
|
||||
import top.fjy8018.designpattern.pattern.creational.factorymethod.spring.bean.FormItemConverter;
|
||||
import top.fjy8018.designpattern.pattern.creational.factorymethod.spring.bean.FormItemTypeEnum;
|
||||
|
||||
/**
|
||||
* TODO:
|
||||
*
|
||||
* @author F嘉阳
|
||||
* @date 2022/4/8 14:26
|
||||
*/
|
||||
@Configuration
|
||||
public class FactoryConfig {
|
||||
|
||||
@Bean
|
||||
public StrategyFactory<String, FormDataHandler> formDataHandlerFactory() {
|
||||
return new StrategyFactory<>(FormDataHandler.class);
|
||||
}
|
||||
|
||||
@Bean
|
||||
public StrategyFactory<FormItemTypeEnum, FormItemConverter> formItemConverterFactory() {
|
||||
return new StrategyFactory<>(FormItemConverter.class);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
package top.fjy8018.designpattern.pattern.creational.factorymethod.spring.after;
|
||||
|
||||
/**
|
||||
* TODO:
|
||||
*
|
||||
* @author F嘉阳
|
||||
* @date 2022/4/8 13:42
|
||||
*/
|
||||
public interface Strategy<T> {
|
||||
|
||||
/**
|
||||
* 获得策略的标识
|
||||
*/
|
||||
T getId();
|
||||
}
|
||||
@@ -0,0 +1,64 @@
|
||||
package top.fjy8018.designpattern.pattern.creational.factorymethod.spring.after;
|
||||
|
||||
import com.google.common.collect.Maps;
|
||||
import org.springframework.beans.BeansException;
|
||||
import org.springframework.beans.factory.InitializingBean;
|
||||
import org.springframework.context.ApplicationContext;
|
||||
import org.springframework.context.ApplicationContextAware;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* TODO:
|
||||
*
|
||||
* @author F嘉阳
|
||||
* @date 2022/4/8 13:42
|
||||
*/
|
||||
public class StrategyFactory<T, S extends Strategy<T>> implements InitializingBean, ApplicationContextAware {
|
||||
|
||||
private Map<T, S> strategyMap;
|
||||
|
||||
private ApplicationContext appContext;
|
||||
|
||||
private final Class<S> strategyType;
|
||||
|
||||
/**
|
||||
* 创建一个策略工厂
|
||||
*
|
||||
* @param strategyType 策略的类型
|
||||
*/
|
||||
public StrategyFactory(Class<S> strategyType) {
|
||||
this.strategyType = strategyType;
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据策略 id 获得对应的策略的 Bean
|
||||
*
|
||||
* @param id 策略 id
|
||||
* @return 策略的 Bean
|
||||
*/
|
||||
public S getStrategy(T id) {
|
||||
return strategyMap.get(id);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void afterPropertiesSet() throws Exception {
|
||||
// 获取 Spring 容器中,所有 S 类型的 Bean
|
||||
Collection<S> strategies = appContext.getBeansOfType(strategyType).values();
|
||||
|
||||
strategyMap = Maps.newHashMapWithExpectedSize(strategies.size());
|
||||
|
||||
// 将 所有 S 类型的 Bean 放入到 strategyMap 中
|
||||
for (final S strategy : strategies) {
|
||||
T id = strategy.getId();
|
||||
|
||||
strategyMap.put(id, strategy);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
|
||||
appContext = applicationContext;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
package top.fjy8018.designpattern.pattern.creational.factorymethod.spring.bean;
|
||||
|
||||
/**
|
||||
* TODO:
|
||||
*
|
||||
* @author F嘉阳
|
||||
* @date 2022/4/8 14:16
|
||||
*/
|
||||
public class CommonResponse<T> {
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
package top.fjy8018.designpattern.pattern.creational.factorymethod.spring.bean;
|
||||
|
||||
import top.fjy8018.designpattern.pattern.behavior.strategy.spring.FormSubmitRequest;
|
||||
import top.fjy8018.designpattern.pattern.creational.factorymethod.spring.after.Strategy;
|
||||
|
||||
/**
|
||||
* TODO:
|
||||
*
|
||||
* @author F嘉阳
|
||||
* @date 2022/4/8 13:37
|
||||
*/
|
||||
public interface FormDataHandler extends Strategy<String> {
|
||||
|
||||
/**
|
||||
* 获得策略的标识
|
||||
*/
|
||||
@Override
|
||||
default String getId() {
|
||||
return getFormCode();
|
||||
}
|
||||
|
||||
String getFormCode();
|
||||
|
||||
CommonResponse<Object> submit(FormSubmitRequest request);
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
package top.fjy8018.designpattern.pattern.creational.factorymethod.spring.bean;
|
||||
|
||||
import top.fjy8018.designpattern.pattern.behavior.templatemethod.spring.bean.FormItem;
|
||||
import top.fjy8018.designpattern.pattern.behavior.templatemethod.spring.bean.FormItemConfig;
|
||||
import top.fjy8018.designpattern.pattern.creational.factorymethod.spring.after.Strategy;
|
||||
|
||||
/**
|
||||
* TODO:
|
||||
*
|
||||
* @author F嘉阳
|
||||
* @date 2022/4/8 13:40
|
||||
*/
|
||||
public interface FormItemConverter extends Strategy<FormItemTypeEnum> {
|
||||
|
||||
/**
|
||||
* 获得策略的标识
|
||||
*/
|
||||
@Override
|
||||
default FormItemTypeEnum getId() {
|
||||
return getType();
|
||||
}
|
||||
|
||||
FormItemTypeEnum getType();
|
||||
|
||||
FormItem convert(FormItemConfig config);
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
package top.fjy8018.designpattern.pattern.creational.factorymethod.spring.bean;
|
||||
|
||||
/**
|
||||
* TODO:
|
||||
*
|
||||
* @author F嘉阳
|
||||
* @date 2022/4/8 13:39
|
||||
*/
|
||||
public enum FormItemTypeEnum {
|
||||
}
|
||||
@@ -0,0 +1,39 @@
|
||||
package top.fjy8018.designpattern.pattern.creational.factorymethod.spring.before;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Component;
|
||||
import top.fjy8018.designpattern.pattern.creational.factorymethod.spring.bean.FormDataHandler;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* TODO:
|
||||
*
|
||||
* @author F嘉阳
|
||||
* @date 2022/4/8 13:36
|
||||
*/
|
||||
@Component
|
||||
public class FormDataHandlerFactory {
|
||||
|
||||
private static final
|
||||
Map<String, FormDataHandler> FORM_DATA_HANDLER_MAP = new HashMap<>(16);
|
||||
|
||||
/**
|
||||
* 根据表单标识,获取对应的 Handler
|
||||
*
|
||||
* @param formCode 表单标识
|
||||
* @return 表单对应的 Handler
|
||||
*/
|
||||
public FormDataHandler getHandler(String formCode) {
|
||||
return FORM_DATA_HANDLER_MAP.get(formCode);
|
||||
}
|
||||
|
||||
@Autowired
|
||||
public void setFormDataHandlers(List<FormDataHandler> handlers) {
|
||||
for (FormDataHandler handler : handlers) {
|
||||
FORM_DATA_HANDLER_MAP.put(handler.getFormCode(), handler);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,39 @@
|
||||
package top.fjy8018.designpattern.pattern.creational.factorymethod.spring.before;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Component;
|
||||
import top.fjy8018.designpattern.pattern.creational.factorymethod.spring.bean.FormItemConverter;
|
||||
import top.fjy8018.designpattern.pattern.creational.factorymethod.spring.bean.FormItemTypeEnum;
|
||||
|
||||
import java.util.EnumMap;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* TODO:
|
||||
*
|
||||
* @author F嘉阳
|
||||
* @date 2022/4/8 13:38
|
||||
*/
|
||||
@Component
|
||||
public class FormItemConverterFactory {
|
||||
|
||||
private static final
|
||||
EnumMap<FormItemTypeEnum, FormItemConverter> CONVERTER_MAP = new EnumMap<>(FormItemTypeEnum.class);
|
||||
|
||||
/**
|
||||
* 根据表单项类型获得对应的转换器
|
||||
*
|
||||
* @param type 表单项类型
|
||||
* @return 表单项转换器
|
||||
*/
|
||||
public FormItemConverter getConverter(FormItemTypeEnum type) {
|
||||
return CONVERTER_MAP.get(type);
|
||||
}
|
||||
|
||||
@Autowired
|
||||
public void setConverters(List<FormItemConverter> converters) {
|
||||
for (final FormItemConverter converter : converters) {
|
||||
CONVERTER_MAP.put(converter.getType(), converter);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
package top.fjy8018.designpattern.pattern.behavior.strategy.spring;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
@Component
|
||||
class FormSubmitHandlerTest {
|
||||
|
||||
@Autowired
|
||||
private FormSubmitHandlerFactory factory;
|
||||
|
||||
@Test
|
||||
void getSubmitType() {
|
||||
FormSubmitHandler<Serializable> handler = factory.getHandler("preview");
|
||||
handler.handleSubmit(new FormSubmitRequest());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
package top.fjy8018.designpattern.pattern.behavior.templatemethod.spring.after;
|
||||
|
||||
import com.alibaba.fastjson.JSONArray;
|
||||
import com.alibaba.fastjson.JSONObject;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Component;
|
||||
import top.fjy8018.designpattern.pattern.behavior.templatemethod.spring.bean.FormItem;
|
||||
import top.fjy8018.designpattern.pattern.behavior.templatemethod.spring.bean.FormItemConfig;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.IntStream;
|
||||
|
||||
@Component
|
||||
class FormItemConverterFactoryTest {
|
||||
|
||||
@Autowired
|
||||
private FormItemConverterFactory factory;
|
||||
|
||||
public List<FormItem> convertFormItems(JSONArray inputConfigs) {
|
||||
return IntStream.range(0, inputConfigs.size())
|
||||
.mapToObj(inputConfigs::getJSONObject)
|
||||
.map(this::convertFormItem)
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
|
||||
private FormItem convertFormItem(JSONObject inputConfig) {
|
||||
FormItemConfig itemConfig = inputConfig.toJavaObject(FormItemConfig.class);
|
||||
AbstractFormItemConverter converter = factory.getConverter(itemConfig.getType());
|
||||
|
||||
if (converter == null) {
|
||||
throw new IllegalArgumentException("不存在转换器:" + itemConfig.getType());
|
||||
}
|
||||
|
||||
return converter.convert(itemConfig);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,76 @@
|
||||
package top.fjy8018.designpattern.pattern.behavior.visitor.spring;
|
||||
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import top.fjy8018.designpattern.pattern.behavior.visitor.spring.after.DrawVisitor;
|
||||
import top.fjy8018.designpattern.pattern.behavior.visitor.spring.after.Visitor;
|
||||
import top.fjy8018.designpattern.pattern.behavior.visitor.spring.bean.Building;
|
||||
import top.fjy8018.designpattern.pattern.behavior.visitor.spring.bean.Factory;
|
||||
import top.fjy8018.designpattern.pattern.behavior.visitor.spring.bean.Node;
|
||||
import top.fjy8018.designpattern.pattern.behavior.visitor.spring.bean.School;
|
||||
import top.fjy8018.designpattern.pattern.behavior.visitor.spring.before.DrawService;
|
||||
|
||||
/**
|
||||
* DrawService中只有4个draw方法,参数类型分别是Factory, Building, School和Node,如果调用方传了一个City进来怎么办?
|
||||
* 毕竟调用方可以自己实现一个City类传进来。这种情况下程序该调用什么方法呢?
|
||||
* 我们没有draw(City)方法,为了防止这种情况发生,程序在编译阶段就直接选择使用DrawService::draw(Node)方法。
|
||||
* 无论调用方传了什么实现进来,我们都统一使用DrawService::draw(Node)方法以确保程序安全运行。
|
||||
* 在编译时(而不是运行时)决定调用哪个方法,这就叫做Static/Early Binding。
|
||||
* 这也就解释了我们为什么输出了 draw node 。
|
||||
*/
|
||||
@Slf4j
|
||||
class DrawServiceTest {
|
||||
|
||||
/**
|
||||
* 输出:draw node
|
||||
*/
|
||||
@Test
|
||||
public void draw() {
|
||||
draw(new Factory());
|
||||
}
|
||||
|
||||
/**
|
||||
* 输出:draw factory
|
||||
*/
|
||||
@Test
|
||||
public void draw17() {
|
||||
draw17(new Factory());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void draw2() {
|
||||
Visitor drawVisitor = new DrawVisitor();
|
||||
Factory factory = new Factory();
|
||||
factory.accept(drawVisitor);
|
||||
}
|
||||
|
||||
private void draw(Node node) {
|
||||
DrawService drawService = new DrawService();
|
||||
if (node instanceof Building) {
|
||||
Building building = (Building) node;
|
||||
drawService.draw(building);
|
||||
} else if (node instanceof Factory) {
|
||||
Factory factory = (Factory) node;
|
||||
drawService.draw(factory);
|
||||
} else if (node instanceof School) {
|
||||
School school = (School) node;
|
||||
drawService.draw(school);
|
||||
} else {
|
||||
drawService.draw(node);
|
||||
}
|
||||
}
|
||||
|
||||
private void draw17(Node node) {
|
||||
DrawService drawService = new DrawService();
|
||||
if (node instanceof Building building) {
|
||||
drawService.draw(building);
|
||||
} else if (node instanceof Factory factory) {
|
||||
drawService.draw(factory);
|
||||
} else if (node instanceof School school) {
|
||||
drawService.draw(school);
|
||||
} else {
|
||||
drawService.draw(node);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user