策略模式与模版模式的区别与应用
本文为博主原创,未经允许不得转载:
最近在做项目的优化,由于项目在早期缺乏规划,在开发过程中,对于某一个业务的不同类型判断,增加了很多 if else ,代码的健壮性变得很差。
所以考虑使用设计模式中的策略模式与模版模式进行开发中的代码设计。且由于在使用过程中策略模式与模版模式经常一起使用,所以对这两种设计模式
进行一起整理记录下。
1.模版模式:
模版模式的定义:模板方法模式定义了一个算法的步骤,并允许子类别为一个或多个步骤提供其实践方式。让子类别在不改变算法架构的情况下,重新定义算法中的某些步骤。
模版模式属于行为型设计模式,其意图是在一个方法里实现一个算法,并定义延迟算法的某些步骤,从而让其他类重新定义他们。
项目中经常使用的RestTemplate,JdbcTemplate,RedisTemplate等都采用了模版模式的设计模式,因为在操作资源的时候,经常会涉及到打开资源链接
关闭资源连接等,且为公用的模式,所以采用模版模式,然后将其定义为一个算法骨架,通过子类或实现类来实现算法的具体实现。
example:
定义一个模版:
public abstract class AbstractDataSourceTemplate { /** * 开启连接 */ abstract void open(); /** * 执行操作 */ abstract void execute(); /** * 关闭连接 */ abstract void close(); /** * 模版方法 */ public final void run() { open(); execute(); close(); } }
通过上述模版实现JdbcTemplate 与 RedisTemplate
public class RedisDataSourceTemplate extends AbstractDataSourceTemplate { /** * 开启连接 */ @Override void open() { System.out.println("开启redis连接..."); } /** * 执行操作 */ @Override void execute() { System.out.println("操作redis..."); } /** * 关闭连接 */ @Override void close() { System.out.println("关闭redis连接..."); } }
JdbcTemplate ::
public class JdbcDataSourceTemplate extends AbstractDataSourceTemplate { /** * 开启连接 */ @Override void open() { System.out.println("开启jdbc连接..."); } /** * 执行操作 */ @Override void execute() { System.out.println("操作jdbc..."); } /** * 关闭连接 */ @Override void close() { System.out.println("关闭jdbc连接..."); } }
使用
//jdbc模版 AbstractDataSourceTemplate template = new JdbcDataSourceTemplate(); template.run(); System.out.println("----------------"); //redis模版 AbstractDataSourceTemplate template1 = new RedisDataSourceTemplate(); template1.run();
总结
- 封装不可变部分,扩展可变部分
- 提取公共代码,便于维护
- 行为由父类控制骨架/算法,子类实现
- 对每个不同的实现都需要定义一个子类,这会导致类的个数增加,系统更加庞大,设计也更加抽象
- 父类中的抽象方法由子类实现,子类执行的结果会影响父类的结果,这导致一种反向的控制结构,它提高了代码阅读的难度
2.策略模式:
策略模式的应用比模版模式的应用场景更为常见。我们在开发过程中,经常会使用 if .. else if ( ) 或 switch 。。 case。。等进行同一个业务的不同场景或类型判断。
比如进行权限校验判断时,判断当前管理员是 超级管理员:userType ==1,如果是二级管理员 userType == 2....等等。这些场景都可以使用策略模式进行开发优化,可以避免
很长的 if else 判断。
策略模式的定义:
策略模式(Strategy Pattern)属于对象的行为模式。其用意是针对一组算法,将每一个算法封装到具有共同接口的独立的类中,从而使得它们可以相互替换。
策略模式使得算法可以在不影响到客户端的情况下发生变化。
其主要目的是通过定义相似的算法,替换if else 语句写法,并且可以随时相互替换。
在其他博客中找到一个很好的场景,是支付场景,通过策略模式区分支付宝,银行卡,点券支付的场景。
package strategy; public interface PayStrategy { String selectPayWay(Integer paycode); }
规定具体策略行为
package strategy; public class PayContext { private PayStrategy payStrategy; public String selectPayWay(Integer payCode){ payStrategy = StrategyFactory.getInstance().create(payCode); return payStrategy.selectPayWay(payCode); } public PayStrategy getPayStrategy() { return payStrategy; } public void setPayStrategy(PayStrategy payStrategy) { this.payStrategy = payStrategy; } }
支付宝付款实现类
package strategy.paystrategy; import strategy.PayStrategy; public class ALPayStrategy implements PayStrategy { @Override public String selectPayWay(Integer paycode) { //do something return "支付宝支付成功"; } }
银行卡支付实现类
package strategy.paystrategy; import strategy.PayStrategy; public class CardPayStrategy implements PayStrategy { @Override public String selectPayWay(Integer paycode) { //do something return "银行卡支付成功"; } }
微信支付实现类
package strategy.paystrategy; import strategy.PayStrategy; public class WeChatPayStrategy implements PayStrategy { @Override public String selectPayWay(Integer paycode) { //do something return "微信支付成功"; } }
创建策略类的工厂
package strategy; import pay.PayWayEnum; import strategy.paystrategy.ALPayStrategy; import strategy.paystrategy.CardPayStrategy; import strategy.paystrategy.PointCouponPayStrategy; import strategy.paystrategy.WeChatPayStrategy; import java.util.HashMap; import java.util.Map; public class StrategyFactory { private static StrategyFactory factory = new StrategyFactory(); private StrategyFactory(){} private static Map strategyMap = new HashMap<>(16); static { strategyMap.put(PayWayEnum.AL_PAY.getCode(),new ALPayStrategy()); strategyMap.put(PayWayEnum.WEICHAT_PAY.getCode(),new WeChatPayStrategy()); strategyMap.put(PayWayEnum.CARD_PAY.getCode(),new CardPayStrategy()); strategyMap.put(PayWayEnum.PONIT_COUPON_PAY.getCode(),new PointCouponPayStrategy()); } public PayStrategy create(Integer payCode){ return (PayStrategy) strategyMap.get(payCode); } public static StrategyFactory getInstance(){ return factory; } }
实现客户端
package strategy; public class Client { public static void main(String[] args) { PayContext payContext = new PayContext(); System.out.println(payContext.selectPayWay(100)); } }
最后在贴一个枚举类
package pay; public enum PayWayEnum { /**微信支付*/ WEICHAT_PAY("微信支付",100), /**支付宝支付*/ AL_PAY("支付宝支付",101), /**银行卡支付*/ CARD_PAY("银行卡支付",102), /**点券支付*/ PONIT_COUPON_PAY("点券支付",103); private String msg; private Integer code; PayWayEnum(String msg, Integer code) { this.msg = msg; this.code = code; } public String getMsg() { return msg; } public Integer getCode() { return code; } }
从上面代码中,我们可以看到,我们完全消除了对状态码进行判断的那些if…else的冗余代码,取而代之是直接由客户端决定使用哪种算法,
然后交由上下文获取结果。极大的增强的了扩展性,隐藏了内部实现的细节,当然我们也可以看到,策略模式由于独立策略的实现,
也使得系统内部增加了很多策略,对客户端来必须知道这些策略类实现的是那些策略,而且需要知道具体的策略条件。
然而在实际的生产环境中我们可能不会像示例代码这样干,在实际的生产环境中我们一般会结合spring来对我们所需的策略进行操作,
这边我可以给大家有个具体的思路,大家可以通过这个思路来想想,自己在实际生产环境会怎样操作
1.首先和上面代码一样定义一个Strategy接口,其中有一个operation的函数交给具体业务去实现
2.根据自己的业务,会拥有很多的策略类实现该接口;将这些类注册到spring Bean容器中提供使用。
3。通过客户端传值,从spring容器中获取Strategy实例
4.最终来执行operation函数
参考博客:https://blog.csdn.net/qq1037893644/article/details/102681593