聊聊项目中使用到的设计模式

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;
    }
}
复制代码

猜你喜欢

转载自juejin.im/post/7085639227844591629