1: 策略模式
业务场景:在发布一个通知的时候,需要选择接收该通知的用户对象,可以按照【部门】,【考点】,【学校】三种选择,此时多数小伙伴的实现方式是这样的
if(type == 部门) {
//通过部门找到所有的用户
}
else if(type == 考点) {
//通过考点找到所有的用户
}
else if(type == 学校) {
//通过学校找到所有的用户
}
复制代码
这种实现方式的弊端很明显:
- 1:如果现在新增一个类型,那么就要再添加一个判断,继续实现业务逻辑,就会造成这个方法越来越臃肿,不好扩展,难以维护,可读性降低
- 2:如果新增一个类型就违背了面向对象编程的开闭原则以及单一原则
像这种有多个if...else的分支逻辑,我们可以使用策略模式来解决
1: 定义一个通用的接口
public interface NoticeUserInterface {
//查询处所有需要接收该通知的用户的集合
List<User> queryAll(Integer type,Integer paramId);
//类型:1:部门 2:考点 3:学校
Integer getType();
}
复制代码
2:定义不同的策略实现
// 部门
@Service
public class OrganNoticeUserInterfaceImpl implements NoticeUserInterface{
@Override
public List<User> queryAll(Integer type,Integer depId) {
//具体的实现逻辑,根据部门查找所有接收该通知的用户
}
@Override
public Integer getType() {
return 1;
}
}
复制代码
// 考点
@Service
public class KDNoticeUserInterfaceImpl implements NoticeUserInterface{
@Override
public List<User> queryAll(Integer type,Integer kdId) {
//具体的实现逻辑,根据考点查找所有接收该通知的用户
}
@Override
public Integer getType() {
return 2;
}
}
复制代码
// 学校
@Service
public class SchoolNoticeUserInterfaceImpl implements NoticeUserInterface{
@Override
public List<User> queryAll(Integer type,Integer schoolId) {
//具体的实现逻辑,根据学校查找所有接收该通知的用户
}
@Override
public Integer getType() {
return 3;
}
}
复制代码
3:使用策略模式
@Component
public class NoticeUserComponent implements ApplicationContextAware {
private Map<Integer, NoticeUserInterface> iCheckStrategyMap = new ConcurrentHashMap<>();
public List<User> queryResult(Integer type, Integer paramId) {
NoticeUserInterface iCheckInterface = iCheckStrategyMap.get(type);
if (iCheckInterface != null) {
return iCheckInterface.queryAll(paramId);
}
return null;
}
//把不同策略放到map
@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
Map<String, NoticeUserInterface> tmepMap = applicationContext.getBeansOfType(NoticeUserInterface.class);
if(!tmepMap.isEmpty()) {
for(String beanName : tmepMap.keySet()) {
NoticeUserInterface noticeUserInterface = tmepMap.get(beanName);
Integer type = noticeUserInterface.getType();
iCheckStrategyMap.put(type,noticeUserInterface);
}
}
}
}
复制代码
1: 模版模式
在项目中需要创建模版,模版的字段都是保存在数据库,在生成模版的时候需要从数据库拿到该模版的所有字段,然后生成对应的excel,dbf,csv文件,此时可以这样实现
class ExcelHandle {
void createFile(Long templateId) {
//从数据库找到该模版所有的字段
List<String> rows = queryFieldsByTemplateId(templateId);
//生成文件
createFile(rows);
}
}
class DbfHandle {
void createFile(Long templateId) {
//从数据库找到该模版所有的字段
List<String> rows = queryFieldsByTemplateId(templateId);
//生成文件
createFile(rows);
}
}
class CsvHandle {
void createFile(Long templateId) {
//从数据库找到该模版所有的字段
List<String> rows = queryFieldsByTemplateId(templateId);
//生成文件
createFile(rows);
}
}
复制代码
其实无论是生成Excel,还是dbf或者是csv都需要从数据库中找到该模版的所有的字段,只有生成具体文件的时候是没办法确定下来的,就是不知道是生成Excel还是DBF或者是CSV,这种我们可以使用模版模式
1:定义一个抽象类
public abstract class CreateFileComponents {
/**
* 定义抽象方法,根据模版生成Excel,DBF,CSV等文件,具体的实现在子类
*/
public abstract void create(ArrayList<Map<String, Object>> rows, String name);
/**
* 公用方法,生成文件需要从数据库中找到对应的字段生成文件
* @param templateId
* @return
* @throws Exception
*/
public final void createFile(Integer templateId) throws Exception{
// 根据模版ID找到该模版所有的字段
List<String> rows = queryFieldsByTemplateId(templateId);
//在本地生成预览文件
create(rows);
//然后将该文件上传到minio上
uploadToMinio();
}
}
复制代码
2:定义不同的子类
//生成Excel文件
public class ExcelFile extends CreateFileComponents{
@Override
public void create(ArrayList<Map<String, Object>> rows) {
//生成Excel
}
}
复制代码
//生成DBF文件
public class DdfFile extends CreateFileComponents{
@Override
public void create(ArrayList<Map<String, Object>> rows) {
//生成Dbf
}
}
复制代码
//生成CSV文件
public class CsvFile extends CreateFileComponents{
@Override
public void create(ArrayList<Map<String, Object>> rows) {
//生成Dbf
}
}
复制代码
3:使用模版模式
CreateFileComponents components =CreateFileFactory.createFileComponents(template.getType());
components.createFile(id);
复制代码
其实这里还使用简单工厂模式
public class CreateFileFactory {
public static CreateFileComponents createFileToViewComponents(Integer type) {
switch (type){
case 0:
return new ExcelFile();
case 1:
return new DBFFile();
case 2:
return new CSVFile();
}
return null;
}
}
复制代码