1.策略模式到底是什么?
策略模式属于对象的行为模式。其用意是针对一组算法,将每一个算法封装到具有共同接口的独立的类中,从而使得它们可以相互替换。策略模式使得算法可以在不影响到客户端的情况下发生变化。
简单的说,策略模式代表了一类算法的通用解决方案,你可以在运行时选择使用哪种解决方案。
1.1策略模式的重心
策略模式的重心不是如何实现算法, 而是如何组织、调用这些算法, 从而使得程序结构更加灵活,具有更好的维护性和扩展性。
1.2算法的平等性
策略模式一个很大的特点就是各个策略算法的平等性。对于一系列具体的策略算法,地位都是一样的,因此可以实现算法之间可以互相替换。所有的策略算法在实现上也是相互独立的,相互之间是没有依赖的。所以可以这样描述这一系列策略算法:策略算法是相同行为的不同实现。
1.3运行时策略的唯一性
运行期间,策略模式在每一个时刻只能使用一个具体的策略实现对象,虽然可以动态地在不同的策略实现中切换,但是同时只能使用一个。
1.4公有的行为
经常见到的是,所有的具体策略都有一些公有的行为。这时候,就应该把这些公有的行为放到共同的抽象策略角色
2.策略模式的结构
策略模式包含三部分内容:(如下图所示)
- a.一个或多个使用策略对象的客户.(环境角色)
- b.一个代表某个算法的接口, 它是策略模式的接口. (抽象策略角色)
- c.一个或多个该接口的具体实现, 它们代表了算法的多种实现.(具体策略角色)
3.策略模式的应用
- a.容错恢复机制, 程序运行的时候, 如果发生某种错误, 系统并不会直接挂掉或者说影响系统的其他功能点.
- 而是系统可以容忍这样的错误, 并且事先提供好了这种容错恢复机制, 来使得程序正常的运行下去.
- 例如: 一个系统要对所有的操作进行日志记录, 且需要把日志记录落库, 方便后续的使用, 但是在把日志记录落库的时候,
- 可能会发生错误, 如数据库出现问题, 那就先可以记录在文件里面, 等到数据库问题修复, 再把文件中的日志记录同步到数据库中去
- 对于这样的功能设计, 可以采用策略设计模式, 根据需要在运行期间进行动态的切换.
- b.假设现在要设计一个会员机制的购物系统, 对本系统的所有SVIP提供打八折的购物优惠,
- 对本系统的所有VIP提供打九折的购物优惠, 对非会员购物不打折. 那么对于这样的系统功能设计, 也可以采用策略模式来设计.
- c.使用不同的条件(物品的重量或者颜色等)来筛选库存中的物品, 可以将这一模式应用到更广泛的领域,
- 比如使用不同的标准来验证输入的有效性, 使用不同的方式来分析或者格式化输入.
4.策略模式Demo
4.1策略接口:
/**
* @decription 连接数据库业务层
* @author qiye
* @date 2023/12/25
* @version 1.0.0
*/
public interface DriverMangerService {
/**
* 连接数据库
* @param vo
* @return
*/
Boolean connect(DbDataBase vo);
}
策略接口封装类
/**
* @decription jdbc连接数据库的上下文类
* @author qiye
* @date 2023/12/26
* @version 1.0.0
*/
public class DriverManger {
private final DriverMangerService driverMangerService;
public DriverManger(DriverMangerService v) {
this.driverMangerService = v;
}
public Boolean getDriverMangerService(DbDataBase vo) {
return driverMangerService.connect(vo);
}
}
4.2策略接口的实现
策略接口实现1
/**
* @author qiye
* @version 1.0.0
* @decription mysql连接数据库
* @date 2023/12/25
*/
@Service("mysqlDriverMangerService")
public class MysqlDriverMangerServiceImpl implements DriverMangerService {
/**
* 连接数据库
*
* @param vo
* @return
*/
@Override
public Boolean connect(DbDataBase vo) {
Connection conn = null;
boolean flag = false;
try {
//加载驱动程序
Class.forName("com.mysql.jdbc.Driver");
//建立与数据库的连接
conn = DriverManager.getConnection(vo.getJdbcUrl(), vo.getUserName(), vo.getPassword());
System.out.println("JDBC连接成功!");
flag = true;
} catch (Exception e) {
e.printStackTrace();
} finally {
if (conn != null) {
try {
conn.close();
} catch (SQLException ex) {
ex.printStackTrace();
}
}
}
return flag;
}
}
策略接口实现2
@Service("oracleDriverMangerService")
public class OracleDriverMangerServiceImpl implements DriverMangerService {
/**
* @decription oracle连接
* @author qiye
* @date 2023/12/25
* @version 1.0.0
*/
@Override
public Boolean connect(DbDataBase vo) {
boolean flag = false;
Connection conn = null;
try {
Class.forName("oracle.jdbc.driver.OracleDriver");
conn = DriverManager.getConnection(vo.getJdbcUrl(), vo.getUserName(), vo.getPassword());
if (conn != null && !conn.isClosed()) {
System.out.println("成功连接到Oracle数据库!");
flag = true;
} else {
System.out.println("无法连接到Oracle数据库!");
}
conn.close();
} catch (ClassNotFoundException | SQLException e) {
e.printStackTrace();
} finally {
if (conn != null) {
try {
conn.close();
} catch (SQLException ex) {
ex.printStackTrace();
}
}
}
return flag;
}
}
策略接口实现3
@Service("postgreDriverMangerService")
public class PostgreDriverMangerServiceImpl implements DriverMangerService {
/**
* @decription Postgre连接
* @author qiye
* @date 2023/12/25
* @version 1.0.0
*/
@Override
public Boolean connect(DbDataBase vo) {
boolean flag = false;
Connection connection = null;
try {
Class.forName("org.postgresql.Driver");
connection = DriverManager.getConnection(vo.getJdbcUrl(), vo.getUserName(), vo.getPassword());
if (connection != null) {
System.out.println("PostgreSQL database 连接成功");
flag = true;
}
} catch (ClassNotFoundException | SQLException e) {
e.printStackTrace();
} finally {
try {
if (connection != null) {
connection.close();
}
} catch (SQLException e) {
e.printStackTrace();
}
}
return flag;
}
}
4.3调用
DriverManger driverManger = null;
try {
switch (vo.getJdbcDriver()) {
case "com.mysql.jdbc.Driver":
driverManger = new DriverManger(mysqlDriverMangerService);
break;
case "org.postgresql.Driver":
driverManger = new DriverManger(postgreDriverMangerService);
break;
case "oracle.jdbc.driver.OracleDriver":
driverManger = new DriverManger(oracleDriverMangerService);
break;
}
if(driverManger!=null){
flag = driverManger.getDriverMangerService(vo);
}
} catch (Exception e) {
e.printStackTrace();
return Response.error(500, "连接失败");
}
5.策略模式的优缺点
5.1优点
- a.使用策略模式可以避免使用多重条件if…else if…else语句, 多重条件不易维护且代码可读性差.
- b.策略模式提供了管理相关的算法族的办法. 策略类的等级结构定义了一个算法或者行为族. 恰当使用继承可以把公共的代码移到父类里面, 从而避免代码重复
5.2缺点
- a.客户端必须知道所有的策略类, 并自行决定使用哪一个策略类. 这就意味着客户端必须理解这些算法的区别, 以便适时选择恰当的算法类. 换言之, 策略模式只适用于客户端知道算法或行为的情况.
- b.由于策略模式把每个具体的策略实现都单独封装成类, 如果备选的策略很多的话, 那么对象的数目就会很多.