今天你的leader兴致冲冲地找到你,希望你能够帮他一个小忙。他如今急着要去开会。要帮什么忙呢?你非常好奇。

他对你说。当前你们项目的数据库中有一张用户信息表。里面存放了非常用户的数据。如今须要完毕一个选择性查询用户信息的功能。

他说会传递给你一个包括很多username的数组。你须要依据这些username把他们对应的数据都给查出来。

这个功能非常easy的嘛。你爽快地答应了。

因为你们项目使用的是MySQL数据库,你非常快地写出了例如以下代码:

[java] view
plain
copy

  1. public class QueryUtil {
  2. public void findUserInfo(String[] usernames) throws Exception {
  3. Class.forName("com.mysql.jdbc.Driver");
  4. Connection conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/test", "root",
  5. "123456");
  6. Statement stat = conn.createStatement();
  7. StringBuilder sql = new StringBuilder("select * from user_info where ");
  8. for (String user : usernames) {
  9. sql.append("username = '");
  10. sql.append(user);
  11. sql.append("' or ");
  12. }
  13. System.out.println(sql);
  14. ResultSet resultSet = stat.executeQuery(sql.toString());
  15. while (resultSet.next()) {
  16. // 处理从数据库读出来的数据
  17. }
  18. // 后面应将读到的数据组装成对象返回,这里略去。
  19. }
  20. }

这里依据传入的username数组拼装了SQL语句,然后去数据库中查找对应的行。为了方面调试。你还将拼装好的SQL语句打印了出来。

然后,你写了例如以下代码来測试这种方法:

[java] view
plain
copy

  1. public class Test {
  2. public static void main(String[] args) throws Exception {
  3. QueryUtil query = new QueryUtil();
  4. query.findUserInfo(new String[] { "Tom", "Jim", "Anna" });
  5. }
  6. }

如今执行一下測试代码,你发现程序出错了。于是你立马去检查了一下打印的SQL语句,果然发现了问题。

  1. select * from user_info where username = 'Tom' or username = 'Jim' or username = 'Anna' or

拼装出来的SQL语句在最后多加了一个 or keyword。由于for循环运行到最后一条数据时不应该再加上or,但是代码非常笨地给最后一条数据也加了orkeyword。导致SQL语句语法出错了。

这可怎么办呢?

有了。你灵光一闪,想出了一个解决的方法。

等SQL语句拼装完毕后,把最后一个or删除掉不就好了么。于是你将代码改成例如以下所看到的:

[java] view
plain
copy

  1. public class QueryUtil {
  2. public void findUserInfo(String[] usernames) throws Exception {
  3. Class.forName("com.mysql.jdbc.Driver");
  4. Connection conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/test", "root",
  5. "123456");
  6. Statement stat = conn.createStatement();
  7. StringBuilder sql = new StringBuilder("select * from user_info where ");
  8. for (String user : usernames) {
  9. sql.append("username = '");
  10. sql.append(user);
  11. sql.append("' or ");
  12. }
  13. sql.delete(sql.length() - " or ".length(), sql.length());
  14. System.out.println(sql);
  15. ResultSet resultSet = stat.executeQuery(sql.toString());
  16. while (resultSet.next()) {
  17. // 处理从数据库读出来的数据
  18. }
  19. // 后面应将读到的数据组装成对象返回,这里略去。
  20. }
  21. }

使用StringBuilder的delete方法,把最后多余的一个or删除掉了,这样再执行測试代码。一切就正常了,打印的SQL语句例如以下所看到的:

  1. select * from user_info where username = 'Tom' or username = 'Jim' or username = 'Anna'

好了,完工!你自信满满。

你的leader开完会后,过来看了下你的成果。整体来说。他还挺惬意。但对于你使用的SQL语句拼装算法,他总是感觉有些不正确劲,但是又说不上哪里不好。

于是他告诉了你还有一种拼装SQL语句的算法。让你增加到代码中,但是之前的那种算法也不要删除。先保留着再说,然后他又非常忙似的跑开了。

于是,你把他刚刚教你的算法加了进去,代码例如以下所看到的:

[java] view
plain
copy

  1. public class QueryUtil {
  2. public void findUserInfo(String[] usernames, int strategy) throws Exception {
  3. Class.forName("com.mysql.jdbc.Driver");
  4. Connection conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/test", "root",
  5. "123456");
  6. Statement stat = conn.createStatement();
  7. StringBuilder sql = new StringBuilder("select * from user_info where ");
  8. if (strategy == 1) {
  9. for (String user : usernames) {
  10. sql.append("username = '");
  11. sql.append(user);
  12. sql.append("' or ");
  13. }
  14. sql.delete(sql.length() - " or ".length(), sql.length());
  15. } else if (strategy == 2) {
  16. boolean needOr = false;
  17. for (String user : usernames) {
  18. if (needOr) {
  19. sql.append(" or ");
  20. }
  21. sql.append("username = '");
  22. sql.append(user);
  23. sql.append("'");
  24. needOr = true;
  25. }
  26. }
  27. System.out.println(sql);
  28. ResultSet resultSet = stat.executeQuery(sql.toString());
  29. while (resultSet.next()) {
  30. // 处理从数据库读出来的数据
  31. }
  32. // 后面应将读到的数据组装成对象返回,这里略去。
  33. }
  34. }

能够看到,你leader教你的拼装算法。使用了一个布尔变量来控制是否须要加个or这个keyword。第一次运行for循环的时候由于该布尔值为false,所以不会加上or,在循环的最后将布尔值赋值为true,这样以后循环每次都会在头部加上一个orkeyword。由于使用了头部加入or的方法。所以不用再操心SQL语句的尾部会多出一个or来。然后你为了将两个算法都保留,在findUserInfo方法上加了一个參数,strategy值为1表示使用第一种算法。strategy值为2表示使用另外一种算法。

这样測试代码也须要改成例如以下方式:

[java] view
plain
copy

  1. public class Test {
  2. public static void main(String[] args) throws Exception {
  3. QueryUtil query = new QueryUtil();
  4. query.findUserInfo(new String[] { "Tom", "Jim", "Anna" }, 2);
  5. }
  6. }

这里你通过參数指明了使用另外一种算法来拼装SQL语句。打印的结果和使用第一种算法是全然同样的。

你立马把你的leader从百忙之中拖了过来。让他检验一下你当前的成果,但是他还是一如既往的挑剔。

“你这样写的话,findUserInfo这种方法的逻辑就太复杂了,很不利于阅读,也不利于将来的扩展,假设我还有第三第四种算法想加进去,这种方法还能看吗?”  你的leader指点你,遇到这样的情况,就要使用策略模式来解决,策略模式的核心思想就是把算法提取出来放到一个独立的对象中

为了指点你。他不顾自己的百忙,開始教你怎样使用策略模式进行优化。

首先定义一个策略接口:

[java] view
plain
copy

  1. public interface Strategy {
  2. String getSQL(String[] usernames);
  3. }

然后定义两个子类都实现了上述接口,并将两种拼装SQL语句的算法分别增加两个子类中:

[java] view
plain
copy

  1. public class Strategy1 implements Strategy {
  2. @Override
  3. public String getSQL(String[] usernames) {
  4. StringBuilder sql = new StringBuilder("select * from user_info where ");
  5. for (String user : usernames) {
  6. sql.append("username = '");
  7. sql.append(user);
  8. sql.append("' or ");
  9. }
  10. sql.delete(sql.length() - " or ".length(), sql.length());
  11. return sql.toString();
  12. }
  13. }
[java] view
plain
copy

  1. public class Strategy2 implements Strategy {
  2. @Override
  3. public String getSQL(String[] usernames) {
  4. StringBuilder sql = new StringBuilder("select * from user_info where ");
  5. boolean needOr = false;
  6. for (String user : usernames) {
  7. if (needOr) {
  8. sql.append(" or ");
  9. }
  10. sql.append("username = '");
  11. sql.append(user);
  12. sql.append("'");
  13. needOr = true;
  14. }
  15. return sql.toString();
  16. }
  17. }

然后把QueryUtil中findUserInfo方法的第二个參数改成Strategy对象,这样仅仅须要调用Strategy的getSQL方法就能够获得拼装好的SQL语句,代码例如以下所看到的:

[java] view
plain
copy

  1. public class QueryUtil {
  2. public void findUserInfo(String[] usernames, Strategy strategy) throws Exception {
  3. Class.forName("com.mysql.jdbc.Driver");
  4. Connection conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/test", "root",
  5. "123456");
  6. Statement stat = conn.createStatement();
  7. String sql = strategy.getSQL(usernames);
  8. System.out.println(sql);
  9. ResultSet resultSet = stat.executeQuery(sql);
  10. while (resultSet.next()) {
  11. // 处理从数据库读出来的数据
  12. }
  13. // 后面应将读到的数据组装成对象返回。这里略去。
  14. }
  15. }

最后,測试代码在调用findUserInfo方法时。仅仅须要显示地指明须要使用哪一个策略对象就能够了:

[java] view
plain
copy

  1. public class Test {
  2. public static void main(String[] args) throws Exception {
  3. QueryUtil query = new QueryUtil();
  4. query.findUserInfo(new String[] { "Tom", "Jim", "Anna" }, new Strategy1());
  5. query.findUserInfo(new String[] { "Jac", "Joe", "Rose" }, new Strategy2());
  6. }
  7. }

打印出的SQL语句丝毫不出预料。例如以下所看到的:

  1. select * from user_info where username = 'Tom' or username = 'Jim' or username = 'Anna'
  2. select * from user_info where username = 'Jac' or username = 'Joe' or username = 'Rose'

使用策略模式改动之后,代码的可读性和扩展性都有了非常大的提高。即使以后还须要加入新的算法。你也是手到擒来了!

策略:它定义了算法家庭,分别封装起来。让它们之间能够互相替换。此模式让算法的变化。不会影响到使用算法的客户。 

最新文章

  1. mysqldump
  2. Java资源大全中文版(Awesome最新版)(转载)
  3. [小菜随笔]关于monkey报错日志分析
  4. LDAP与migrationtools 导入系统账号
  5. PADSPCB权威指南-第一章 PADS软件系统(部分)(原创)
  6. mongoDB安装学习
  7. js二级下拉被flash档住的解决办法
  8. ISO 9141-2 and ISO 14230-2 INITIALIZATION and DATA TRANSFER
  9. WPF——数据绑定及属性改变事件
  10. C字符串总结+字符串库实现(增,改,删,查):
  11. Android_declare-styleable_自己定义控件的属性
  12. 问题(一)---线程池,锁、堆栈和Hashmap相关
  13. 位置信息类API调用的代码示例合集:中国省市区查询、经纬度地址转换、POI检索等
  14. ClientURL库-curl_setopt()
  15. div轮流滚动显示
  16. 用python写一个预警机器人(支持微信和钉钉)
  17. ios开发之--CAKeyframeAnimation的详细用法
  18. 微信小程序的同步操作
  19. uiautomator viewer
  20. django views视图函数返回值 return redirect httpresponse总结

热门文章

  1. hdu3001(状态压缩DP)
  2. 1.13(java学习笔记)异常机制
  3. 设置iframe高度自适应屏幕高度
  4. 使用gtest自动化测试并给出性能测试结果(windows 版本,版本平台也可以使用,但并没有做完整的测试)
  5. 新建一个兼容eclipse和myeclipse、IDEA都兼容的项目结构(maven)
  6. ios frame,bound和center
  7. Spark jdbc postgresql数据库连接和写入操作源代码解读
  8. Spring获取properties文件中的属性
  9. Hadoop之Flume详解
  10. 通过Linux定时任务实现定时轮询数据库及发送Http请求